From 7f1ab9b1e111b9ea9261eec4b7c6fb0f42591eef Mon Sep 17 00:00:00 2001 From: grischka Date: Sun, 16 Jul 2017 12:10:00 +0200 Subject: [PATCH] tccgen: nodata_wanted The existing variable 'nocode_wanted' is now used to control output of static data too. So... (nocode_wanted == 0) code and data (normal within functions) (nocode_wanted < 0) means: no code, but data (global or static data) (nocode_wanted > 0) means: no code and no data (code and data suppressed) (nocode_wanted & 0xC0000000) means: we're in declaration of static data Also: new option '-dT' to be used with -run tcc -dT -run file.c This will look in file.c for certain comment-boundaries: /*-* test-xxx: ...some description */ and then for each test below run it from memory. This way various features and error messages can be tested with one single file. See 96_nodata_wanted.c for an example. Also: tccgen.c: one more bitfield fix --- libtcc.c | 4 +- tcc.c | 2 + tcc.h | 1 + tccgen.c | 95 +++++++++++++++--------- tcctools.c | 105 +++++++++++++++++++++++++++ tests/tests2/95_bitfields.c | 2 +- tests/tests2/95_bitfields_ms.expect | 16 ++-- tests/tests2/96_nodata_wanted.c | 74 +++++++++++++++++++ tests/tests2/96_nodata_wanted.expect | 24 ++++++ tests/tests2/Makefile | 93 +++++++++++++----------- 10 files changed, 330 insertions(+), 86 deletions(-) create mode 100644 tests/tests2/96_nodata_wanted.c create mode 100644 tests/tests2/96_nodata_wanted.expect diff --git a/libtcc.c b/libtcc.c index 72f53c0..bf13724 100644 --- a/libtcc.c +++ b/libtcc.c @@ -634,11 +634,9 @@ static int tcc_compile(TCCState *s1) preprocess_start(s1); tccgen_start(s1); - #ifdef INC_DEBUG printf("%s: **** new file\n", file->filename); #endif - ch = file->buf_ptr[0]; tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; @@ -1801,6 +1799,8 @@ reparse: s->dflag = 3; else if (*optarg == 'M') s->dflag = 7; + else if (*optarg == 'T') + s->do_test = argc; else if (isnum(*optarg)) g_debug = atoi(optarg); else diff --git a/tcc.c b/tcc.c index 6e8cdba..b502df1 100644 --- a/tcc.c +++ b/tcc.c @@ -282,6 +282,8 @@ redo: n = s->nb_files; if (n == 0) tcc_error("no input files\n"); + if (s->do_test) + tcc_tool_test(s, argc, argv); /* maybe never returns */ if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (!s->outfile) { diff --git a/tcc.h b/tcc.h index 5d2cbde..4113028 100644 --- a/tcc.h +++ b/tcc.h @@ -813,6 +813,7 @@ struct TCCState { int option_pthread; /* -pthread option */ int argc; char **argv; + int do_test; }; struct filespec { diff --git a/tccgen.c b/tccgen.c index 3cc6108..60ae198 100644 --- a/tccgen.c +++ b/tccgen.c @@ -50,7 +50,9 @@ ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack p ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop; ST_DATA int const_wanted; /* true if constant wanted */ -ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ +ST_DATA int nocode_wanted; /* no code generation wanted */ +#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */ +#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */ ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ ST_DATA CType func_vt; /* current function return type (used by return instruction) */ ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ @@ -230,7 +232,7 @@ ST_FUNC void tccgen_start(TCCState *s1) anon_sym = SYM_FIRST_ANOM; section_sym = 0; const_wanted = 0; - nocode_wanted = 1; + nocode_wanted = 0x80000000; /* define some often used types */ int_type.t = VT_INT; @@ -1206,14 +1208,12 @@ ST_FUNC int gv(int rc) } else { if (is_float(vtop->type.t) && (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - unsigned long offset; /* CPUs usually cannot use float constants, so we store them generically in data segment */ size = type_size(&vtop->type, &align); - offset = section_add(data_section, size, align); - vpush_ref(&vtop->type, data_section, offset, size); + vpush_ref(&vtop->type, data_section, data_section->data_offset, size); vswap(); - init_putv(&vtop->type, data_section, offset); + init_putv(&vtop->type, data_section, data_section->data_offset); vtop->r |= VT_LVAL; } #ifdef CONFIG_TCC_BCHECK @@ -2329,6 +2329,11 @@ static void gen_cvt_ftoi1(int t) static void force_charshort_cast(int t) { int bits, dbt; + + /* cannot cast static initializers */ + if (STATIC_DATA_WANTED) + return; + dbt = t & VT_BTYPE; /* XXX: add optimization if lvalue : just change type and offset */ if (dbt == VT_BYTE) @@ -3405,12 +3410,9 @@ static void struct_layout(CType *type, AttributeDef *ad) //#define BF_DEBUG for (f = type->ref->next; f; f = f->next) { - if (f->type.t & VT_BITFIELD) { + if (f->type.t & VT_BITFIELD) bit_size = BIT_SIZE(f->type.t); - /* in pcc mode, long long bitfields have type int if they fit */ - if (pcc && (f->type.t & VT_BTYPE) == VT_LLONG && bit_size <= 32) - f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT; - } else + else bit_size = -1; size = type_size(&f->type, &align); a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0; @@ -3479,6 +3481,10 @@ static void struct_layout(CType *type, AttributeDef *ad) goto new_field; } + /* in pcc mode, long long bitfields have type int if they fit */ + if (size == 8 && bit_size <= 32) + f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT, size = 4; + while (bit_pos >= align * 8) c += align, bit_pos -= align * 8; offset = c; @@ -4558,8 +4564,10 @@ ST_FUNC void unary(void) type.t |= VT_ARRAY; type.ref->c = len; vpush_ref(&type, data_section, data_section->data_offset, len); - ptr = section_ptr_add(data_section, len); - memcpy(ptr, funcname, len); + if (!NODATA_WANTED) { + ptr = section_ptr_add(data_section, len); + memcpy(ptr, funcname, len); + } next(); } break; @@ -6314,7 +6322,7 @@ static int decl_designator(CType *type, Section *sec, unsigned long c, vstore(); } vpop(); - } else { + } else if (!NODATA_WANTED) { c_end = c + nb_elems * elem_size; if (c_end > sec->data_allocated) section_realloc(sec, c_end); @@ -6348,9 +6356,25 @@ static void init_putv(CType *type, Section *sec, unsigned long c) /* XXX: generate error if incorrect relocation */ gen_assign_cast(&dtype); bt = type->t & VT_BTYPE; + + if ((vtop->r & VT_SYM) + && bt != VT_PTR + && bt != VT_FUNC + && (bt != (PTR_SIZE == 8 ? VT_LLONG : VT_INT) + || (type->t & VT_BITFIELD)) + && !((vtop->r & VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM) + ) + tcc_error("initializer element is not computable at load time"); + + if (NODATA_WANTED) { + vtop--; + return; + } + size = type_size(type, &align); section_reserve(sec, c + size); ptr = sec->data + c; + /* XXX: make code faster ? */ if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM && @@ -6404,20 +6428,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c) } } } else { - if ((vtop->r & VT_SYM) && - (bt == VT_BYTE || - bt == VT_SHORT || - bt == VT_DOUBLE || - bt == VT_LDOUBLE || -#if PTR_SIZE == 8 - bt == VT_INT || -#else - bt == VT_LLONG || -#endif - (type->t & VT_BITFIELD) - )) - tcc_error("initializer element is not computable at load time"); - if (type->t & VT_BITFIELD) { int bit_pos, bit_size, bits, n; unsigned char *p, v, m; @@ -6598,7 +6608,8 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, string in global variable, we handle it specifically */ if (sec && tok == TOK_STR && size1 == 1) { - memcpy(sec->data + c + len, tokc.str.data, nb); + if (!NODATA_WANTED) + memcpy(sec->data + c + len, tokc.str.data, nb); } else { for(i=0;ido_bounds_check && !NODATA_WANTED; +#endif + + if (type->t & VT_STATIC) + nocode_wanted |= NODATA_WANTED ? 0x40000000 : 0x80000000; flexible_array = NULL; if ((type->t & VT_BTYPE) == VT_STRUCT) { @@ -6779,10 +6797,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, } else if (ad->a.packed) { align = 1; } + + if (NODATA_WANTED) + size = 0, align = 1; + if ((r & VT_VALMASK) == VT_LOCAL) { sec = NULL; #ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { + if (bcheck && (type->t & VT_ARRAY)) { loc--; } #endif @@ -6792,7 +6814,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, /* handles bounds */ /* XXX: currently, since we do only one pass, we cannot track '&' operators, so we add only arrays */ - if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { + if (bcheck && (type->t & VT_ARRAY)) { addr_t *bounds_ptr; /* add padding between regions */ loc--; @@ -6860,7 +6882,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, addr = section_add(sec, size, align); #ifdef CONFIG_TCC_BCHECK /* add padding if bound check */ - if (tcc_state->do_bounds_check) + if (bcheck) section_add(sec, 1, 1); #endif } else { @@ -6888,7 +6910,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, #ifdef CONFIG_TCC_BCHECK /* handles bounds now because the symbol must be defined before for the relocation */ - if (tcc_state->do_bounds_check) { + if (bcheck) { addr_t *bounds_ptr; greloca(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR, 0); @@ -6903,6 +6925,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (type->t & VT_VLA) { int a; + if (NODATA_WANTED) + goto no_alloc; + /* save current stack pointer */ if (vlas_in_scope == 0) { if (vla_sp_root_loc == -1) @@ -6935,6 +6960,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, end_macro(); restore_parse_state(&saved_parse_state); } + + nocode_wanted = saved_nocode_wanted; } /* parse a function defined by symbol 'sym' and generate its code in @@ -6978,7 +7005,7 @@ static void gen_function(Sym *sym) func_vt.t = VT_VOID; /* for safety */ func_var = 0; /* for safety */ ind = 0; /* for safety */ - nocode_wanted = 1; + nocode_wanted = 0x80000000; check_vstack(); } diff --git a/tcctools.c b/tcctools.c index 53d88be..0e2755b 100644 --- a/tcctools.c +++ b/tcctools.c @@ -544,3 +544,108 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename) } /* -------------------------------------------------------------- */ +/* run test snippets from file */ + +static char *readfile(const char *fname) +{ + char *buf; + int fsize; + FILE *fi; + fi = fopen(fname, "rb"); + if (!fi) + return NULL; + fseek(fi, 0, SEEK_END); + fsize = ftell(fi); + fseek(fi, 0, SEEK_SET); + buf = tcc_malloc(fsize + 1); + fread(buf, fsize, 1, fi); + fclose(fi); + buf[fsize] = 0; + return buf; +} + +static int run_prog(const char *prog, int ac, char **av) +{ + TCCState *s; + int (*func)(int, char**); + int ret = -10000; + + s = tcc_new(); + tcc_parse_args(s, &ac, &av, 1); + tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + if (tcc_compile_string(s, prog) == -1) + goto done; + if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) + goto done; + func = tcc_get_symbol(s, "main"); + if (!func) + goto done; + ret = func(ac, av); +done: + tcc_delete(s); + return ret; +} + +static char *trimback(char *a, char *e) +{ + while (e > a && (unsigned char)e[-1] <= ' ') + --e; + *e = 0;; + return a; +} + +ST_FUNC int tcc_tool_test(TCCState *s, int argc, char **argv) +{ + const char *fname; + char *buf, *p, *a, *b, *e, tmp[100]; + int r = 0, c, n; + const char sep[] = "/*-* test"; + + n = s->do_test - argc; + if (!n) + return 0; + fname = argv[0], argv -= n, argc += n; + + buf = readfile(fname); + if (NULL == buf) + return -1; + p = strstr(buf, sep); + if (!p) { + tcc_free(buf); + return -1; + } + + while (*p) { + a = p, p = strchr(p, '\n'); + if (NULL == p) + break; + *p++ = 0; + b = p, p = strstr(p, sep); + if (NULL == p) + p = strchr(b, 0); + c = *p, *p = 0; + + trimback(a, b); + if (r) + printf("\n"); + printf("%s\n", a); + fflush(stdout); + + e = a += sizeof sep - 5; + while (*e && *e != ':') + ++e; + if (!*e || e - a > 32) + e = a + 4; + n = snprintf(tmp, sizeof tmp, "#line 1 \"%.*s\"\n", (int)(e - a), a); + if (b - buf >= n) + b = memcpy(b - n, tmp, n); + n = run_prog(b, argc, argv); + if (n != -10000) + printf("returns %d\n", n); + *p = c, ++r; + } + tcc_free(buf); + exit(0); +} + +/* -------------------------------------------------------------- */ diff --git a/tests/tests2/95_bitfields.c b/tests/tests2/95_bitfields.c index 1ec9781..7edbeed 100644 --- a/tests/tests2/95_bitfields.c +++ b/tests/tests2/95_bitfields.c @@ -58,7 +58,7 @@ struct M P __s { long long x : 45; long long : 2; - long long y : 35; + long long y : 30; unsigned long long z : 38; char a; short b; }; diff --git a/tests/tests2/95_bitfields_ms.expect b/tests/tests2/95_bitfields_ms.expect index f4eb2d3..6b5c3f9 100644 --- a/tests/tests2/95_bitfields_ms.expect +++ b/tests/tests2/95_bitfields_ms.expect @@ -23,8 +23,8 @@ values : 03 ffffffff 0f fffffff8 78 align/size : 4 8 ---- TEST 5 - MS-BITFIELDS ---- -bits in use : 00000000FFFF00FF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF -bits as set : 0000000000770044000000000000007800000007F00000000000000123456789 +bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 0000000000770044000000000000007800000000300000000000000123456789 values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 align/size : 8 32 @@ -61,8 +61,8 @@ values : 03 ffffffff 0f fffffff8 78 align/size : 1 8 ---- TEST 5 - MS-BITFIELDS - PACKED ---- -bits in use : FFFFFF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF -bits as set : 007744000000000000007800000007F00000000000000123456789 +bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 007744000000000000007800000000300000000000000123456789 values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 align/size : 1 27 @@ -99,8 +99,8 @@ values : 03 ffffffff 0f fffffff8 78 align/size : 4 8 ---- TEST 5 - MS-BITFIELDS - WITH ALIGN ---- -bits in use : 00000000FFFF00FF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF -bits as set : 0000000000770044000000000000007800000007F00000000000000123456789 +bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 0000000000770044000000000000007800000000300000000000000123456789 values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 align/size : 8 32 @@ -137,8 +137,8 @@ values : 03 ffffffff 0f fffffff8 78 align/size : 1 8 ---- TEST 5 - MS-BITFIELDS - PACKED - WITH ALIGN ---- -bits in use : FFFFFF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF -bits as set : 007744000000000000007800000007F00000000000000123456789 +bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF +bits as set : 007744000000000000007800000000300000000000000123456789 values : 0000000123456789 fffffffff0000000 0000000000000078 44 77 align/size : 1 27 diff --git a/tests/tests2/96_nodata_wanted.c b/tests/tests2/96_nodata_wanted.c new file mode 100644 index 0000000..6f7f3c2 --- /dev/null +++ b/tests/tests2/96_nodata_wanted.c @@ -0,0 +1,74 @@ +/*****************************************************************************/ +/* test 'nodata_wanted' data output suppression */ + +/*-* test 1: initializer not computable 1 */ +void foo() { + if (1) { + static short w = (int)&foo; /* error */ + } +} + +/*-* test 2: initializer not computable 2 */ +void foo() { + if (0) { + static short w = (int)&foo; /* error */ + } +} + +/*-* test 3: initializer not computable 3 */ +void foo(); +static short w = (int)&foo; /* error */ + + +/*-* test 4: 2 cast warnings */ +void foo() { + short w = &foo; /* no error */ +} + +/*-* test 5; nodata_wanted test */ +#include + +#define DATA_LBL(s) \ + __asm__(".global d"#s",t"#s"\n.data\nd"#s":\n.text\nt"#s":\n"); \ + extern char d##s[],t##s[]; + +#define PROG \ + static void *p = (void*)&main;\ + static char cc[] = "static string";\ + static double d = 8.0;\ + static struct __attribute__((packed)) {\ + unsigned x : 12;\ + unsigned char y : 7;\ + unsigned z : 28, a: 4, b: 5;\ + } s = { 0x333,0x44,0x555555,6,7 };\ + printf(" static data: %d - %.1f - %.1f - %s - %s\n",\ + sizeof 8.0, 8.0, d, __FUNCTION__, cc);\ + printf(" static bitfields: %x %x %x %x %x\n", s.x, s.y, s.z, s.a, s.b); + +int main() +{ + printf("suppression off\n"); + DATA_LBL(s1); + if (1) { + PROG + } + DATA_LBL(e1); + printf(" data length is %s\n", de1 - ds1 ? "not 0":"0"); + //printf(" text length is %s\n", te1 - ts1 ? "not 0":"0"); + + printf("suppression on\n"); + DATA_LBL(s2); + if (0) { + PROG + } + DATA_LBL(e2); + printf(" data length is %x\n", de2 - ds2); + //printf(" text length is %X\n", te2 - ts2); + return 0; +} + +/*-* test 6: some test */ +int main() +{ + return 34; +} diff --git a/tests/tests2/96_nodata_wanted.expect b/tests/tests2/96_nodata_wanted.expect new file mode 100644 index 0000000..0db4ba2 --- /dev/null +++ b/tests/tests2/96_nodata_wanted.expect @@ -0,0 +1,24 @@ +/*-* test 1: initializer not computable 1 */ +test 1:3: error: initializer element is not computable at load time + +/*-* test 2: initializer not computable 2 */ +test 2:3: error: initializer element is not computable at load time + +/*-* test 3: initializer not computable 3 */ +test 3:2: error: initializer element is not computable at load time + +/*-* test 4: 2 cast warnings */ +test 4:2: warning: assignment makes integer from pointer without a cast +test 4:2: warning: nonportable conversion from pointer to char/short + +/*-* test 5; nodata_wanted test */ +suppression off + static data: 8 - 8.0 - 8.0 - main - static string + static bitfields: 333 44 555555 6 7 + data length is not 0 +suppression on + data length is 0 +returns 0 + +/*-* test 6: some test */ +returns 34 diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index 44f20f7..832aa49 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -5,29 +5,6 @@ VPATH = $(SRC) TESTS = $(patsubst %.c,%.test,$(sort $(notdir $(wildcard $(SRC)/*.c)))) -# Some tests might need arguments -ARGS = -31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5 -46_grep.test : ARGS = '[^* ]*[:a:d: ]+\:\*-/: $$' $(SRC)/46_grep.c - -# And some tests don't test the right thing with -run -NORUN = -42_function_pointer.test : NORUN = true - -# Some tests might need different flags -FLAGS = -76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers - -# Always generate certain .expects (don't put these in the GIT), -GEN-ALWAYS = 95_bitfields.expect - -# Filter source directory in warnings/errors (out-of-tree builds) -FILTER = 2>&1 | sed 's,$(SRC)/,,g' -# Filter some always-warning -ifeq (-$(findstring arm,$(ARCH))-,-arm-) -FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported' -endif - # some tests do not pass on all platforms, remove them for now SKIP = 34_array_assignment.test # array assignment is not in C standard ifeq ($(CONFIG_arm_eabi),yes) # not ARM soft-float @@ -50,46 +27,80 @@ ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-) SKIP += 95_bitfields_ms.test # type_align is differnt on 32bit-non-windows endif +# Some tests might need arguments +ARGS = +31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5 +46_grep.test : ARGS = '[^* ]*[:a:d: ]+\:\*-/: $$' $(SRC)/46_grep.c + +# And some tests don't test the right thing with -run +NORUN = +42_function_pointer.test : NORUN = true + +# Some tests might need different flags +FLAGS = +76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers + +# run the source file cut into snippets +96_nodata_wanted.test : FLAGS = -dT + +# Always generate certain .expects (don't put these in the GIT), +GEN-ALWAYS = +GEN-ALWAYS += 95_bitfields.expect + +# using the ms compiler for the really ms-compatible bitfields +95_bitfields_ms.test : GEN = $(GEN-MSC) + +# Filter source directory in warnings/errors (out-of-tree builds) +FILTER = 2>&1 | sed 's,$(SRC)/,,g' +# Filter some always-warning +ifeq (-$(findstring arm,$(ARCH))-,-arm-) +FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported' +endif + all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ; %.test: %.c %.expect @echo Test: $*... - @$(if $(NORUN),\ - ($(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS)),\ - $(TCC) $(FLAGS) -run $< $(ARGS)\ - ) $(FILTER) >$*.output 2>&1 || true - @diff -Nbu $(filter %.expect,$^) $*.output \ - && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS)) + @$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3)) -F1 = $(or $(filter $1_%,$(TESTS)),$1_???.test) -F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)" +T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS) +T2 = $(TCC) $(FLAGS) -run $< $(ARGS) +T3 = $(FILTER) >$*.output 2>&1 || true \ + && diff -Nbu $(filter %.expect,$^) $*.output \ + && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS)) # run single test and update .expect file, e.g. "make tests2.37+" tests2.%+: @$(MAKE) $(call F2,$(call F1,$*)) --no-print-directory +# just run tcc to see the output, e.g. "make tests2.37-" +tests2.%-: + @$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory + # run single test, e.g. "make tests2.37" tests2.%: @$(MAKE) $(call F1,$*) --no-print-directory +F1 = $(or $(filter $1_%,$(TESTS)),$1_???.test) +F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)" + # automatically generate .expect files with gcc: %.expect : @echo Generating: $@ - @$(CC) -w -std=gnu99 $(FLAGS) $(SRC)/$*.c -o a.exe - @./a.exe $(ARGS) $(FILTER) >$@ 2>&1 - @rm -f a.exe - -# using the ms compiler for the really ms-compatible bitfields -MS-CC = cl -95_bitfields_ms.expect : - @echo Generating: $@ - @$(MS-CC) $(basename $@).c - @./$(basename $@).exe >$@ 2>&1 + @$(call GEN,$(SRC)/$*.c) $(FILTER) >$@ 2>&1 @rm -f *.exe *.obj *.pdb +# using TCC for .expect if -dT in FLAGS +GEN = $(if $(findstring -dT,$(FLAGS)),$(GEN-TCC),$(GEN-CC)) +GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS) +GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS) +GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe +MS-CC = cl + # tell make not to delete .PRECIOUS: %.expect +# force .expect generation for these files $(sort $(GEN-ALWAYS) $(UPDATE)) : force force: