tinycc/tcc.c

536 lines
16 KiB
C
Raw Normal View History

/*
* TCC - Tiny C Compiler
*
2004-10-28 05:38:03 +08:00
* Copyright (c) 2001-2004 Fabrice Bellard
*
2003-05-24 22:11:17 +08:00
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
2003-05-24 22:11:17 +08:00
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
2003-05-24 22:11:17 +08:00
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
2003-04-14 03:49:30 +08:00
#if defined NOTALLINONE || defined TCC_USE_LIBTCC
2009-07-19 04:08:01 +08:00
#include "tcc.h"
#else
#include "libtcc.c"
2009-07-19 04:08:01 +08:00
#endif
2009-04-18 19:17:27 +08:00
static char **files;
static int nb_files, nb_libraries;
static int multiple_files;
static int print_search_dirs;
static int output_type;
static int reloc_output;
static const char *outfile;
static int do_bench = 0;
tcc: Draft suppoprt for -MD/-MF options In build systems, this is used to automatically collect target dependencies, e.g. ---- 8< (hello.c) ---- #include "hello.h" #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } $ tcc -MD -c hello.c # -> hello.o, hello.d $ cat hello.d hello.o : \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ NOTE: gcc supports -MD only for .c -> .o, but in tcc, we generate dependencies for whatever action is being taken. E.g. for .c -> exe, the result will be: $ tcc -MD -o hello hello.c # -> hello, hello.d hello: \ /usr/lib/crt1.o \ /usr/lib/crti.o \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/lib/libc.so \ /lib/libc.so.6 \ /usr/lib/ld-linux.so.2 \ /lib/ld-linux.so.2 \ /usr/lib/libc_nonshared.a \ /lib/libc.so.6 \ /usr/lib/libc_nonshared.a \ /home/kirr/local/tcc/lib/tcc/libtcc1.a \ /usr/lib/crtn.o \ So tcc dependency generator is a bit more clever than one used in gcc :) Also, I've updated TODO and Changelog (in not-yet-released section). v2: (Taking inputs from grischka and me myself) - put code to generate deps file into a function. - used tcc_fileextension() instead of open-coding - generate deps only when compilation/preprocessing was successful v3: - use pstrcpy instead of snprintf(buf, sizeof(buf), "%s", ...)
2010-06-21 00:08:12 +08:00
static int gen_deps;
static const char *deps_outfile;
#define TCC_OPTION_HAS_ARG 0x0001
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
static void help(void)
2002-05-14 07:00:17 +08:00
{
2006-10-17 03:44:00 +08:00
printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
2010-09-09 01:13:36 +08:00
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
" tcc [options...] -run infile [arguments...]\n"
2002-07-16 06:17:02 +08:00
"General options:\n"
2008-04-01 03:49:14 +08:00
" -v display current version, increase verbosity\n"
2002-07-16 06:17:02 +08:00
" -c compile only - generate an object file\n"
" -o outfile set output filename\n"
" -Bdir set tcc internal library path\n"
" -bench output compilation statistics\n"
" -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
2003-09-20 04:35:50 +08:00
" -w disable all warnings\n"
2002-07-16 06:17:02 +08:00
"Preprocessor options:\n"
2006-10-17 03:44:00 +08:00
" -E preprocess only\n"
2002-07-16 06:17:02 +08:00
" -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n"
"Linker options:\n"
" -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n"
" -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n"
" -shared generate a shared library\n"
" -soname set name for shared library to be used at runtime\n"
" -static static linking\n"
2003-05-25 00:21:09 +08:00
" -rdynamic export all global symbols to dynamic linker\n"
" -r generate (relocatable) object file\n"
"Debugger options:\n"
" -g generate runtime debug info\n"
#ifdef CONFIG_TCC_BCHECK
" -b compile with built-in memory and bounds checker (implies -g)\n"
#endif
#ifdef CONFIG_TCC_BACKTRACE
" -bt N show N callers in stack traces\n"
#endif
tcc: Draft suppoprt for -MD/-MF options In build systems, this is used to automatically collect target dependencies, e.g. ---- 8< (hello.c) ---- #include "hello.h" #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } $ tcc -MD -c hello.c # -> hello.o, hello.d $ cat hello.d hello.o : \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ NOTE: gcc supports -MD only for .c -> .o, but in tcc, we generate dependencies for whatever action is being taken. E.g. for .c -> exe, the result will be: $ tcc -MD -o hello hello.c # -> hello, hello.d hello: \ /usr/lib/crt1.o \ /usr/lib/crti.o \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/lib/libc.so \ /lib/libc.so.6 \ /usr/lib/ld-linux.so.2 \ /lib/ld-linux.so.2 \ /usr/lib/libc_nonshared.a \ /lib/libc.so.6 \ /usr/lib/libc_nonshared.a \ /home/kirr/local/tcc/lib/tcc/libtcc1.a \ /usr/lib/crtn.o \ So tcc dependency generator is a bit more clever than one used in gcc :) Also, I've updated TODO and Changelog (in not-yet-released section). v2: (Taking inputs from grischka and me myself) - put code to generate deps file into a function. - used tcc_fileextension() instead of open-coding - generate deps only when compilation/preprocessing was successful v3: - use pstrcpy instead of snprintf(buf, sizeof(buf), "%s", ...)
2010-06-21 00:08:12 +08:00
"Misc options:\n"
" -MD generate target dependencies for make\n"
" -MF depfile put generated dependencies here\n"
2002-05-14 07:00:17 +08:00
);
}
typedef struct TCCOption {
const char *name;
uint16_t index;
uint16_t flags;
} TCCOption;
enum {
TCC_OPTION_HELP,
TCC_OPTION_I,
TCC_OPTION_D,
TCC_OPTION_U,
TCC_OPTION_L,
TCC_OPTION_B,
TCC_OPTION_l,
TCC_OPTION_bench,
TCC_OPTION_bt,
TCC_OPTION_b,
TCC_OPTION_g,
TCC_OPTION_c,
TCC_OPTION_static,
TCC_OPTION_shared,
TCC_OPTION_soname,
TCC_OPTION_o,
TCC_OPTION_r,
TCC_OPTION_s,
TCC_OPTION_Wl,
TCC_OPTION_W,
TCC_OPTION_O,
TCC_OPTION_m,
TCC_OPTION_f,
TCC_OPTION_nostdinc,
2003-04-27 19:45:01 +08:00
TCC_OPTION_nostdlib,
TCC_OPTION_print_search_dirs,
TCC_OPTION_rdynamic,
TCC_OPTION_pthread,
TCC_OPTION_run,
TCC_OPTION_v,
2003-09-20 04:35:50 +08:00
TCC_OPTION_w,
TCC_OPTION_pipe,
2006-10-17 03:44:00 +08:00
TCC_OPTION_E,
tcc: Draft suppoprt for -MD/-MF options In build systems, this is used to automatically collect target dependencies, e.g. ---- 8< (hello.c) ---- #include "hello.h" #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } $ tcc -MD -c hello.c # -> hello.o, hello.d $ cat hello.d hello.o : \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ NOTE: gcc supports -MD only for .c -> .o, but in tcc, we generate dependencies for whatever action is being taken. E.g. for .c -> exe, the result will be: $ tcc -MD -o hello hello.c # -> hello, hello.d hello: \ /usr/lib/crt1.o \ /usr/lib/crti.o \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/lib/libc.so \ /lib/libc.so.6 \ /usr/lib/ld-linux.so.2 \ /lib/ld-linux.so.2 \ /usr/lib/libc_nonshared.a \ /lib/libc.so.6 \ /usr/lib/libc_nonshared.a \ /home/kirr/local/tcc/lib/tcc/libtcc1.a \ /usr/lib/crtn.o \ So tcc dependency generator is a bit more clever than one used in gcc :) Also, I've updated TODO and Changelog (in not-yet-released section). v2: (Taking inputs from grischka and me myself) - put code to generate deps file into a function. - used tcc_fileextension() instead of open-coding - generate deps only when compilation/preprocessing was successful v3: - use pstrcpy instead of snprintf(buf, sizeof(buf), "%s", ...)
2010-06-21 00:08:12 +08:00
TCC_OPTION_MD,
TCC_OPTION_MF,
2009-06-17 08:11:27 +08:00
TCC_OPTION_x,
};
static const TCCOption tcc_options[] = {
{ "h", TCC_OPTION_HELP, 0 },
2010-01-27 05:58:48 +08:00
{ "-help", TCC_OPTION_HELP, 0 },
{ "?", TCC_OPTION_HELP, 0 },
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "bench", TCC_OPTION_bench, 0 },
2010-09-09 01:13:36 +08:00
#ifdef CONFIG_TCC_BACKTRACE
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
2010-09-09 01:13:36 +08:00
#endif
#ifdef CONFIG_TCC_BCHECK
{ "b", TCC_OPTION_b, 0 },
#endif
{ "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "c", TCC_OPTION_c, 0 },
{ "static", TCC_OPTION_static, 0 },
{ "shared", TCC_OPTION_shared, 0 },
{ "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
{ "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
{ "pthread", TCC_OPTION_pthread, 0},
{ "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2003-05-24 23:46:29 +08:00
{ "rdynamic", TCC_OPTION_rdynamic, 0 },
{ "r", TCC_OPTION_r, 0 },
{ "s", TCC_OPTION_s, 0 },
{ "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
2003-04-27 19:45:01 +08:00
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
2008-04-01 03:49:14 +08:00
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2003-09-20 04:35:50 +08:00
{ "w", TCC_OPTION_w, 0 },
{ "pipe", TCC_OPTION_pipe, 0},
2006-10-17 03:44:00 +08:00
{ "E", TCC_OPTION_E, 0},
tcc: Draft suppoprt for -MD/-MF options In build systems, this is used to automatically collect target dependencies, e.g. ---- 8< (hello.c) ---- #include "hello.h" #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } $ tcc -MD -c hello.c # -> hello.o, hello.d $ cat hello.d hello.o : \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ NOTE: gcc supports -MD only for .c -> .o, but in tcc, we generate dependencies for whatever action is being taken. E.g. for .c -> exe, the result will be: $ tcc -MD -o hello hello.c # -> hello, hello.d hello: \ /usr/lib/crt1.o \ /usr/lib/crti.o \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/lib/libc.so \ /lib/libc.so.6 \ /usr/lib/ld-linux.so.2 \ /lib/ld-linux.so.2 \ /usr/lib/libc_nonshared.a \ /lib/libc.so.6 \ /usr/lib/libc_nonshared.a \ /home/kirr/local/tcc/lib/tcc/libtcc1.a \ /usr/lib/crtn.o \ So tcc dependency generator is a bit more clever than one used in gcc :) Also, I've updated TODO and Changelog (in not-yet-released section). v2: (Taking inputs from grischka and me myself) - put code to generate deps file into a function. - used tcc_fileextension() instead of open-coding - generate deps only when compilation/preprocessing was successful v3: - use pstrcpy instead of snprintf(buf, sizeof(buf), "%s", ...)
2010-06-21 00:08:12 +08:00
{ "MD", TCC_OPTION_MD, 0},
{ "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG },
2009-06-17 08:11:27 +08:00
{ "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
{ NULL },
};
static int64_t getclock_us(void)
{
#ifdef _WIN32
struct _timeb tb;
_ftime(&tb);
return (tb.time * 1000LL + tb.millitm) * 1000LL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000LL + tv.tv_usec;
#endif
}
/* convert 'str' into an array of space separated strings */
static int expand_args(char ***pargv, const char *str)
2002-05-14 07:00:17 +08:00
{
const char *s1;
char **argv, *arg;
int argc, len;
argc = 0;
argv = NULL;
for(;;) {
while (is_space(*str))
str++;
if (*str == '\0')
break;
s1 = str;
while (*str != '\0' && !is_space(*str))
str++;
len = str - s1;
arg = tcc_malloc(len + 1);
memcpy(arg, s1, len);
arg[len] = '\0';
dynarray_add((void ***)&argv, &argc, arg);
}
*pargv = argv;
return argc;
}
static int parse_args(TCCState *s, int argc, char **argv)
{
int optind;
const TCCOption *popt;
const char *optarg, *p1, *r1;
char *r;
2002-05-14 07:00:17 +08:00
optind = 0;
2008-04-28 02:50:35 +08:00
while (optind < argc) {
r = argv[optind++];
if (r[0] != '-' || r[1] == '\0') {
/* add a new file */
dynarray_add((void ***)&files, &nb_files, r);
if (!multiple_files) {
optind--;
/* argv[0] will be this file */
break;
}
} else {
/* find option in table (match only the first chars */
popt = tcc_options;
for(;;) {
p1 = popt->name;
if (p1 == NULL)
error("invalid option -- '%s'", r);
r1 = r + 1;
for(;;) {
if (*p1 == '\0')
goto option_found;
if (*r1 != *p1)
break;
p1++;
r1++;
}
popt++;
}
option_found:
if (popt->flags & TCC_OPTION_HAS_ARG) {
if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) {
optarg = r1;
} else {
if (optind >= argc)
error("argument to '%s' is missing", r);
optarg = argv[optind++];
}
} else {
if (*r1 != '\0')
2008-04-28 02:50:35 +08:00
return 0;
optarg = NULL;
2002-05-14 07:00:17 +08:00
}
switch(popt->index) {
case TCC_OPTION_HELP:
2008-04-28 02:50:35 +08:00
return 0;
case TCC_OPTION_I:
if (tcc_add_include_path(s, optarg) < 0)
error("too many include paths");
break;
case TCC_OPTION_D:
{
char *sym, *value;
sym = (char *)optarg;
value = strchr(sym, '=');
if (value) {
*value = '\0';
value++;
}
tcc_define_symbol(s, sym, value);
}
break;
case TCC_OPTION_U:
tcc_undefine_symbol(s, optarg);
break;
case TCC_OPTION_L:
tcc_add_library_path(s, optarg);
break;
case TCC_OPTION_B:
/* set tcc utilities path (mainly for tcc development) */
2009-04-18 19:17:27 +08:00
tcc_set_lib_path(s, optarg);
break;
case TCC_OPTION_l:
dynarray_add((void ***)&files, &nb_files, r);
nb_libraries++;
break;
case TCC_OPTION_pthread:
/* fixme: these options could be different on your platform */
if(output_type != TCC_OUTPUT_OBJ){
dynarray_add((void ***)&files, &nb_files, "-lpthread");
nb_libraries++;
}
tcc_define_symbol(s, "_REENTRANT", "1");
break;
case TCC_OPTION_bench:
do_bench = 1;
break;
#ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt:
set_num_callers(atoi(optarg));
break;
#endif
#ifdef CONFIG_TCC_BCHECK
case TCC_OPTION_b:
s->do_bounds_check = 1;
s->do_debug = 1;
break;
#endif
case TCC_OPTION_g:
s->do_debug = 1;
break;
case TCC_OPTION_c:
multiple_files = 1;
output_type = TCC_OUTPUT_OBJ;
break;
case TCC_OPTION_static:
s->static_link = 1;
break;
case TCC_OPTION_shared:
output_type = TCC_OUTPUT_DLL;
break;
case TCC_OPTION_soname:
s->soname = optarg;
break;
case TCC_OPTION_o:
multiple_files = 1;
outfile = optarg;
break;
case TCC_OPTION_r:
/* generate a .o merging several output files */
reloc_output = 1;
output_type = TCC_OUTPUT_OBJ;
break;
case TCC_OPTION_nostdinc:
s->nostdinc = 1;
break;
2003-04-27 19:45:01 +08:00
case TCC_OPTION_nostdlib:
s->nostdlib = 1;
break;
case TCC_OPTION_print_search_dirs:
print_search_dirs = 1;
break;
case TCC_OPTION_run:
{
int argc1;
char **argv1;
argc1 = expand_args(&argv1, optarg);
if (argc1 > 0) {
parse_args(s, argc1, argv1);
}
multiple_files = 0;
output_type = TCC_OUTPUT_MEMORY;
}
break;
case TCC_OPTION_v:
2008-04-01 03:49:14 +08:00
do {
if (0 == s->verbose++)
2008-04-01 03:49:14 +08:00
printf("tcc version %s\n", TCC_VERSION);
} while (*optarg++ == 'v');
break;
case TCC_OPTION_f:
if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported)
goto unsupported_option;
break;
case TCC_OPTION_W:
if (tcc_set_warning(s, optarg, 1) < 0 &&
s->warn_unsupported)
goto unsupported_option;
break;
2003-09-20 04:35:50 +08:00
case TCC_OPTION_w:
s->warn_none = 1;
2003-09-20 04:35:50 +08:00
break;
2003-05-24 23:46:29 +08:00
case TCC_OPTION_rdynamic:
s->rdynamic = 1;
break;
case TCC_OPTION_Wl:
{
if ((r = (char *) tcc_set_linker(s, (char *)optarg, TRUE)))
error("unsupported linker option '%s'", r);
}
break;
2006-10-17 03:44:00 +08:00
case TCC_OPTION_E:
output_type = TCC_OUTPUT_PREPROCESS;
break;
tcc: Draft suppoprt for -MD/-MF options In build systems, this is used to automatically collect target dependencies, e.g. ---- 8< (hello.c) ---- #include "hello.h" #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } $ tcc -MD -c hello.c # -> hello.o, hello.d $ cat hello.d hello.o : \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ NOTE: gcc supports -MD only for .c -> .o, but in tcc, we generate dependencies for whatever action is being taken. E.g. for .c -> exe, the result will be: $ tcc -MD -o hello hello.c # -> hello, hello.d hello: \ /usr/lib/crt1.o \ /usr/lib/crti.o \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/lib/libc.so \ /lib/libc.so.6 \ /usr/lib/ld-linux.so.2 \ /lib/ld-linux.so.2 \ /usr/lib/libc_nonshared.a \ /lib/libc.so.6 \ /usr/lib/libc_nonshared.a \ /home/kirr/local/tcc/lib/tcc/libtcc1.a \ /usr/lib/crtn.o \ So tcc dependency generator is a bit more clever than one used in gcc :) Also, I've updated TODO and Changelog (in not-yet-released section). v2: (Taking inputs from grischka and me myself) - put code to generate deps file into a function. - used tcc_fileextension() instead of open-coding - generate deps only when compilation/preprocessing was successful v3: - use pstrcpy instead of snprintf(buf, sizeof(buf), "%s", ...)
2010-06-21 00:08:12 +08:00
case TCC_OPTION_MD:
gen_deps = 1;
break;
case TCC_OPTION_MF:
deps_outfile = optarg;
break;
2009-06-17 08:11:27 +08:00
case TCC_OPTION_x:
break;
default:
if (s->warn_unsupported) {
unsupported_option:
warning("unsupported option '%s'", r);
}
break;
}
}
}
2008-04-28 02:50:35 +08:00
return optind + 1;
}
int main(int argc, char **argv)
{
int i;
TCCState *s;
int nb_objfiles, ret, optind;
int64_t start_time = 0;
2009-04-18 19:17:27 +08:00
s = tcc_new();
2009-07-19 04:07:33 +08:00
output_type = TCC_OUTPUT_EXE;
outfile = NULL;
multiple_files = 1;
files = NULL;
nb_files = 0;
nb_libraries = 0;
reloc_output = 0;
print_search_dirs = 0;
ret = 0;
2008-04-28 02:50:35 +08:00
optind = parse_args(s, argc - 1, argv + 1);
if (print_search_dirs) {
/* enough for Linux kernel */
printf("install: %s/\n", s->tcc_lib_path);
return 0;
}
2008-04-28 02:50:35 +08:00
if (optind == 0 || nb_files == 0) {
if (optind && s->verbose)
2008-04-28 02:50:35 +08:00
return 0;
help();
return 1;
}
nb_objfiles = nb_files - nb_libraries;
/* if outfile provided without other options, we output an
executable */
if (outfile && output_type == TCC_OUTPUT_MEMORY)
output_type = TCC_OUTPUT_EXE;
/* check -c consistency : only single file handled. XXX: checks file type */
if (output_type == TCC_OUTPUT_OBJ && !reloc_output) {
/* accepts only a single input file */
if (nb_objfiles != 1)
error("cannot specify multiple files with -c");
if (nb_libraries != 0)
error("cannot specify libraries with -c");
}
2006-10-17 03:44:00 +08:00
if (output_type == TCC_OUTPUT_PREPROCESS) {
if (!outfile) {
s->outfile = stdout;
} else {
s->outfile = fopen(outfile, "w");
2006-10-17 03:44:00 +08:00
if (!s->outfile)
error("could not open '%s'", outfile);
2006-10-17 03:44:00 +08:00
}
2002-07-16 06:17:02 +08:00
}
if (do_bench) {
start_time = getclock_us();
}
tcc_set_output_type(s, output_type);
s->reloc_output = reloc_output;
/* compile or add each files or library */
for(i = 0; i < nb_files && ret == 0; i++) {
const char *filename;
filename = files[i];
if (filename[0] == '-' && filename[1] == 'l') {
2009-05-12 00:46:02 +08:00
if (tcc_add_library(s, filename + 2) < 0) {
error_noabort("cannot find %s", filename);
ret = 1;
2009-05-12 00:46:02 +08:00
}
} else {
if (1 == s->verbose)
2008-04-01 03:49:14 +08:00
printf("-> %s\n", filename);
if (tcc_add_file(s, filename) < 0)
ret = 1;
}
}
/* free all files */
tcc_free(files);
2009-07-07 03:10:14 +08:00
if (0 == ret) {
if (do_bench)
tcc_print_stats(s, getclock_us() - start_time);
tcc: Draft suppoprt for -MD/-MF options In build systems, this is used to automatically collect target dependencies, e.g. ---- 8< (hello.c) ---- #include "hello.h" #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } $ tcc -MD -c hello.c # -> hello.o, hello.d $ cat hello.d hello.o : \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ NOTE: gcc supports -MD only for .c -> .o, but in tcc, we generate dependencies for whatever action is being taken. E.g. for .c -> exe, the result will be: $ tcc -MD -o hello hello.c # -> hello, hello.d hello: \ /usr/lib/crt1.o \ /usr/lib/crti.o \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/lib/libc.so \ /lib/libc.so.6 \ /usr/lib/ld-linux.so.2 \ /lib/ld-linux.so.2 \ /usr/lib/libc_nonshared.a \ /lib/libc.so.6 \ /usr/lib/libc_nonshared.a \ /home/kirr/local/tcc/lib/tcc/libtcc1.a \ /usr/lib/crtn.o \ So tcc dependency generator is a bit more clever than one used in gcc :) Also, I've updated TODO and Changelog (in not-yet-released section). v2: (Taking inputs from grischka and me myself) - put code to generate deps file into a function. - used tcc_fileextension() instead of open-coding - generate deps only when compilation/preprocessing was successful v3: - use pstrcpy instead of snprintf(buf, sizeof(buf), "%s", ...)
2010-06-21 00:08:12 +08:00
if (s->output_type == TCC_OUTPUT_MEMORY)
2009-07-07 03:10:14 +08:00
ret = tcc_run(s, argc - optind, argv + optind);
else {
tcc: Draft suppoprt for -MD/-MF options In build systems, this is used to automatically collect target dependencies, e.g. ---- 8< (hello.c) ---- #include "hello.h" #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } $ tcc -MD -c hello.c # -> hello.o, hello.d $ cat hello.d hello.o : \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ NOTE: gcc supports -MD only for .c -> .o, but in tcc, we generate dependencies for whatever action is being taken. E.g. for .c -> exe, the result will be: $ tcc -MD -o hello hello.c # -> hello, hello.d hello: \ /usr/lib/crt1.o \ /usr/lib/crti.o \ hello.c \ hello.h \ /usr/include/stdio.h \ /usr/include/features.h \ /usr/include/bits/predefs.h \ /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs.h \ /usr/include/bits/wordsize.h \ /usr/include/gnu/stubs-32.h \ /home/kirr/local/tcc/lib/tcc/include/stddef.h \ /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /home/kirr/local/tcc/lib/tcc/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/lib/libc.so \ /lib/libc.so.6 \ /usr/lib/ld-linux.so.2 \ /lib/ld-linux.so.2 \ /usr/lib/libc_nonshared.a \ /lib/libc.so.6 \ /usr/lib/libc_nonshared.a \ /home/kirr/local/tcc/lib/tcc/libtcc1.a \ /usr/lib/crtn.o \ So tcc dependency generator is a bit more clever than one used in gcc :) Also, I've updated TODO and Changelog (in not-yet-released section). v2: (Taking inputs from grischka and me myself) - put code to generate deps file into a function. - used tcc_fileextension() instead of open-coding - generate deps only when compilation/preprocessing was successful v3: - use pstrcpy instead of snprintf(buf, sizeof(buf), "%s", ...)
2010-06-21 00:08:12 +08:00
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (outfile)
fclose(s->outfile);
} else {
ret = tcc_output_file(s, outfile ? outfile : tcc_default_target(s));
ret = ret ? 1 : 0;
}
/* dump collected dependencies */
if (gen_deps && !ret)
tcc_gen_makedeps(s, outfile, deps_outfile);
}
2009-07-07 03:10:14 +08:00
}
2009-07-07 03:10:14 +08:00
tcc_delete(s);
#ifdef MEM_DEBUG
if (do_bench) {
printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size);
}
#endif
return ret;
2001-10-28 07:48:39 +08:00
}