2 * TCC - Tiny C Compiler
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #if defined NOTALLINONE || defined TCC_USE_LIBTCC
28 static int nb_files
, nb_libraries
;
29 static int multiple_files
;
30 static int print_search_dirs
;
31 static int output_type
;
32 static int reloc_output
;
33 static const char *outfile
;
34 static int do_bench
= 0;
36 static const char *deps_outfile
;
38 #define TCC_OPTION_HAS_ARG 0x0001
39 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
41 static void help(void)
43 printf("tcc version " TCC_VERSION
" - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
44 "Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
45 " tcc [options...] -run infile [arguments...]\n"
47 " -v display current version, increase verbosity\n"
48 " -c compile only - generate an object file\n"
49 " -o outfile set output filename\n"
50 " -Bdir set tcc internal library and include path\n"
51 " -bench output compilation statistics\n"
52 " -run run compiled source\n"
53 " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
54 " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
55 " -w disable all warnings\n"
56 "Preprocessor options:\n"
57 " -E preprocess only\n"
58 " -Idir add include path 'dir'\n"
59 " -Dsym[=val] define 'sym' with value 'val'\n"
60 " -Usym undefine 'sym'\n"
62 " -Ldir add library path 'dir'\n"
63 " -llib link with dynamic or static library 'lib'\n"
64 " -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n"
65 " -shared generate a shared library\n"
66 " -soname set name for shared library to be used at runtime\n"
67 " -static static linking\n"
68 " -rdynamic export all global symbols to dynamic linker\n"
69 " -r generate (relocatable) object file\n"
71 " -g generate runtime debug info\n"
72 #ifdef CONFIG_TCC_BCHECK
73 " -b compile with built-in memory and bounds checker (implies -g)\n"
75 #ifdef CONFIG_TCC_BACKTRACE
76 " -bt N show N callers in stack traces\n"
79 " -MD generate target dependencies for make\n"
80 " -MF depfile put generated dependencies here\n"
84 typedef struct TCCOption
{
117 TCC_OPTION_print_search_dirs
,
131 static const TCCOption tcc_options
[] = {
132 { "h", TCC_OPTION_HELP
, 0 },
133 { "-help", TCC_OPTION_HELP
, 0 },
134 { "?", TCC_OPTION_HELP
, 0 },
135 { "I", TCC_OPTION_I
, TCC_OPTION_HAS_ARG
},
136 { "D", TCC_OPTION_D
, TCC_OPTION_HAS_ARG
},
137 { "U", TCC_OPTION_U
, TCC_OPTION_HAS_ARG
},
138 { "L", TCC_OPTION_L
, TCC_OPTION_HAS_ARG
},
139 { "B", TCC_OPTION_B
, TCC_OPTION_HAS_ARG
},
140 { "l", TCC_OPTION_l
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
141 { "bench", TCC_OPTION_bench
, 0 },
142 #ifdef CONFIG_TCC_BACKTRACE
143 { "bt", TCC_OPTION_bt
, TCC_OPTION_HAS_ARG
},
145 #ifdef CONFIG_TCC_BCHECK
146 { "b", TCC_OPTION_b
, 0 },
148 { "g", TCC_OPTION_g
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
149 { "c", TCC_OPTION_c
, 0 },
150 { "static", TCC_OPTION_static
, 0 },
151 { "shared", TCC_OPTION_shared
, 0 },
152 { "soname", TCC_OPTION_soname
, TCC_OPTION_HAS_ARG
},
153 { "o", TCC_OPTION_o
, TCC_OPTION_HAS_ARG
},
154 { "pedantic", TCC_OPTION_pedantic
, 0},
155 { "pthread", TCC_OPTION_pthread
, 0},
156 { "run", TCC_OPTION_run
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
157 { "rdynamic", TCC_OPTION_rdynamic
, 0 },
158 { "r", TCC_OPTION_r
, 0 },
159 { "s", TCC_OPTION_s
, 0 },
160 { "Wl,", TCC_OPTION_Wl
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
161 { "W", TCC_OPTION_W
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
162 { "O", TCC_OPTION_O
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
163 { "m", TCC_OPTION_m
, TCC_OPTION_HAS_ARG
},
164 { "f", TCC_OPTION_f
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
165 { "isystem", TCC_OPTION_isystem
, TCC_OPTION_HAS_ARG
},
166 { "nostdinc", TCC_OPTION_nostdinc
, 0 },
167 { "nostdlib", TCC_OPTION_nostdlib
, 0 },
168 { "print-search-dirs", TCC_OPTION_print_search_dirs
, 0 },
169 { "v", TCC_OPTION_v
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
170 { "w", TCC_OPTION_w
, 0 },
171 { "pipe", TCC_OPTION_pipe
, 0},
172 { "E", TCC_OPTION_E
, 0},
173 { "MD", TCC_OPTION_MD
, 0},
174 { "MF", TCC_OPTION_MF
, TCC_OPTION_HAS_ARG
},
175 { "x", TCC_OPTION_x
, TCC_OPTION_HAS_ARG
},
179 static int64_t getclock_us(void)
184 return (tb
.time
* 1000LL + tb
.millitm
) * 1000LL;
187 gettimeofday(&tv
, NULL
);
188 return tv
.tv_sec
* 1000000LL + tv
.tv_usec
;
192 /* convert 'str' into an array of space separated strings */
193 static int expand_args(char ***pargv
, const char *str
)
202 while (is_space(*str
))
207 while (*str
!= '\0' && !is_space(*str
))
210 arg
= tcc_malloc(len
+ 1);
211 memcpy(arg
, s1
, len
);
213 dynarray_add((void ***)&argv
, &argc
, arg
);
219 #if defined(TCC_TARGET_X86_64) || defined (TCC_TARGET_I386)
222 #define CAST (const char * const *)
224 #define CAST (char * const *)
227 #if defined(TCC_TARGET_X86_64)
230 #elif defined (TCC_TARGET_I386)
232 #define CHILD "x86_64"
235 static char *ssuffix(const char *oldname
, const char sep
)
237 char *p
, *name
= tcc_strdup(oldname
);
238 p
= strchr(name
, sep
);
241 /* prefix "win32-" when file extension is present */
242 if (*tcc_fileextension(name
)){
243 name
= tcc_realloc(name
, strlen(oldname
+ 7));
244 sprintf(name
, "win32-%s", oldname
);
249 static void exec_other_tcc(TCCState
*s
, int argc
,
250 char **argv
,const char *optarg
, int optind
)
252 char child_path
[4096],child_name
[4096];
253 char *parent
,*child_tcc
;
254 int opt
= atoi(optarg
);
255 if (strlen(argv
[0]) > 4000)
256 error("-m%i unsafe path length", ARG
);
258 case ARG
+ 1: /* oops we called ourselves */
259 error("-m%i cross compiler not installed", ARG
);
263 parent
= tcc_basename(argv
[0]);
264 child_tcc
= ssuffix(parent
,'-');
265 sprintf(child_name
, CHILD
"-%s", child_tcc
);
267 if (strcmp(parent
, child_name
)) {
268 /* child_path = dirname */
269 pstrcpy(child_path
, parent
- argv
[0] + 1, argv
[0]);
270 child_tcc
= strchr(child_path
, 0);
271 strcpy(child_tcc
, child_name
);
273 printf("%s -m%i -> %s\n",
274 parent
, ARG
, child_path
);
275 sprintf(argv
[optind
],"-m%i", ARG
+ 1); /* no loop */
276 execvp(child_path
, CAST argv
);
277 sprintf(child_tcc
,"tcc%s",tcc_fileextension(parent
));
278 execvp(child_path
, CAST argv
);
279 error("-m%i cross compiler not found", ARG
);
280 } else error("-m%i unsupported configuration", ARG
);
282 case 96 ^ ARG
: break;
283 case 96 ^ (ARG
+ 1): break;
285 warning("usupported option \"-m%s\"",optarg
);
293 static int parse_args(TCCState
*s
, int argc
, char **argv
)
296 const TCCOption
*popt
;
297 const char *optarg
, *p1
, *r1
;
301 was_pthread
= 0; /* is set if commandline contains -pthread key */
304 while (optind
< argc
) {
307 if (r
[0] != '-' || r
[1] == '\0') {
309 dynarray_add((void ***)&files
, &nb_files
, r
);
310 if (!multiple_files
) {
312 /* argv[0] will be this file */
316 /* find option in table (match only the first chars */
321 error("invalid option -- '%s'", r
);
334 if (popt
->flags
& TCC_OPTION_HAS_ARG
) {
335 if (*r1
!= '\0' || (popt
->flags
& TCC_OPTION_NOSEP
)) {
339 error("argument to '%s' is missing", r
);
340 optarg
= argv
[optind
++];
348 switch(popt
->index
) {
349 case TCC_OPTION_HELP
:
353 if (tcc_add_include_path(s
, optarg
) < 0)
354 error("too many include paths");
359 sym
= (char *)optarg
;
360 value
= strchr(sym
, '=');
365 tcc_define_symbol(s
, sym
, value
);
369 tcc_undefine_symbol(s
, optarg
);
372 tcc_add_library_path(s
, optarg
);
375 /* set tcc utilities path (mainly for tcc development) */
376 tcc_set_lib_path(s
, optarg
);
377 /* append /include and add it as -isystem, as gcc does */
378 r
= tcc_strdup(optarg
);
379 r
= tcc_realloc(r
, strlen(r
) + 8 + 1);
380 strcat(r
, "/include");
381 tcc_add_sysinclude_path(s
, r
);
385 dynarray_add((void ***)&files
, &nb_files
, r
);
388 case TCC_OPTION_pthread
:
390 tcc_define_symbol(s
, "_REENTRANT", "1");
392 case TCC_OPTION_bench
:
395 #ifdef CONFIG_TCC_BACKTRACE
397 set_num_callers(atoi(optarg
));
400 #ifdef CONFIG_TCC_BCHECK
402 s
->do_bounds_check
= 1;
411 output_type
= TCC_OUTPUT_OBJ
;
413 case TCC_OPTION_static
:
416 case TCC_OPTION_shared
:
417 output_type
= TCC_OUTPUT_DLL
;
419 case TCC_OPTION_soname
:
422 #if defined(TCC_TARGET_X86_64) || defined (TCC_TARGET_I386)
424 exec_other_tcc(s
, argc
+1, argv
-1, optarg
, optind
);
432 /* generate a .o merging several output files */
434 output_type
= TCC_OUTPUT_OBJ
;
436 case TCC_OPTION_isystem
:
437 tcc_add_sysinclude_path(s
, optarg
);
439 case TCC_OPTION_nostdinc
:
442 case TCC_OPTION_nostdlib
:
445 case TCC_OPTION_print_search_dirs
:
446 print_search_dirs
= 1;
452 argc1
= expand_args(&argv1
, optarg
);
454 parse_args(s
, argc1
, argv1
);
457 output_type
= TCC_OUTPUT_MEMORY
;
462 if (0 == s
->verbose
++)
463 printf("tcc version %s\n", TCC_VERSION
);
464 } while (*optarg
++ == 'v');
467 if (tcc_set_flag(s
, optarg
, 1) < 0 && s
->warn_unsupported
)
468 goto unsupported_option
;
471 if (tcc_set_warning(s
, optarg
, 1) < 0 &&
473 goto unsupported_option
;
478 case TCC_OPTION_rdynamic
:
483 if ((r
= (char *) tcc_set_linker(s
, (char *)optarg
, TRUE
)))
484 error("unsupported linker option '%s'", r
);
488 output_type
= TCC_OUTPUT_PREPROCESS
;
494 deps_outfile
= optarg
;
499 if (s
->warn_unsupported
) {
501 warning("unsupported option '%s'", r
);
507 /* fixme: these options could be different on your platform */
509 && output_type
!= TCC_OUTPUT_OBJ
)
511 dynarray_add((void ***)&files
, &nb_files
, "-lpthread");
517 int main(int argc
, char **argv
)
521 int nb_objfiles
, ret
, optind
;
522 int64_t start_time
= 0;
526 output_type
= TCC_OUTPUT_EXE
;
533 print_search_dirs
= 0;
536 optind
= parse_args(s
, argc
- 1, argv
+ 1);
537 if (print_search_dirs
) {
538 /* enough for Linux kernel */
539 printf("install: %s/\n", s
->tcc_lib_path
);
542 if (optind
== 0 || nb_files
== 0) {
543 if (optind
&& s
->verbose
)
549 nb_objfiles
= nb_files
- nb_libraries
;
551 /* if outfile provided without other options, we output an
553 if (outfile
&& output_type
== TCC_OUTPUT_MEMORY
)
554 output_type
= TCC_OUTPUT_EXE
;
556 /* check -c consistency : only single file handled. XXX: checks file type */
557 if (output_type
== TCC_OUTPUT_OBJ
&& !reloc_output
) {
558 /* accepts only a single input file */
559 if (nb_objfiles
!= 1)
560 error("cannot specify multiple files with -c");
561 if (nb_libraries
!= 0)
562 error("cannot specify libraries with -c");
566 if (output_type
== TCC_OUTPUT_PREPROCESS
) {
570 s
->outfile
= fopen(outfile
, "w");
572 error("could not open '%s'", outfile
);
577 start_time
= getclock_us();
580 tcc_set_output_type(s
, output_type
);
581 s
->reloc_output
= reloc_output
;
583 /* compile or add each files or library */
584 for(i
= 0; i
< nb_files
&& ret
== 0; i
++) {
585 const char *filename
;
588 if (filename
[0] == '-' && filename
[1] == 'l') {
589 if (tcc_add_library(s
, filename
+ 2) < 0) {
590 error_noabort("cannot find %s", filename
);
595 printf("-> %s\n", filename
);
596 if (tcc_add_file(s
, filename
) < 0)
606 tcc_print_stats(s
, getclock_us() - start_time
);
608 if (s
->output_type
== TCC_OUTPUT_MEMORY
)
609 ret
= tcc_run(s
, argc
- optind
, argv
+ optind
);
611 if (s
->output_type
== TCC_OUTPUT_PREPROCESS
) {
615 ret
= tcc_output_file(s
, outfile
? outfile
: tcc_default_target(s
));
619 /* dump collected dependencies */
620 if (gen_deps
&& !ret
)
621 tcc_gen_makedeps(s
, outfile
, deps_outfile
);
629 printf("memory: %d bytes, max = %d bytes\n", mem_cur_size
, mem_max_size
);