tcctools.c: integrate tiny_libmaker/_impdef
usage:
tcc -ar [rcsv] lib files...
tcc -impdef lib.dll [-v] [-o lib.def]
also:
- support more files with -c: tcc -c f1.c f2.c ...
- fix a bug which caused tcc f1.c f2.S to produce no asm
- allow tcc -ar @listfile too
- change prototype: _void_ tcc_set_options(...)
- apply -Wl,-whole-archive when a librariy is given
as libxxx.a also (not just for -lxxx)
This commit is contained in:
212
libtcc.c
212
libtcc.c
@ -239,7 +239,7 @@ PUB_FUNC char *tcc_strdup(const char *str)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
PUB_FUNC void tcc_memstats(int bench)
|
||||
PUB_FUNC void tcc_memcheck(void)
|
||||
{
|
||||
}
|
||||
|
||||
@ -379,7 +379,7 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
PUB_FUNC void tcc_memstats(int bench)
|
||||
PUB_FUNC void tcc_memcheck(void)
|
||||
{
|
||||
if (mem_cur_size) {
|
||||
mem_debug_header_t *header = mem_debug_chain;
|
||||
@ -393,8 +393,7 @@ PUB_FUNC void tcc_memstats(int bench)
|
||||
#if MEM_DEBUG-0 == 2
|
||||
exit(2);
|
||||
#endif
|
||||
} else if (bench)
|
||||
fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size);
|
||||
}
|
||||
}
|
||||
#endif /* MEM_DEBUG */
|
||||
|
||||
@ -435,7 +434,7 @@ ST_FUNC void dynarray_reset(void *pp, int *n)
|
||||
*(void**)pp = NULL;
|
||||
}
|
||||
|
||||
static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char *in)
|
||||
static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in)
|
||||
{
|
||||
const char *p;
|
||||
do {
|
||||
@ -878,18 +877,14 @@ LIBTCCAPI TCCState *tcc_new(void)
|
||||
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
|
||||
"name proto __asm__ (#alias) __THROW");
|
||||
# endif
|
||||
#endif /* ndef TCC_TARGET_PE */
|
||||
|
||||
/* Some GCC builtins that are simple to express as macros. */
|
||||
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
|
||||
|
||||
#endif /* ndef TCC_TARGET_PE */
|
||||
return s;
|
||||
}
|
||||
|
||||
LIBTCCAPI void tcc_delete(TCCState *s1)
|
||||
{
|
||||
int bench = s1->do_bench;
|
||||
|
||||
tcc_cleanup();
|
||||
|
||||
/* free sections */
|
||||
@ -915,6 +910,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
|
||||
dynarray_reset(&s1->files, &s1->nb_files);
|
||||
dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
|
||||
dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
|
||||
dynarray_reset(&s1->argv, &s1->argc);
|
||||
|
||||
#ifdef TCC_IS_NATIVE
|
||||
/* free runtime memory */
|
||||
@ -923,7 +919,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
|
||||
|
||||
tcc_free(s1);
|
||||
if (0 == --nb_states)
|
||||
tcc_memstats(bench);
|
||||
tcc_memcheck();
|
||||
}
|
||||
|
||||
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
|
||||
@ -965,7 +961,7 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
|
||||
# endif
|
||||
#else
|
||||
/* paths for crt objects */
|
||||
tcc_split_path(s, (void ***)&s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
|
||||
tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
|
||||
/* add libc crt1/crti objects */
|
||||
if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
|
||||
!s->nostdlib) {
|
||||
@ -979,13 +975,13 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
|
||||
|
||||
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
|
||||
{
|
||||
tcc_split_path(s, (void ***)&s->include_paths, &s->nb_include_paths, pathname);
|
||||
tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
|
||||
{
|
||||
tcc_split_path(s, (void ***)&s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
|
||||
tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1106,7 +1102,7 @@ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
|
||||
|
||||
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
|
||||
{
|
||||
tcc_split_path(s, (void ***)&s->library_paths, &s->nb_library_paths, pathname);
|
||||
tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1440,6 +1436,7 @@ typedef struct TCCOption {
|
||||
|
||||
enum {
|
||||
TCC_OPTION_HELP,
|
||||
TCC_OPTION_v,
|
||||
TCC_OPTION_I,
|
||||
TCC_OPTION_D,
|
||||
TCC_OPTION_U,
|
||||
@ -1480,13 +1477,14 @@ enum {
|
||||
TCC_OPTION_pedantic,
|
||||
TCC_OPTION_pthread,
|
||||
TCC_OPTION_run,
|
||||
TCC_OPTION_v,
|
||||
TCC_OPTION_w,
|
||||
TCC_OPTION_pipe,
|
||||
TCC_OPTION_E,
|
||||
TCC_OPTION_MD,
|
||||
TCC_OPTION_MF,
|
||||
TCC_OPTION_x
|
||||
TCC_OPTION_x,
|
||||
TCC_OPTION_ar,
|
||||
TCC_OPTION_impdef
|
||||
};
|
||||
|
||||
#define TCC_OPTION_HAS_ARG 0x0001
|
||||
@ -1496,6 +1494,7 @@ static const TCCOption tcc_options[] = {
|
||||
{ "h", TCC_OPTION_HELP, 0 },
|
||||
{ "-help", TCC_OPTION_HELP, 0 },
|
||||
{ "?", TCC_OPTION_HELP, 0 },
|
||||
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
|
||||
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
|
||||
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
|
||||
@ -1542,13 +1541,16 @@ static const TCCOption tcc_options[] = {
|
||||
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
|
||||
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
|
||||
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
|
||||
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "w", TCC_OPTION_w, 0 },
|
||||
{ "pipe", TCC_OPTION_pipe, 0},
|
||||
{ "E", TCC_OPTION_E, 0},
|
||||
{ "MD", TCC_OPTION_MD, 0},
|
||||
{ "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG },
|
||||
{ "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
|
||||
{ "ar", TCC_OPTION_ar, 0},
|
||||
#ifdef TCC_TARGET_PE
|
||||
{ "impdef", TCC_OPTION_impdef, 0},
|
||||
#endif
|
||||
{ NULL, 0, 0 },
|
||||
};
|
||||
|
||||
@ -1595,58 +1597,106 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype
|
||||
{
|
||||
struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
|
||||
f->type = filetype;
|
||||
f->alacarte = s->alacarte_link;
|
||||
strcpy(f->name, filename);
|
||||
dynarray_add(&s->files, &s->nb_files, f);
|
||||
}
|
||||
|
||||
/* read list file */
|
||||
static void args_parser_listfile(TCCState *s, const char *filename)
|
||||
static int args_parser_make_argv(const char *r, int *argc, char ***argv)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0, q, 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);
|
||||
//printf("<%s>\n", str.data), fflush(stdout);
|
||||
dynarray_add(argv, argc, tcc_strdup(str.data));
|
||||
cstr_free(&str);
|
||||
++ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read list file */
|
||||
static void args_parser_listfile(TCCState *s,
|
||||
const char *filename, int optind, int *pargc, char ***pargv)
|
||||
{
|
||||
int fd, i;
|
||||
size_t len;
|
||||
char *p;
|
||||
int argc = 0;
|
||||
char **argv = NULL;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
tcc_error("file '%s' not found", filename);
|
||||
tcc_error("listfile '%s' not found", filename);
|
||||
|
||||
len = lseek(fd, 0, SEEK_END);
|
||||
p = tcc_malloc(len + 1), p[len] = 0;
|
||||
lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd);
|
||||
tcc_set_options(s, p);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
|
||||
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
|
||||
{
|
||||
const TCCOption *popt;
|
||||
const char *optarg, *r;
|
||||
const char *run = NULL;
|
||||
int optind = 0;
|
||||
int x;
|
||||
int last_o = -1;
|
||||
int x;
|
||||
CString linker_arg; /* collect -Wl options */
|
||||
char buf[1024];
|
||||
int tool = 0, arg_start = 0, noaction = optind;
|
||||
char **argv = *pargv;
|
||||
int argc = *pargc;
|
||||
|
||||
cstr_new(&linker_arg);
|
||||
|
||||
while (optind < argc) {
|
||||
|
||||
r = argv[optind++];
|
||||
|
||||
reparse:
|
||||
r = argv[optind];
|
||||
if (r[0] == '@' && r[1] != '\0') {
|
||||
args_parser_listfile(s, r + 1);
|
||||
args_parser_listfile(s, r + 1, optind, &argc, &argv);
|
||||
continue;
|
||||
}
|
||||
|
||||
optind++;
|
||||
if (tool) {
|
||||
if (r[0] == '-' && r[1] == 'v' && r[2] == 0)
|
||||
++s->verbose;
|
||||
continue;
|
||||
}
|
||||
reparse:
|
||||
if (r[0] != '-' || r[1] == '\0') {
|
||||
if (r[0] != '@') /* allow "tcc file(s) -run @ args ..." */
|
||||
args_parser_add_file(s, r, s->filetype);
|
||||
if (run) {
|
||||
tcc_set_options(s, run);
|
||||
optind--;
|
||||
/* argv[0] will be this file */
|
||||
arg_start = optind - 1;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
@ -1675,7 +1725,7 @@ reparse:
|
||||
|
||||
switch(popt->index) {
|
||||
case TCC_OPTION_HELP:
|
||||
return 0;
|
||||
return OPT_HELP;
|
||||
case TCC_OPTION_I:
|
||||
tcc_add_include_path(s, optarg);
|
||||
break;
|
||||
@ -1693,7 +1743,7 @@ reparse:
|
||||
tcc_set_lib_path(s, optarg);
|
||||
break;
|
||||
case TCC_OPTION_l:
|
||||
args_parser_add_file(s, optarg, AFF_TYPE_LIBWH - s->alacarte_link);
|
||||
args_parser_add_file(s, optarg, AFF_TYPE_LIB);
|
||||
s->nb_libraries++;
|
||||
break;
|
||||
case TCC_OPTION_pthread:
|
||||
@ -1774,9 +1824,6 @@ reparse:
|
||||
case TCC_OPTION_nostdlib:
|
||||
s->nostdlib = 1;
|
||||
break;
|
||||
case TCC_OPTION_print_search_dirs:
|
||||
s->print_search_dirs = 1;
|
||||
break;
|
||||
case TCC_OPTION_run:
|
||||
#ifndef TCC_IS_NATIVE
|
||||
tcc_error("-run is not available in a cross compiler");
|
||||
@ -1786,6 +1833,7 @@ reparse:
|
||||
goto set_output_type;
|
||||
case TCC_OPTION_v:
|
||||
do ++s->verbose; while (*optarg++ == 'v');
|
||||
++noaction;
|
||||
break;
|
||||
case TCC_OPTION_f:
|
||||
if (set_flag(s, options_f, optarg) < 0)
|
||||
@ -1804,12 +1852,13 @@ reparse:
|
||||
break;
|
||||
#endif
|
||||
case TCC_OPTION_m:
|
||||
if (set_flag(s, options_m, optarg) == 0)
|
||||
break;
|
||||
else if (x = atoi(optarg), x == 32 || x == 64)
|
||||
s->cross_target = x;
|
||||
else
|
||||
goto unsupported_option;
|
||||
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 TCC_OPTION_W:
|
||||
if (set_flag(s, options_W, optarg) < 0)
|
||||
@ -1860,6 +1909,20 @@ reparse:
|
||||
case TCC_OPTION_O:
|
||||
last_o = atoi(optarg);
|
||||
break;
|
||||
case TCC_OPTION_print_search_dirs:
|
||||
x = OPT_PRINT_DIRS;
|
||||
goto extra_action;
|
||||
case TCC_OPTION_impdef:
|
||||
x = OPT_IMPDEF;
|
||||
goto extra_action;
|
||||
case TCC_OPTION_ar:
|
||||
x = OPT_AR;
|
||||
extra_action:
|
||||
arg_start = optind - 1;
|
||||
if (arg_start != noaction)
|
||||
tcc_error("cannot parse %s here", r);
|
||||
tool = x;
|
||||
break;
|
||||
case TCC_OPTION_traditional:
|
||||
case TCC_OPTION_pedantic:
|
||||
case TCC_OPTION_pipe:
|
||||
@ -1873,53 +1936,32 @@ unsupported_option:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (last_o > 0)
|
||||
tcc_define_symbol(s, "__OPTIMIZE__", NULL);
|
||||
|
||||
if (linker_arg.size) {
|
||||
r = linker_arg.data;
|
||||
goto arg_err;
|
||||
}
|
||||
|
||||
return optind;
|
||||
*pargc = argc - arg_start;
|
||||
*pargv = argv + arg_start;
|
||||
if (tool)
|
||||
return tool;
|
||||
if (optind != noaction)
|
||||
return 0;
|
||||
if (s->verbose == 2)
|
||||
return OPT_PRINT_DIRS;
|
||||
if (s->verbose)
|
||||
return OPT_V;
|
||||
return OPT_HELP;
|
||||
}
|
||||
|
||||
LIBTCCAPI int tcc_set_options(TCCState *s, const char *r)
|
||||
LIBTCCAPI void tcc_set_options(TCCState *s, const char *r)
|
||||
{
|
||||
char **argv;
|
||||
int argc;
|
||||
int ret, q, c;
|
||||
CString str;
|
||||
|
||||
argc = 0, argv = NULL;
|
||||
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);
|
||||
//printf("<%s>\n", str.data), fflush(stdout);
|
||||
dynarray_add(&argv, &argc, tcc_strdup(str.data));
|
||||
cstr_free(&str);
|
||||
}
|
||||
ret = tcc_parse_args(s, argc, argv);
|
||||
char **argv = NULL;
|
||||
int argc = 0;
|
||||
args_parser_make_argv(r, &argc, &argv);
|
||||
tcc_parse_args(s, &argc, &argv, 0);
|
||||
dynarray_reset(&argv, &argc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
|
||||
@ -1928,11 +1970,15 @@ PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
|
||||
total_time = 1;
|
||||
if (total_bytes < 1)
|
||||
total_bytes = 1;
|
||||
fprintf(stderr, "%d idents, %d lines, %d bytes, %0.3f s, %u lines/s, %0.1f MB/s\n",
|
||||
fprintf(stderr, "* %d idents, %d lines, %d bytes\n"
|
||||
"* %0.3f s, %u lines/s, %0.1f MB/s\n",
|
||||
tok_ident - TOK_IDENT, total_lines, total_bytes,
|
||||
(double)total_time/1000,
|
||||
(unsigned)total_lines*1000/total_time,
|
||||
(double)total_bytes/1000/total_time);
|
||||
#ifdef MEM_DEBUG
|
||||
fprintf(stderr, "* %d bytes memory used\n", mem_max_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
PUB_FUNC void tcc_set_environment(TCCState *s)
|
||||
|
||||
Reference in New Issue
Block a user