763 lines
16 KiB
C
763 lines
16 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif /* HAVE_CONFIG_H */
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <tcc.h>
|
|
#include <tcc/option.h>
|
|
#include <tcc/memory.h>
|
|
#include "utils/string.h"
|
|
|
|
# define F_WD_ALL 0x0001 /* warning is activated when using -Wall */
|
|
# define F_FD_INVERT 0x0002 /* invert value before storing */
|
|
|
|
# define WARN_ON 1 /* warning is on (-Woption) */
|
|
# define WARN_ERR 2 /* warning is an error (-Werror=option) */
|
|
# define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */
|
|
|
|
typedef struct Flag {
|
|
uint16_t offset;
|
|
uint16_t flags;
|
|
const char *name;
|
|
} Flag;
|
|
|
|
enum {
|
|
OPTION_ignored = 0,
|
|
OPTION_HELP,
|
|
OPTION_HELP_MORE,
|
|
OPTION_v,
|
|
OPTION_I,
|
|
OPTION_D,
|
|
OPTION_U,
|
|
OPTION_P,
|
|
OPTION_L,
|
|
OPTION_B,
|
|
OPTION_l,
|
|
OPTION_bench,
|
|
OPTION_c,
|
|
OPTION_dumpmachine,
|
|
OPTION_dumpversion,
|
|
OPTION_d,
|
|
OPTION_std,
|
|
OPTION_o,
|
|
OPTION_pthread,
|
|
OPTION_r,
|
|
OPTION_Wl,
|
|
OPTION_Wp,
|
|
OPTION_W,
|
|
OPTION_O,
|
|
OPTION_m,
|
|
OPTION_f,
|
|
OPTION_isystem,
|
|
OPTION_include,
|
|
OPTION_nostdinc,
|
|
OPTION_nostdlib,
|
|
OPTION_w,
|
|
OPTION_E,
|
|
OPTION_M,
|
|
OPTION_MF,
|
|
OPTION_MD,
|
|
OPTION_MM,
|
|
OPTION_MMD,
|
|
OPTION_MP,
|
|
OPTION_x,
|
|
OPTION_ar,
|
|
};
|
|
|
|
static const TCCOption options[] = {
|
|
{"h", OPTION_HELP, 0},
|
|
{"-help", OPTION_HELP, 0},
|
|
{"?", OPTION_HELP, 0},
|
|
{"hh", OPTION_HELP_MORE, 0},
|
|
{"v", OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"-version", OPTION_v, 0}, /* handle as verbose, also prints version*/
|
|
{"I", OPTION_I, TCC_OPTION_HAS_ARG},
|
|
{"D", OPTION_D, TCC_OPTION_HAS_ARG},
|
|
{"U", OPTION_U, TCC_OPTION_HAS_ARG},
|
|
{"P", OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"L", OPTION_L, TCC_OPTION_HAS_ARG},
|
|
{"B", OPTION_B, TCC_OPTION_HAS_ARG},
|
|
{"l", OPTION_l, TCC_OPTION_HAS_ARG},
|
|
{"bench", OPTION_bench, 0},
|
|
{"c", OPTION_c, 0},
|
|
{"dumpmachine", OPTION_dumpmachine, 0},
|
|
{"dumpversion", OPTION_dumpversion, 0},
|
|
{"d", OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"std", OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"o", OPTION_o, TCC_OPTION_HAS_ARG},
|
|
{"pthread", OPTION_pthread, 0},
|
|
{"r", OPTION_r, 0},
|
|
{"Wl", OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"Wp", OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"W", OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"O", OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"m", OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"f", OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"isystem", OPTION_isystem, TCC_OPTION_HAS_ARG},
|
|
{"include", OPTION_include, TCC_OPTION_HAS_ARG},
|
|
{"nostdinc", OPTION_nostdinc, 0},
|
|
{"nostdlib", OPTION_nostdlib, 0},
|
|
{"w", OPTION_w, 0},
|
|
{"E", OPTION_E, 0},
|
|
{"M", OPTION_M, 0},
|
|
{"MD", OPTION_MD, 0},
|
|
{"MF", OPTION_MF, TCC_OPTION_HAS_ARG},
|
|
{"MM", OPTION_MM, 0},
|
|
{"MMD", OPTION_MMD, 0},
|
|
{"MP", OPTION_MP, 0},
|
|
{"x", OPTION_x, 0},
|
|
{"ar", OPTION_ar, 0},
|
|
|
|
/* ignored (silently, except after -Wunsupported) */
|
|
{"arch", 0, TCC_OPTION_HAS_ARG},
|
|
{"g", 0, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
|
|
{"C", 0, 0},
|
|
{"-param", 0, 0},
|
|
{"pedantic", 0, 0},
|
|
{"pipe", 0, 0},
|
|
{"s", 0, 0},
|
|
{"traditional", 0, 0},
|
|
{"shared", 0, 0},
|
|
{"soname", 0, 0},
|
|
{"static", 0, 0},
|
|
|
|
{NULL, 0, 0}
|
|
};
|
|
|
|
static const Flag options_W[] = {
|
|
{offsetof(TCCState, warn_all), F_WD_ALL, "all"},
|
|
{offsetof(TCCState, warn_error), 0, "error"},
|
|
{offsetof(TCCState, warn_write_strings), 0, "write-strings"},
|
|
{offsetof(TCCState, warn_unsupported), 0, "unsupported"},
|
|
{offsetof(TCCState, warn_implicit_function_declaration), F_WD_ALL, "implicit-function-declaration"},
|
|
{offsetof(TCCState, warn_discarded_qualifiers), F_WD_ALL, "discarded-qualifiers"},
|
|
{0, 0, NULL}
|
|
};
|
|
|
|
static const Flag options_f[] = {
|
|
{offsetof(TCCState, char_is_unsigned), 0, "unsigned-char"},
|
|
{offsetof(TCCState, char_is_unsigned), F_FD_INVERT, "signed-char"},
|
|
{offsetof(TCCState, leading_underscore), 0, "leading-underscore"},
|
|
{offsetof(TCCState, ms_extensions), 0, "ms-extensions"},
|
|
{offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers"},
|
|
{offsetof(TCCState, reverse_funcargs), 0, "reverse-funcargs"},
|
|
{offsetof(TCCState, gnu89_inline), 0, "gnu89-inline"},
|
|
{0, 0, NULL}
|
|
};
|
|
|
|
static const Flag options_m[] = {
|
|
{offsetof(TCCState, ms_bitfields), 0, "ms-bitfields"},
|
|
{0, 0, NULL}
|
|
};
|
|
|
|
static const char dumpmachine_str[] = "i386-pc-stupidos";
|
|
|
|
static int
|
|
strstart(const char *val, const char **str)
|
|
{
|
|
const char *p;
|
|
const char *q;
|
|
|
|
p = *str;
|
|
q = val;
|
|
|
|
while (*q)
|
|
{
|
|
if (*p != *q) return (0);
|
|
p++;
|
|
q++;
|
|
}
|
|
|
|
*str = p;
|
|
return (1);
|
|
}
|
|
|
|
static int
|
|
set_flag(TCCState *s, const Flag *flags, const char *name)
|
|
{
|
|
int value, mask, ret;
|
|
const Flag *p;
|
|
const char *r;
|
|
unsigned char *f;
|
|
|
|
r = name;
|
|
value = !strstart("no-", &r);
|
|
mask = 0;
|
|
|
|
/* when called with options_W, look for -W[no-]error=<option> */
|
|
if ((flags->flags & F_WD_ALL) && strstart("error=", &r))
|
|
{
|
|
value = value ? WARN_ON|WARN_ERR : WARN_NOE;
|
|
mask = WARN_ON;
|
|
}
|
|
|
|
for (ret = -1, p = flags; p->name; ++p)
|
|
{
|
|
if ((ret && strcmp(r, p->name))
|
|
|| ((p->flags & F_WD_ALL) == 0))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
f = (unsigned char *)s + p->offset;
|
|
*f = (*f & mask) | (value ^ !!(p->flags & F_FD_INVERT));
|
|
|
|
if (ret)
|
|
{
|
|
ret = 0;
|
|
if (strcmp(r, "all"))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Like strstart, but automatically takes into account that ld options can
|
|
*
|
|
* - start with double or single dash (e.g. '--soname' or '-soname')
|
|
* - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so'
|
|
* or '-Wl,-soname=x.so')
|
|
*
|
|
* you provide `val` always in 'option[=]' form (no leading -)
|
|
*/
|
|
static int
|
|
link_option(const char *str, const char *val, const char **ptr)
|
|
{
|
|
const char *p, *q;
|
|
int ret;
|
|
|
|
/* there should be 1 or 2 dashes */
|
|
if (*str++ != '-')
|
|
return 0;
|
|
if (*str == '-')
|
|
str++;
|
|
|
|
/* then str & val should match (potentially up to '=') */
|
|
p = str;
|
|
q = val;
|
|
|
|
ret = 1;
|
|
if (q[0] == '?')
|
|
{
|
|
++q;
|
|
if (strstart("no-", &p))
|
|
ret = -1;
|
|
}
|
|
|
|
while (*q != '\0' && *q != '=')
|
|
{
|
|
if (*p != *q)
|
|
return (0);
|
|
p++;
|
|
q++;
|
|
}
|
|
|
|
/* '=' near eos means ',' or '=' is ok */
|
|
if (*q == '=')
|
|
{
|
|
if (*p == 0)
|
|
*ptr = p;
|
|
if (*p != ',' && *p != '=')
|
|
return 0;
|
|
p++;
|
|
} else if (*p) {
|
|
return (0);
|
|
}
|
|
*ptr = p;
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
link_arg(const char *opt, const char *str)
|
|
{
|
|
int l = strlen(opt);
|
|
return 0 == strncmp(opt, str, l) && (str[l] == '\0' || str[l] == ',');
|
|
}
|
|
|
|
static const char *
|
|
skip_linker_arg(const char **str)
|
|
{
|
|
const char *s1 = *str;
|
|
const char *s2 = strchr(s1, ',');
|
|
*str = s2 ? s2++ : (s2 = s1 + strlen(s1));
|
|
return s2;
|
|
}
|
|
|
|
static void
|
|
copy_linker_arg(char **pp, const char *s, int sep)
|
|
{
|
|
const char *q = s;
|
|
char *p = *pp;
|
|
int l = 0;
|
|
if (p && sep)
|
|
p[l = strlen(p)] = sep, ++l;
|
|
skip_linker_arg(&q);
|
|
pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s);
|
|
}
|
|
|
|
/* set linker options */
|
|
static int
|
|
set_linker(TCCState *s, const char *option)
|
|
{
|
|
const char *p;
|
|
char *end;
|
|
int ignoring;
|
|
int ret;
|
|
TCCState *s1 = s;
|
|
|
|
while (*option)
|
|
{
|
|
p = NULL;
|
|
end = NULL;
|
|
ignoring = 0;
|
|
|
|
if (link_option(option, "Bsymbolic", &p))
|
|
{
|
|
s->symbolic = 1;
|
|
} else if (link_option(option, "nostdlib", &p)) {
|
|
s->nostdlib = 1;
|
|
} else if (link_option(option, "e=", &p)
|
|
|| link_option(option, "entry=", &p)) {
|
|
copy_linker_arg(&s->entryname, p, 0);
|
|
} else if (link_option(option, "image-base=", &p)
|
|
|| link_option(option, "Ttext=", &p)) {
|
|
s->text_addr = strtoull(p, &end, 16);
|
|
s->has_text_addr = 1;
|
|
} else if (link_option(option, "oformat=", &p)) {
|
|
if (link_arg("binary", p))
|
|
{
|
|
s->output_format = TCC_OUTPUT_FORMAT_BINARY;
|
|
}
|
|
else if (link_arg("coff", p))
|
|
{
|
|
s->output_format = TCC_OUTPUT_FORMAT_COFF;
|
|
}
|
|
else
|
|
{
|
|
goto err;
|
|
}
|
|
|
|
} else if (link_option(option, "as-needed", &p)) {
|
|
ignoring = 1;
|
|
} else if (link_option(option, "O", &p)) {
|
|
ignoring = 1;
|
|
} else if (link_option(option, "section-alignment=", &p)) {
|
|
s->section_align = strtoul(p, &end, 16);
|
|
} else if (ret = link_option(option, "?whole-archive", &p), ret) {
|
|
if (ret > 0)
|
|
s->filetype |= AFF_WHOLE_ARCHIVE;
|
|
else
|
|
s->filetype &= ~AFF_WHOLE_ARCHIVE;
|
|
} else if (link_option(option, "z=", &p)) {
|
|
ignoring = 1;
|
|
} else if (p) {
|
|
return 0;
|
|
} else {
|
|
err:
|
|
return tcc_error_noabort("unsupported linker option '%s'", option);
|
|
}
|
|
if (ignoring)
|
|
tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", option);
|
|
option = skip_linker_arg(&p);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
args_parser_make_argv(const char *r, int *argc, char ***argv)
|
|
{
|
|
int ret = 0;
|
|
int q;
|
|
int c;
|
|
CString str;
|
|
|
|
for(;;)
|
|
{
|
|
while (c = (unsigned char)*r, c && c <= ' ')
|
|
{
|
|
++r;
|
|
}
|
|
if (c == 0)
|
|
{
|
|
break;
|
|
}
|
|
q = 0;
|
|
cstr_new(&str);
|
|
while (c = (unsigned char)*r, c)
|
|
{
|
|
++r;
|
|
if (c == '\\' && (*r == '"' || *r == '\\'))
|
|
{
|
|
c = *r++;
|
|
}
|
|
else if (c == '"')
|
|
{
|
|
q = !q;
|
|
continue;
|
|
}
|
|
else if (q == 0 && c <= ' ')
|
|
{
|
|
break;
|
|
}
|
|
cstr_ccat(&str, c);
|
|
}
|
|
cstr_ccat(&str, 0);
|
|
dynarray_add(argv, argc, tcc_strdup(str.data));
|
|
cstr_free(&str);
|
|
++ret;
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
args_parser_listfile(TCCState *s, const char *fname, int optind, int *pargc,
|
|
char ***pargv)
|
|
{
|
|
TCCState *s1;
|
|
int fd, i;
|
|
char *p;
|
|
int argc = 0;
|
|
char **argv = NULL;
|
|
|
|
s1 = s;
|
|
|
|
fd = open(fname, O_RDONLY | O_BINARY);
|
|
if (fd < 0)
|
|
{
|
|
return (tcc_error_noabort("listfile '%s' not found", fname));
|
|
}
|
|
|
|
p = tcc_load_text(fd);
|
|
for (i = 0; i < *pargc; ++i)
|
|
{
|
|
if (i == optind)
|
|
{
|
|
args_parser_make_argv(p, &argc, &argv);
|
|
}
|
|
else
|
|
{
|
|
dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i]));
|
|
}
|
|
}
|
|
tcc_free(p);
|
|
dynarray_reset(&s->argv, &s->argc);
|
|
*pargc = s->argc = argc, *pargv = s->argv = argv;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
args_parser_add_file(TCCState *s, const char *fname, int ftype)
|
|
{
|
|
struct filespec *f;
|
|
|
|
f= tcc_malloc(sizeof *f + strlen(fname));
|
|
f->type = ftype;
|
|
strcpy(f->name, fname);
|
|
dynarray_add(&s->files, &s->nb_files, f);
|
|
}
|
|
|
|
int
|
|
tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
|
|
{
|
|
TCCState *s1 = s;
|
|
const TCCOption *popt;
|
|
const char *optarg, *r;
|
|
const char *p1;
|
|
const char *r1;
|
|
int x;
|
|
int tool = 0;
|
|
int arg_start = 0;
|
|
int noaction;
|
|
char **argv;
|
|
int argc;
|
|
|
|
noaction = optind;
|
|
argv = *pargv;
|
|
argc = *pargc;
|
|
|
|
cstr_reset(&s->linker_arg);
|
|
|
|
while (optind < argc) {
|
|
r = argv[optind];
|
|
if (r[0] == '@' && r[1] != '\0')
|
|
{
|
|
if (args_parser_listfile(s, r + 1, optind, &argc, &argv))
|
|
{
|
|
return (-1);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
optind++;
|
|
if (tool)
|
|
{
|
|
if (r[0] == '-' && r[1] == 'v' && r[2] == 0)
|
|
{
|
|
s->verbose++;
|
|
}
|
|
continue;
|
|
}
|
|
reparse:
|
|
if (r[0] != '-' || r[1] == '\0')
|
|
{
|
|
args_parser_add_file(s, r, s->filetype);
|
|
continue;
|
|
}
|
|
|
|
/* find option in table */
|
|
for (popt = options; ; ++popt)
|
|
{
|
|
p1 = popt->name;
|
|
r1 = r + 1;
|
|
if (p1 == NULL)
|
|
{
|
|
return tcc_error_noabort("invalid option -- '%s'", r);
|
|
}
|
|
if (!strstart(p1, &r1))
|
|
{
|
|
continue;
|
|
}
|
|
optarg = r1;
|
|
if (popt->flags & TCC_OPTION_HAS_ARG)
|
|
{
|
|
if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP))
|
|
{
|
|
if (optind >= argc)
|
|
{
|
|
return (tcc_error_noabort("argument to '%s' is missing", r));
|
|
}
|
|
optarg = argv[optind++];
|
|
}
|
|
}
|
|
else if (*r1 != '\0')
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch(popt->index)
|
|
{
|
|
case OPTION_HELP:
|
|
x = TCC_OPT_HELP;
|
|
goto extra_action;
|
|
case OPTION_HELP_MORE:
|
|
x = TCC_OPT_HELP_MORE;
|
|
goto extra_action;
|
|
case OPTION_I:
|
|
tcc_add_include_path(s, optarg);
|
|
break;
|
|
case OPTION_D:
|
|
tcc_define_symbol(s, optarg, NULL);
|
|
break;
|
|
case OPTION_U:
|
|
tcc_undefine_symbol(s, optarg);
|
|
break;
|
|
case OPTION_L:
|
|
tcc_add_library_path(s, optarg);
|
|
break;
|
|
case OPTION_B:
|
|
/* set tcc utilities path (mainly for tcc development) */
|
|
tcc_set_lib_path(s, optarg);
|
|
++noaction;
|
|
break;
|
|
case OPTION_l:
|
|
args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
|
|
s->nb_libraries++;
|
|
break;
|
|
case OPTION_pthread:
|
|
s->option_pthread = 1;
|
|
break;
|
|
case OPTION_bench:
|
|
s->do_bench = 1;
|
|
break;
|
|
case OPTION_c:
|
|
x = TCC_OUTPUT_OBJ;
|
|
set_output_type:
|
|
if (s->output_type)
|
|
tcc_warning("-%s: overriding compiler action already specified", popt->name);
|
|
s->output_type = x;
|
|
break;
|
|
case OPTION_d:
|
|
if (*optarg == 'D')
|
|
s->dflag = 3;
|
|
else if (*optarg == 'M')
|
|
s->dflag = 7;
|
|
else
|
|
goto unsupported_option;
|
|
break;
|
|
case OPTION_std:
|
|
if (strcmp(optarg, "=c11") == 0 || strcmp(optarg, "=gnu11") == 0)
|
|
s->cversion = 201112;
|
|
break;
|
|
case OPTION_o:
|
|
if (s->outfile)
|
|
{
|
|
tcc_warning("multiple -o option");
|
|
tcc_free(s->outfile);
|
|
}
|
|
s->outfile = tcc_strdup(optarg);
|
|
break;
|
|
case OPTION_r:
|
|
/* generate a .o merging several output files */
|
|
s->option_r = 1;
|
|
x = TCC_OUTPUT_OBJ;
|
|
goto set_output_type;
|
|
case OPTION_isystem:
|
|
tcc_add_sysinclude_path(s, optarg);
|
|
break;
|
|
case OPTION_include:
|
|
cstr_printf(&s->cmdline_incl, "#include \"%s\"\n", optarg);
|
|
break;
|
|
case OPTION_nostdinc:
|
|
s->nostdinc = 1;
|
|
break;
|
|
case OPTION_nostdlib:
|
|
s->nostdlib = 1;
|
|
break;
|
|
case OPTION_v:
|
|
do { ++s->verbose; } while (*optarg++ == 'v');
|
|
++noaction;
|
|
break;
|
|
case OPTION_f:
|
|
if (set_flag(s, options_f, optarg) < 0)
|
|
goto unsupported_option;
|
|
break;
|
|
case OPTION_m:
|
|
if (set_flag(s, options_m, optarg) < 0)
|
|
{
|
|
if (x = atoi(optarg), x != 32 && x != 64)
|
|
goto unsupported_option;
|
|
if (PTR_SIZE != x/8)
|
|
return x;
|
|
++noaction;
|
|
}
|
|
break;
|
|
case OPTION_W:
|
|
s->warn_none = 0;
|
|
if (optarg[0] && set_flag(s, options_W, optarg) < 0)
|
|
goto unsupported_option;
|
|
break;
|
|
case OPTION_w:
|
|
s->warn_none = 1;
|
|
break;
|
|
case OPTION_Wl:
|
|
if (s->linker_arg.size)
|
|
((char*)s->linker_arg.data)[s->linker_arg.size - 1] = ',';
|
|
cstr_cat(&s->linker_arg, optarg, 0);
|
|
x = set_linker(s, s->linker_arg.data);
|
|
if (x)
|
|
cstr_reset(&s->linker_arg);
|
|
if (x < 0)
|
|
return -1;
|
|
break;
|
|
case OPTION_Wp:
|
|
r = optarg;
|
|
goto reparse;
|
|
case OPTION_E:
|
|
x = TCC_OUTPUT_PREPROCESS;
|
|
goto set_output_type;
|
|
case OPTION_P:
|
|
s->Pflag = atoi(optarg) + 1;
|
|
break;
|
|
case OPTION_M:
|
|
s->include_sys_deps = 1;
|
|
// fall through
|
|
case OPTION_MM:
|
|
s->just_deps = 1;
|
|
if(!s->deps_outfile)
|
|
s->deps_outfile = tcc_strdup("-");
|
|
// fall through
|
|
case OPTION_MMD:
|
|
s->gen_deps = 1;
|
|
break;
|
|
case OPTION_MD:
|
|
s->gen_deps = 1;
|
|
s->include_sys_deps = 1;
|
|
break;
|
|
case OPTION_MF:
|
|
s->deps_outfile = tcc_strdup(optarg);
|
|
break;
|
|
case OPTION_MP:
|
|
s->gen_phony_deps = 1;
|
|
break;
|
|
case OPTION_dumpmachine:
|
|
printf("%s\n", dumpmachine_str);
|
|
exit(0);
|
|
case OPTION_dumpversion:
|
|
printf ("%s\n", PACKAGE_VERSION);
|
|
exit(0);
|
|
case OPTION_x:
|
|
x = 0;
|
|
if (*optarg == 'c')
|
|
x = AFF_TYPE_C;
|
|
else if (*optarg == 'a')
|
|
x = AFF_TYPE_ASMPP;
|
|
else if (*optarg == 'b')
|
|
x = AFF_TYPE_BIN;
|
|
else if (*optarg == 'n')
|
|
x = AFF_TYPE_NONE;
|
|
else
|
|
tcc_warning("unsupported language '%s'", optarg);
|
|
s->filetype = x | (s->filetype & ~AFF_TYPE_MASK);
|
|
break;
|
|
case OPTION_O:
|
|
s->optimize = atoi(optarg);
|
|
break;
|
|
case OPTION_ar:
|
|
x = TCC_OPT_ARCHIVE;
|
|
extra_action:
|
|
arg_start = optind - 1;
|
|
if (arg_start != noaction)
|
|
return tcc_error_noabort("cannot parse %s here", r);
|
|
tool = x;
|
|
break;
|
|
default:
|
|
unsupported_option:
|
|
tcc_warning_c(warn_unsupported)("unsupported option '%s'", r);
|
|
break;
|
|
}
|
|
}
|
|
if (s->linker_arg.size)
|
|
{
|
|
r = s->linker_arg.data;
|
|
return (tcc_error_noabort("argument to '%s' is missing", r));
|
|
}
|
|
*pargc = argc - arg_start;
|
|
*pargv = argv + arg_start;
|
|
if (tool)
|
|
return (tool);
|
|
if (optind != noaction)
|
|
return (0);
|
|
if (s->verbose)
|
|
return (TCC_OPT_VERSION);
|
|
return (TCC_OPT_HELP);
|
|
}
|
|
|
|
int
|
|
tcc_set_options(TCCState *s, const char *str)
|
|
{
|
|
char **argv;
|
|
int argc;
|
|
int ret;
|
|
|
|
argv = NULL;
|
|
argc = 0;
|
|
args_parser_make_argv(str, &argc, &argv);
|
|
ret = tcc_parse_args(s, &argc, &argv, 0);
|
|
dynarray_reset(&argv, &argc);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return (ret);
|
|
}
|
|
return (0);
|
|
}
|
|
|