From 989b5ee8aee98b44377a3c82c5d65f54c0c6eb2f Mon Sep 17 00:00:00 2001 From: seyko Date: Wed, 13 Apr 2016 07:05:38 +0300 Subject: [PATCH] Allow tcc arguments to be read from @listfiles From: Vlad Vissoultchev Date: Tue, 12 Apr 2016 20:43:15 +0300 Subject: Allow tcc arguments to be read from @listfiles This allows all @ prefixed arguments to be treated as listfiles containing list of source files or tcc options where each one is on a separate line. Can be used to benchmark compilation speed with non-trivial amount of source files. The impl of `tcc_parse_args` had to be moved to a new function that is able to be called recursively w/ the original one remaining as a driver of the new one. Listfiles parsing happens in a new `args_parser_add_listfile` function that uses `tcc_open`/`tcc_close/inp` for buffered file input. --- libtcc.c | 111 +++++++++++++++++++++++++++++++++++++++++-------------- tcc.c | 1 + tcc.h | 9 +++++ 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/libtcc.c b/libtcc.c index 7b232a2..1e81922 100644 --- a/libtcc.c +++ b/libtcc.c @@ -2081,28 +2081,65 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype dynarray_add((void ***)&s->files, &s->nb_files, p); } -PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) +ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv); + +ST_FUNC void args_parser_trim_ws() +{ + for (; ch != CH_EOF; inp()) { + if (ch != '\n' && ch != '\r' && !is_space(ch)) + break; + } +} + +ST_FUNC void args_parser_add_listfile(TCCState *s, const char *filename) +{ + char buf[sizeof file->filename], *pb = buf; + char **argv = NULL; + int argc = 0; + + if (tcc_open(s, filename) < 0) + tcc_error("list file '%s' not found", filename); + + for (ch = handle_eob(), args_parser_trim_ws(); ; inp()) { + /* on new line or buffer overflow */ + if (ch == '\n' || ch == '\r' || ch == CH_EOF + || pb - buf >= sizeof(buf) - 1) { + if (pb > buf) { + *pb = 0, pb = buf; + dynarray_add((void ***)&argv, &argc, tcc_strdup(buf)); + args_parser_trim_ws(); + } + } + if (ch == CH_EOF) + break; + *pb++ = ch; + } + tcc_close(); + tcc_parse_args1(s, argc, argv); + dynarray_reset(&argv, &argc); +} + +ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv) { const TCCOption *popt; const char *optarg, *r; - int run = 0; - int pthread = 0; int optind = 0; - int filetype = 0; - - /* collect -Wl options for input such as "-Wl,-rpath -Wl," */ - CString linker_arg; - cstr_new(&linker_arg); + ParseArgsState *pas = s->parse_args_state; while (optind < argc) { r = argv[optind++]; if (r[0] != '-' || r[1] == '\0') { - args_parser_add_file(s, r, filetype); - if (run) { - optind--; - /* argv[0] will be this file */ - break; + /* handle list files */ + if (r[0] == '@' && r[1]) { + args_parser_add_listfile(s, r + 1); + } else { + args_parser_add_file(s, r, pas->filetype); + if (pas->run) { + optind--; + /* argv[0] will be this file */ + break; + } } continue; } @@ -2152,7 +2189,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) break; case TCC_OPTION_pthread: parse_option_D(s, "_REENTRANT"); - pthread = 1; + pas->pthread = 1; break; case TCC_OPTION_bench: s->do_bench = 1; @@ -2267,7 +2304,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) tcc_warning("-run: some compiler action already specified (%d)", s->output_type); s->output_type = TCC_OUTPUT_MEMORY; tcc_set_options(s, optarg); - run = 1; + pas->run = 1; break; case TCC_OPTION_v: do ++s->verbose; while (*optarg++ == 'v'); @@ -2288,10 +2325,10 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) s->rdynamic = 1; break; case TCC_OPTION_Wl: - if (linker_arg.size) - --linker_arg.size, cstr_ccat(&linker_arg, ','); - cstr_cat(&linker_arg, optarg); - cstr_ccat(&linker_arg, '\0'); + if (pas->linker_arg.size) + --pas->linker_arg.size, cstr_ccat(&pas->linker_arg, ','); + cstr_cat(&pas->linker_arg, optarg); + cstr_ccat(&pas->linker_arg, '\0'); break; case TCC_OPTION_E: if (s->output_type) @@ -2317,13 +2354,13 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) break; case TCC_OPTION_x: if (*optarg == 'c') - filetype = TCC_FILETYPE_C; + pas->filetype = TCC_FILETYPE_C; else if (*optarg == 'a') - filetype = TCC_FILETYPE_ASM_PP; + pas->filetype = TCC_FILETYPE_ASM_PP; else if (*optarg == 'n') - filetype = 0; + pas->filetype = 0; else tcc_warning("unsupported language '%s'", optarg); break; @@ -2349,18 +2386,38 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) break; } } + return optind; +} + +PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) +{ + ParseArgsState *pas; + int ret, is_allocated = 0; + + if (!s->parse_args_state) { + s->parse_args_state = tcc_mallocz(sizeof(ParseArgsState)); + cstr_new(&s->parse_args_state->linker_arg); + is_allocated = 1; + } + pas = s->parse_args_state; + + ret = tcc_parse_args1(s, argc, argv); if (s->output_type == 0) - s->output_type = TCC_OUTPUT_EXE; + s->output_type = TCC_OUTPUT_EXE; - if (pthread && s->output_type != TCC_OUTPUT_OBJ) + if (pas->pthread && s->output_type != TCC_OUTPUT_OBJ) tcc_set_options(s, "-lpthread"); if (s->output_type == TCC_OUTPUT_EXE) - tcc_set_linker(s, (const char *)linker_arg.data); - cstr_free(&linker_arg); + tcc_set_linker(s, (const char *)pas->linker_arg.data); - return optind; + if (is_allocated) { + cstr_free(&pas->linker_arg); + tcc_free(pas); + s->parse_args_state = NULL; + } + return ret; } LIBTCCAPI int tcc_set_options(TCCState *s, const char *str) diff --git a/tcc.c b/tcc.c index 94def68..dc75443 100644 --- a/tcc.c +++ b/tcc.c @@ -92,6 +92,7 @@ static void help(void) " -bench show compilation statistics\n" " -xc -xa specify type of the next infile\n" " - use stdin pipe as infile\n" + " @listfile read line separated arguments from 'listfile'\n" "Preprocessor options:\n" " -Idir add include path 'dir'\n" " -Dsym[=val] define 'sym' with value 'val'\n" diff --git a/tcc.h b/tcc.h index fbd320f..831c145 100644 --- a/tcc.h +++ b/tcc.h @@ -627,6 +627,14 @@ struct sym_attr { #endif }; +typedef struct ParseArgsState +{ + int run; + int pthread; + int filetype; + CString linker_arg; /* collect -Wl options for input such as "-Wl,-rpath -Wl," */ +} ParseArgsState; + struct TCCState { int verbose; /* if true, display some information during compilation */ @@ -806,6 +814,7 @@ struct TCCState { int do_bench; /* option -bench */ int gen_deps; /* option -MD */ char *deps_outfile; /* option -MF */ + ParseArgsState *parse_args_state; }; /* The current value can be: */