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
27 printf("tcc version " TCC_VERSION
" - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
28 "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
29 " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n"
30 " [-static] [infile1 infile2...] [-run infile args...]\n"
33 " -v display current version, increase verbosity\n"
34 " -c compile only - generate an object file\n"
35 " -o outfile set output filename\n"
36 " -Bdir set tcc internal library path\n"
37 " -bench output compilation statistics\n"
38 " -run run compiled source\n"
39 " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
40 " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
41 " -w disable all warnings\n"
42 "Preprocessor options:\n"
43 " -E preprocess only\n"
44 " -Idir add include path 'dir'\n"
45 " -Dsym[=val] define 'sym' with value 'val'\n"
46 " -Usym undefine 'sym'\n"
48 " -Ldir add library path 'dir'\n"
49 " -llib link with dynamic or static library 'lib'\n"
50 " -shared generate a shared library\n"
51 " -soname set name for shared library to be used at runtime\n"
52 " -static static linking\n"
53 " -rdynamic export all global symbols to dynamic linker\n"
54 " -r generate (relocatable) object file\n"
56 " -g generate runtime debug info\n"
57 #ifdef CONFIG_TCC_BCHECK
58 " -b compile with built-in memory and bounds checker (implies -g)\n"
60 #ifdef CONFIG_TCC_BACKTRACE
61 " -bt N show N callers in stack traces\n"
67 static int nb_files
, nb_libraries
;
68 static int multiple_files
;
69 static int print_search_dirs
;
70 static int output_type
;
71 static int reloc_output
;
72 static const char *outfile
;
73 static int do_bench
= 0;
75 #define TCC_OPTION_HAS_ARG 0x0001
76 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
78 typedef struct TCCOption
{
109 TCC_OPTION_print_search_dirs
,
118 static const TCCOption tcc_options
[] = {
119 { "h", TCC_OPTION_HELP
, 0 },
120 { "?", TCC_OPTION_HELP
, 0 },
121 { "I", TCC_OPTION_I
, TCC_OPTION_HAS_ARG
},
122 { "D", TCC_OPTION_D
, TCC_OPTION_HAS_ARG
},
123 { "U", TCC_OPTION_U
, TCC_OPTION_HAS_ARG
},
124 { "L", TCC_OPTION_L
, TCC_OPTION_HAS_ARG
},
125 { "B", TCC_OPTION_B
, TCC_OPTION_HAS_ARG
},
126 { "l", TCC_OPTION_l
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
127 { "bench", TCC_OPTION_bench
, 0 },
128 { "bt", TCC_OPTION_bt
, TCC_OPTION_HAS_ARG
},
129 #ifdef CONFIG_TCC_BCHECK
130 { "b", TCC_OPTION_b
, 0 },
132 { "g", TCC_OPTION_g
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
133 { "c", TCC_OPTION_c
, 0 },
134 { "static", TCC_OPTION_static
, 0 },
135 { "shared", TCC_OPTION_shared
, 0 },
136 { "soname", TCC_OPTION_soname
, TCC_OPTION_HAS_ARG
},
137 { "o", TCC_OPTION_o
, TCC_OPTION_HAS_ARG
},
138 { "run", TCC_OPTION_run
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
139 { "rdynamic", TCC_OPTION_rdynamic
, 0 },
140 { "r", TCC_OPTION_r
, 0 },
141 { "Wl,", TCC_OPTION_Wl
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
142 { "W", TCC_OPTION_W
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
143 { "O", TCC_OPTION_O
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
144 { "m", TCC_OPTION_m
, TCC_OPTION_HAS_ARG
},
145 { "f", TCC_OPTION_f
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
146 { "nostdinc", TCC_OPTION_nostdinc
, 0 },
147 { "nostdlib", TCC_OPTION_nostdlib
, 0 },
148 { "print-search-dirs", TCC_OPTION_print_search_dirs
, 0 },
149 { "v", TCC_OPTION_v
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
150 { "w", TCC_OPTION_w
, 0 },
151 { "pipe", TCC_OPTION_pipe
, 0},
152 { "E", TCC_OPTION_E
, 0},
156 static int64_t getclock_us(void)
161 return (tb
.time
* 1000LL + tb
.millitm
) * 1000LL;
164 gettimeofday(&tv
, NULL
);
165 return tv
.tv_sec
* 1000000LL + tv
.tv_usec
;
169 static int strstart(const char *str
, const char *val
, const char **ptr
)
185 /* convert 'str' into an array of space separated strings */
186 static int expand_args(char ***pargv
, const char *str
)
195 while (is_space(*str
))
200 while (*str
!= '\0' && !is_space(*str
))
203 arg
= tcc_malloc(len
+ 1);
204 memcpy(arg
, s1
, len
);
206 dynarray_add((void ***)&argv
, &argc
, arg
);
212 int parse_args(TCCState
*s
, int argc
, char **argv
)
215 const TCCOption
*popt
;
216 const char *optarg
, *p1
, *r1
;
220 while (optind
< argc
) {
223 if (r
[0] != '-' || r
[1] == '\0') {
225 dynarray_add((void ***)&files
, &nb_files
, r
);
226 if (!multiple_files
) {
228 /* argv[0] will be this file */
232 /* find option in table (match only the first chars */
237 error("invalid option -- '%s'", r
);
250 if (popt
->flags
& TCC_OPTION_HAS_ARG
) {
251 if (*r1
!= '\0' || (popt
->flags
& TCC_OPTION_NOSEP
)) {
255 error("argument to '%s' is missing", r
);
256 optarg
= argv
[optind
++];
264 switch(popt
->index
) {
265 case TCC_OPTION_HELP
:
269 if (tcc_add_include_path(s
, optarg
) < 0)
270 error("too many include paths");
275 sym
= (char *)optarg
;
276 value
= strchr(sym
, '=');
281 tcc_define_symbol(s
, sym
, value
);
285 tcc_undefine_symbol(s
, optarg
);
288 tcc_add_library_path(s
, optarg
);
291 /* set tcc utilities path (mainly for tcc development) */
292 tcc_set_lib_path(s
, optarg
);
295 dynarray_add((void ***)&files
, &nb_files
, r
);
298 case TCC_OPTION_bench
:
301 #ifdef CONFIG_TCC_BACKTRACE
303 num_callers
= atoi(optarg
);
306 #ifdef CONFIG_TCC_BCHECK
317 output_type
= TCC_OUTPUT_OBJ
;
319 case TCC_OPTION_static
:
322 case TCC_OPTION_shared
:
323 output_type
= TCC_OUTPUT_DLL
;
325 case TCC_OPTION_soname
:
333 /* generate a .o merging several output files */
335 output_type
= TCC_OUTPUT_OBJ
;
337 case TCC_OPTION_nostdinc
:
340 case TCC_OPTION_nostdlib
:
343 case TCC_OPTION_print_search_dirs
:
344 print_search_dirs
= 1;
350 argc1
= expand_args(&argv1
, optarg
);
352 parse_args(s
, argc1
, argv1
);
355 output_type
= TCC_OUTPUT_MEMORY
;
361 printf("tcc version %s\n", TCC_VERSION
);
362 } while (*optarg
++ == 'v');
365 if (tcc_set_flag(s
, optarg
, 1) < 0 && s
->warn_unsupported
)
366 goto unsupported_option
;
369 if (tcc_set_warning(s
, optarg
, 1) < 0 &&
371 goto unsupported_option
;
376 case TCC_OPTION_rdynamic
:
382 if (strstart(optarg
, "-Ttext,", &p
)) {
383 s
->text_addr
= strtoul(p
, NULL
, 16);
384 s
->has_text_addr
= 1;
385 } else if (strstart(optarg
, "--oformat,", &p
)) {
386 if (strstart(p
, "elf32-", NULL
)) {
387 s
->output_format
= TCC_OUTPUT_FORMAT_ELF
;
388 } else if (!strcmp(p
, "binary")) {
389 s
->output_format
= TCC_OUTPUT_FORMAT_BINARY
;
391 #ifdef TCC_TARGET_COFF
392 if (!strcmp(p
, "coff")) {
393 s
->output_format
= TCC_OUTPUT_FORMAT_COFF
;
397 error("target %s not found", p
);
400 error("unsupported linker option '%s'", optarg
);
405 output_type
= TCC_OUTPUT_PREPROCESS
;
408 if (s
->warn_unsupported
) {
410 warning("unsupported option '%s'", r
);
419 int main(int argc
, char **argv
)
423 int nb_objfiles
, ret
, optind
;
424 char objfilename
[1024];
425 int64_t start_time
= 0;
429 tcc_set_lib_path_w32(s
);
431 output_type
= TCC_OUTPUT_EXE
;
438 print_search_dirs
= 0;
441 optind
= parse_args(s
, argc
- 1, argv
+ 1);
442 if (print_search_dirs
) {
443 /* enough for Linux kernel */
444 printf("install: %s/\n", tcc_lib_path
);
447 if (optind
== 0 || nb_files
== 0) {
448 if (optind
&& verbose
)
454 nb_objfiles
= nb_files
- nb_libraries
;
456 /* if outfile provided without other options, we output an
458 if (outfile
&& output_type
== TCC_OUTPUT_MEMORY
)
459 output_type
= TCC_OUTPUT_EXE
;
461 /* check -c consistency : only single file handled. XXX: checks file type */
462 if (output_type
== TCC_OUTPUT_OBJ
&& !reloc_output
) {
463 /* accepts only a single input file */
464 if (nb_objfiles
!= 1)
465 error("cannot specify multiple files with -c");
466 if (nb_libraries
!= 0)
467 error("cannot specify libraries with -c");
471 if (output_type
== TCC_OUTPUT_PREPROCESS
) {
475 s
->outfile
= fopen(outfile
, "w");
477 error("could not open '%s", outfile
);
479 } else if (output_type
!= TCC_OUTPUT_MEMORY
) {
481 /* compute default outfile name */
484 strcmp(files
[0], "-") == 0 ? "a" : tcc_basename(files
[0]);
485 pstrcpy(objfilename
, sizeof(objfilename
), name
);
486 ext
= tcc_fileextension(objfilename
);
488 if (output_type
== TCC_OUTPUT_DLL
)
491 if (output_type
== TCC_OUTPUT_EXE
)
495 if (output_type
== TCC_OUTPUT_OBJ
&& !reloc_output
&& *ext
)
498 pstrcpy(objfilename
, sizeof(objfilename
), "a.out");
499 outfile
= objfilename
;
504 start_time
= getclock_us();
507 tcc_set_output_type(s
, output_type
);
509 /* compile or add each files or library */
510 for(i
= 0; i
< nb_files
&& ret
== 0; i
++) {
511 const char *filename
;
514 if (output_type
== TCC_OUTPUT_PREPROCESS
) {
515 if (tcc_add_file_internal(s
, filename
,
516 AFF_PRINT_ERROR
| AFF_PREPROCESS
) < 0)
518 } else if (filename
[0] == '-' && filename
[1]) {
519 if (tcc_add_library(s
, filename
+ 2) < 0)
520 error("cannot find %s", filename
);
523 printf("-> %s\n", filename
);
524 if (tcc_add_file(s
, filename
) < 0)
537 total_time
= (double)(getclock_us() - start_time
) / 1000000.0;
538 if (total_time
< 0.001)
542 printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n",
543 tok_ident
- TOK_IDENT
, total_lines
, total_bytes
,
544 total_time
, (int)(total_lines
/ total_time
),
545 total_bytes
/ total_time
/ 1000000.0);
548 if (s
->output_type
== TCC_OUTPUT_PREPROCESS
) {
551 } else if (s
->output_type
== TCC_OUTPUT_MEMORY
) {
552 ret
= tcc_run(s
, argc
- optind
, argv
+ optind
);
554 ret
= tcc_output_file(s
, outfile
) ? 1 : 0;
556 /* XXX: cannot do it with bound checking because of the malloc hooks */
557 if (!do_bounds_check
)
562 printf("memory: %d bytes, max = %d bytes\n", mem_cur_size
, mem_max_size
);