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.
This commit is contained in:
parent
a1a5c81e6c
commit
989b5ee8ae
3 changed files with 94 additions and 27 deletions
111
libtcc.c
111
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);
|
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 TCCOption *popt;
|
||||||
const char *optarg, *r;
|
const char *optarg, *r;
|
||||||
int run = 0;
|
|
||||||
int pthread = 0;
|
|
||||||
int optind = 0;
|
int optind = 0;
|
||||||
int filetype = 0;
|
ParseArgsState *pas = s->parse_args_state;
|
||||||
|
|
||||||
/* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */
|
|
||||||
CString linker_arg;
|
|
||||||
cstr_new(&linker_arg);
|
|
||||||
|
|
||||||
while (optind < argc) {
|
while (optind < argc) {
|
||||||
|
|
||||||
r = argv[optind++];
|
r = argv[optind++];
|
||||||
if (r[0] != '-' || r[1] == '\0') {
|
if (r[0] != '-' || r[1] == '\0') {
|
||||||
args_parser_add_file(s, r, filetype);
|
/* handle list files */
|
||||||
if (run) {
|
if (r[0] == '@' && r[1]) {
|
||||||
optind--;
|
args_parser_add_listfile(s, r + 1);
|
||||||
/* argv[0] will be this file */
|
} else {
|
||||||
break;
|
args_parser_add_file(s, r, pas->filetype);
|
||||||
|
if (pas->run) {
|
||||||
|
optind--;
|
||||||
|
/* argv[0] will be this file */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2152,7 +2189,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_pthread:
|
case TCC_OPTION_pthread:
|
||||||
parse_option_D(s, "_REENTRANT");
|
parse_option_D(s, "_REENTRANT");
|
||||||
pthread = 1;
|
pas->pthread = 1;
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_bench:
|
case TCC_OPTION_bench:
|
||||||
s->do_bench = 1;
|
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);
|
tcc_warning("-run: some compiler action already specified (%d)", s->output_type);
|
||||||
s->output_type = TCC_OUTPUT_MEMORY;
|
s->output_type = TCC_OUTPUT_MEMORY;
|
||||||
tcc_set_options(s, optarg);
|
tcc_set_options(s, optarg);
|
||||||
run = 1;
|
pas->run = 1;
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_v:
|
case TCC_OPTION_v:
|
||||||
do ++s->verbose; while (*optarg++ == '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;
|
s->rdynamic = 1;
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_Wl:
|
case TCC_OPTION_Wl:
|
||||||
if (linker_arg.size)
|
if (pas->linker_arg.size)
|
||||||
--linker_arg.size, cstr_ccat(&linker_arg, ',');
|
--pas->linker_arg.size, cstr_ccat(&pas->linker_arg, ',');
|
||||||
cstr_cat(&linker_arg, optarg);
|
cstr_cat(&pas->linker_arg, optarg);
|
||||||
cstr_ccat(&linker_arg, '\0');
|
cstr_ccat(&pas->linker_arg, '\0');
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_E:
|
case TCC_OPTION_E:
|
||||||
if (s->output_type)
|
if (s->output_type)
|
||||||
|
@ -2317,13 +2354,13 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_x:
|
case TCC_OPTION_x:
|
||||||
if (*optarg == 'c')
|
if (*optarg == 'c')
|
||||||
filetype = TCC_FILETYPE_C;
|
pas->filetype = TCC_FILETYPE_C;
|
||||||
else
|
else
|
||||||
if (*optarg == 'a')
|
if (*optarg == 'a')
|
||||||
filetype = TCC_FILETYPE_ASM_PP;
|
pas->filetype = TCC_FILETYPE_ASM_PP;
|
||||||
else
|
else
|
||||||
if (*optarg == 'n')
|
if (*optarg == 'n')
|
||||||
filetype = 0;
|
pas->filetype = 0;
|
||||||
else
|
else
|
||||||
tcc_warning("unsupported language '%s'", optarg);
|
tcc_warning("unsupported language '%s'", optarg);
|
||||||
break;
|
break;
|
||||||
|
@ -2349,18 +2386,38 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
|
||||||
break;
|
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)
|
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");
|
tcc_set_options(s, "-lpthread");
|
||||||
|
|
||||||
if (s->output_type == TCC_OUTPUT_EXE)
|
if (s->output_type == TCC_OUTPUT_EXE)
|
||||||
tcc_set_linker(s, (const char *)linker_arg.data);
|
tcc_set_linker(s, (const char *)pas->linker_arg.data);
|
||||||
cstr_free(&linker_arg);
|
|
||||||
|
|
||||||
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)
|
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str)
|
||||||
|
|
1
tcc.c
1
tcc.c
|
@ -92,6 +92,7 @@ static void help(void)
|
||||||
" -bench show compilation statistics\n"
|
" -bench show compilation statistics\n"
|
||||||
" -xc -xa specify type of the next infile\n"
|
" -xc -xa specify type of the next infile\n"
|
||||||
" - use stdin pipe as infile\n"
|
" - use stdin pipe as infile\n"
|
||||||
|
" @listfile read line separated arguments from 'listfile'\n"
|
||||||
"Preprocessor options:\n"
|
"Preprocessor options:\n"
|
||||||
" -Idir add include path 'dir'\n"
|
" -Idir add include path 'dir'\n"
|
||||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||||
|
|
9
tcc.h
9
tcc.h
|
@ -627,6 +627,14 @@ struct sym_attr {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct ParseArgsState
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int pthread;
|
||||||
|
int filetype;
|
||||||
|
CString linker_arg; /* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */
|
||||||
|
} ParseArgsState;
|
||||||
|
|
||||||
struct TCCState {
|
struct TCCState {
|
||||||
|
|
||||||
int verbose; /* if true, display some information during compilation */
|
int verbose; /* if true, display some information during compilation */
|
||||||
|
@ -806,6 +814,7 @@ struct TCCState {
|
||||||
int do_bench; /* option -bench */
|
int do_bench; /* option -bench */
|
||||||
int gen_deps; /* option -MD */
|
int gen_deps; /* option -MD */
|
||||||
char *deps_outfile; /* option -MF */
|
char *deps_outfile; /* option -MF */
|
||||||
|
ParseArgsState *parse_args_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The current value can be: */
|
/* The current value can be: */
|
||||||
|
|
Loading…
Add table
Reference in a new issue