1 | /* |
2 | * TCC - Tiny C Compiler |
3 | * |
4 | * Copyright (c) 2001-2004 Fabrice Bellard |
5 | * |
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. |
10 | * |
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. |
15 | * |
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 |
19 | */ |
20 | |
21 | #include "tcc.h" |
22 | #if ONE_SOURCE |
23 | # include "libtcc.c" |
24 | #endif |
25 | #include "tcctools.c" |
26 | |
27 | static const char help[] = |
28 | "Tiny C Compiler " TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n" |
29 | "Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n" |
30 | " tcc [options...] -run infile [arguments...]\n" |
31 | "General options:\n" |
32 | " -c compile only - generate an object file\n" |
33 | " -o outfile set output filename\n" |
34 | " -run run compiled source\n" |
35 | " -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n" |
36 | " -std=c99 Conform to the ISO 1999 C standard (default).\n" |
37 | " -std=c11 Conform to the ISO 2011 C standard.\n" |
38 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" |
39 | " -w disable all warnings\n" |
40 | " --version -v show version\n" |
41 | " -vv show search paths or loaded files\n" |
42 | " -h -hh show this, show more help\n" |
43 | " -bench show compilation statistics\n" |
44 | " - use stdin pipe as infile\n" |
45 | " @listfile read arguments from listfile\n" |
46 | "Preprocessor options:\n" |
47 | " -Idir add include path 'dir'\n" |
48 | " -Dsym[=val] define 'sym' with value 'val'\n" |
49 | " -Usym undefine 'sym'\n" |
50 | " -E preprocess only\n" |
51 | " -C keep comments (not yet implemented)\n" |
52 | "Linker options:\n" |
53 | " -Ldir add library path 'dir'\n" |
54 | " -llib link with dynamic or static library 'lib'\n" |
55 | " -r generate (relocatable) object file\n" |
56 | " -shared generate a shared library/dll\n" |
57 | " -rdynamic export all global symbols to dynamic linker\n" |
58 | " -soname set name for shared library to be used at runtime\n" |
59 | " -Wl,-opt[=val] set linker option (see tcc -hh)\n" |
60 | "Debugger options:\n" |
61 | " -g generate runtime debug info\n" |
62 | #ifdef CONFIG_TCC_BCHECK |
63 | " -b compile with built-in memory and bounds checker (implies -g)\n" |
64 | #endif |
65 | #ifdef CONFIG_TCC_BACKTRACE |
66 | " -bt[N] link with backtrace (stack dump) support [show max N callers]\n" |
67 | #endif |
68 | "Misc. options:\n" |
69 | " -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n" |
70 | " -nostdinc do not use standard system include paths\n" |
71 | " -nostdlib do not link with standard crt and libraries\n" |
72 | " -Bdir set tcc's private include/library dir\n" |
73 | " -MD generate dependency file for make\n" |
74 | " -MF file specify dependency file name\n" |
75 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
76 | " -m32/64 defer to i386/x86_64 cross compiler\n" |
77 | #endif |
78 | "Tools:\n" |
79 | " create library : tcc -ar [rcsv] lib.a files\n" |
80 | #ifdef TCC_TARGET_PE |
81 | " create def file : tcc -impdef lib.dll [-v] [-o lib.def]\n" |
82 | #endif |
83 | ; |
84 | |
85 | static const char help2[] = |
86 | "Tiny C Compiler " TCC_VERSION" - More Options\n" |
87 | "Special options:\n" |
88 | " -P -P1 with -E: no/alternative #line output\n" |
89 | " -dD -dM with -E: output #define directives\n" |
90 | " -pthread same as -D_REENTRANT and -lpthread\n" |
91 | " -On same as -D__OPTIMIZE__ for n > 0\n" |
92 | " -Wp,-opt same as -opt\n" |
93 | " -include file include 'file' above each input file\n" |
94 | " -isystem dir add 'dir' to system include path\n" |
95 | " -static link to static libraries (not recommended)\n" |
96 | " -dumpversion print version\n" |
97 | " -print-search-dirs print search paths\n" |
98 | " -dt with -run/-E: auto-define 'test_...' macros\n" |
99 | "Ignored options:\n" |
100 | " --param -pedantic -pipe -s -traditional\n" |
101 | "-W... warnings:\n" |
102 | " all turn on some (*) warnings\n" |
103 | " error stop after first warning\n" |
104 | " unsupported warn about ignored options, pragmas, etc.\n" |
105 | " write-strings strings are const\n" |
106 | " implicit-function-declaration warn for missing prototype (*)\n" |
107 | "-f[no-]... flags:\n" |
108 | " unsigned-char default char is unsigned\n" |
109 | " signed-char default char is signed\n" |
110 | " common use common section instead of bss\n" |
111 | " leading-underscore decorate extern symbols\n" |
112 | " ms-extensions allow anonymous struct in struct\n" |
113 | " dollars-in-identifiers allow '$' in C symbols\n" |
114 | "-m... target specific options:\n" |
115 | " ms-bitfields use MSVC bitfield layout\n" |
116 | #ifdef TCC_TARGET_ARM |
117 | " float-abi hard/softfp on arm\n" |
118 | #endif |
119 | #ifdef TCC_TARGET_X86_64 |
120 | " no-sse disable floats on x86_64\n" |
121 | #endif |
122 | "-Wl,... linker options:\n" |
123 | " -nostdlib do not link with standard crt/libs\n" |
124 | " -[no-]whole-archive load lib(s) fully/only as needed\n" |
125 | " -export-all-symbols same as -rdynamic\n" |
126 | " -export-dynamic same as -rdynamic\n" |
127 | " -image-base= -Ttext= set base address of executable\n" |
128 | " -section-alignment= set section alignment in executable\n" |
129 | #ifdef TCC_TARGET_PE |
130 | " -file-alignment= set PE file alignment\n" |
131 | " -stack= set PE stack reserve\n" |
132 | " -large-address-aware set related PE option\n" |
133 | " -subsystem=[console/windows] set PE subsystem\n" |
134 | " -oformat=[pe-* binary] set executable output format\n" |
135 | "Predefined macros:\n" |
136 | " tcc -E -dM - < nul\n" |
137 | #else |
138 | " -rpath= set dynamic library search path\n" |
139 | " -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n" |
140 | " -soname= set DT_SONAME elf tag\n" |
141 | " -Bsymbolic set DT_SYMBOLIC elf tag\n" |
142 | " -oformat=[elf32/64-* binary] set executable output format\n" |
143 | " -init= -fini= -as-needed -O (ignored)\n" |
144 | "Predefined macros:\n" |
145 | " tcc -E -dM - < /dev/null\n" |
146 | #endif |
147 | "See also the manual for more details.\n" |
148 | ; |
149 | |
150 | static const char version[] = |
151 | "tcc version " TCC_VERSION" (" |
152 | #ifdef TCC_TARGET_I386 |
153 | "i386" |
154 | #elif defined TCC_TARGET_X86_64 |
155 | "x86_64" |
156 | #elif defined TCC_TARGET_C67 |
157 | "C67" |
158 | #elif defined TCC_TARGET_ARM |
159 | "ARM" |
160 | #elif defined TCC_TARGET_ARM64 |
161 | "AArch64" |
162 | #elif defined TCC_TARGET_RISCV64 |
163 | "riscv64" |
164 | #endif |
165 | #ifdef TCC_ARM_HARDFLOAT |
166 | " Hard Float" |
167 | #endif |
168 | #ifdef TCC_TARGET_PE |
169 | " Windows" |
170 | #elif defined(TCC_TARGET_MACHO) |
171 | " Darwin" |
172 | #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
173 | " FreeBSD" |
174 | #else |
175 | " Linux" |
176 | #endif |
177 | ")\n" |
178 | ; |
179 | |
180 | static void print_dirs(const char *msg, char **paths, int nb_paths) |
181 | { |
182 | int i; |
183 | printf("%s:\n%s" , msg, nb_paths ? "" : " -\n" ); |
184 | for(i = 0; i < nb_paths; i++) |
185 | printf(" %s\n" , paths[i]); |
186 | } |
187 | |
188 | static void print_search_dirs(TCCState *s) |
189 | { |
190 | printf("install: %s\n" , s->tcc_lib_path); |
191 | /* print_dirs("programs", NULL, 0); */ |
192 | print_dirs("include" , s->sysinclude_paths, s->nb_sysinclude_paths); |
193 | print_dirs("libraries" , s->library_paths, s->nb_library_paths); |
194 | #ifdef TCC_TARGET_PE |
195 | printf("libtcc1:\n %s/lib/" TCC_LIBTCC1"\n" , s->tcc_lib_path); |
196 | #else |
197 | printf("libtcc1:\n %s/" TCC_LIBTCC1"\n" , s->tcc_lib_path); |
198 | print_dirs("crt" , s->crt_paths, s->nb_crt_paths); |
199 | printf("elfinterp:\n %s\n" , DEFAULT_ELFINTERP(s)); |
200 | #endif |
201 | } |
202 | |
203 | static void set_environment(TCCState *s) |
204 | { |
205 | char * path; |
206 | |
207 | path = getenv("C_INCLUDE_PATH" ); |
208 | if(path != NULL) { |
209 | tcc_add_sysinclude_path(s, path); |
210 | } |
211 | path = getenv("CPATH" ); |
212 | if(path != NULL) { |
213 | tcc_add_include_path(s, path); |
214 | } |
215 | path = getenv("LIBRARY_PATH" ); |
216 | if(path != NULL) { |
217 | tcc_add_library_path(s, path); |
218 | } |
219 | } |
220 | |
221 | static char *default_outputfile(TCCState *s, const char *first_file) |
222 | { |
223 | char buf[1024]; |
224 | char *ext; |
225 | const char *name = "a" ; |
226 | |
227 | if (first_file && strcmp(first_file, "-" )) |
228 | name = tcc_basename(first_file); |
229 | snprintf(buf, sizeof(buf), "%s" , name); |
230 | ext = tcc_fileextension(buf); |
231 | #ifdef TCC_TARGET_PE |
232 | if (s->output_type == TCC_OUTPUT_DLL) |
233 | strcpy(ext, ".dll" ); |
234 | else |
235 | if (s->output_type == TCC_OUTPUT_EXE) |
236 | strcpy(ext, ".exe" ); |
237 | else |
238 | #endif |
239 | if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r && *ext) |
240 | strcpy(ext, ".o" ); |
241 | else |
242 | strcpy(buf, "a.out" ); |
243 | return tcc_strdup(buf); |
244 | } |
245 | |
246 | static unsigned getclock_ms(void) |
247 | { |
248 | #ifdef _WIN32 |
249 | return GetTickCount(); |
250 | #else |
251 | struct timeval tv; |
252 | gettimeofday(&tv, NULL); |
253 | return tv.tv_sec*1000 + (tv.tv_usec+500)/1000; |
254 | #endif |
255 | } |
256 | |
257 | int main(int argc0, char **argv0) |
258 | { |
259 | TCCState *s, *s1; |
260 | int ret, opt, n = 0, t = 0, done; |
261 | unsigned start_time = 0; |
262 | const char *first_file; |
263 | int argc; char **argv; |
264 | FILE *ppfp = stdout; |
265 | |
266 | redo: |
267 | argc = argc0, argv = argv0; |
268 | s = s1 = tcc_new(); |
269 | opt = tcc_parse_args(s, &argc, &argv, 1); |
270 | |
271 | if (n == 0) { |
272 | if (opt == OPT_HELP) { |
273 | fputs(help, stdout); |
274 | if (!s->verbose) |
275 | return 0; |
276 | ++opt; |
277 | } |
278 | if (opt == OPT_HELP2) { |
279 | fputs(help2, stdout); |
280 | return 0; |
281 | } |
282 | if (opt == OPT_M32 || opt == OPT_M64) |
283 | tcc_tool_cross(s, argv, opt); /* never returns */ |
284 | if (s->verbose) |
285 | printf(version); |
286 | if (opt == OPT_AR) |
287 | return tcc_tool_ar(s, argc, argv); |
288 | #ifdef TCC_TARGET_PE |
289 | if (opt == OPT_IMPDEF) |
290 | return tcc_tool_impdef(s, argc, argv); |
291 | #endif |
292 | if (opt == OPT_V) |
293 | return 0; |
294 | if (opt == OPT_PRINT_DIRS) { |
295 | /* initialize search dirs */ |
296 | set_environment(s); |
297 | tcc_set_output_type(s, TCC_OUTPUT_MEMORY); |
298 | print_search_dirs(s); |
299 | return 0; |
300 | } |
301 | |
302 | if (s->nb_files == 0) |
303 | tcc_error("no input files\n" ); |
304 | |
305 | if (s->output_type == TCC_OUTPUT_PREPROCESS) { |
306 | if (s->outfile && 0!=strcmp("-" ,s->outfile)) { |
307 | ppfp = fopen(s->outfile, "w" ); |
308 | if (!ppfp) |
309 | tcc_error("could not write '%s'" , s->outfile); |
310 | } |
311 | } else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { |
312 | if (s->nb_libraries) |
313 | tcc_error("cannot specify libraries with -c" ); |
314 | if (s->nb_files > 1 && s->outfile) |
315 | tcc_error("cannot specify output file with -c many files" ); |
316 | } |
317 | |
318 | if (s->do_bench) |
319 | start_time = getclock_ms(); |
320 | } |
321 | |
322 | set_environment(s); |
323 | if (s->output_type == 0) |
324 | s->output_type = TCC_OUTPUT_EXE; |
325 | tcc_set_output_type(s, s->output_type); |
326 | s->ppfp = ppfp; |
327 | |
328 | if ((s->output_type == TCC_OUTPUT_MEMORY |
329 | || s->output_type == TCC_OUTPUT_PREPROCESS) |
330 | && (s->dflag & 16)) { /* -dt option */ |
331 | if (t) |
332 | s->dflag |= 32; |
333 | s->run_test = ++t; |
334 | if (n) |
335 | --n; |
336 | } |
337 | |
338 | /* compile or add each files or library */ |
339 | first_file = NULL, ret = 0; |
340 | do { |
341 | struct filespec *f = s->files[n]; |
342 | s->filetype = f->type; |
343 | if (f->type & AFF_TYPE_LIB) { |
344 | if (tcc_add_library_err(s, f->name) < 0) |
345 | ret = 1; |
346 | } else { |
347 | if (1 == s->verbose) |
348 | printf("-> %s\n" , f->name); |
349 | if (!first_file) |
350 | first_file = f->name; |
351 | if (tcc_add_file(s, f->name) < 0) |
352 | ret = 1; |
353 | } |
354 | done = ret || ++n >= s->nb_files; |
355 | } while (!done && (s->output_type != TCC_OUTPUT_OBJ || s->option_r)); |
356 | |
357 | if (s->run_test) { |
358 | t = 0; |
359 | } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { |
360 | ; |
361 | } else if (0 == ret) { |
362 | if (s->output_type == TCC_OUTPUT_MEMORY) { |
363 | #ifdef TCC_IS_NATIVE |
364 | ret = tcc_run(s, argc, argv); |
365 | #endif |
366 | } else { |
367 | if (!s->outfile) |
368 | s->outfile = default_outputfile(s, first_file); |
369 | if (tcc_output_file(s, s->outfile)) |
370 | ret = 1; |
371 | else if (s->gen_deps) |
372 | gen_makedeps(s, s->outfile, s->deps_outfile); |
373 | } |
374 | } |
375 | |
376 | if (s->do_bench && done && !(t | ret)) |
377 | tcc_print_stats(s, getclock_ms() - start_time); |
378 | tcc_delete(s); |
379 | if (!done) |
380 | goto redo; /* compile more files with -c */ |
381 | if (t) |
382 | goto redo; /* run more tests with -dt -run */ |
383 | if (ppfp && ppfp != stdout) |
384 | fclose(ppfp); |
385 | return ret; |
386 | } |
387 | |