tcc.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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. #include "libtcc.c"
  21. void help(void)
  22. {
  23. printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
  24. "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
  25. " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n"
  26. " [-static] [infile1 infile2...] [-run infile args...]\n"
  27. "\n"
  28. "General options:\n"
  29. " -v display current version, increase verbosity\n"
  30. " -c compile only - generate an object file\n"
  31. " -o outfile set output filename\n"
  32. " -Bdir set tcc internal library path\n"
  33. " -bench output compilation statistics\n"
  34. " -run run compiled source\n"
  35. " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
  36. " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
  37. " -w disable all warnings\n"
  38. "Preprocessor options:\n"
  39. " -E preprocess only\n"
  40. " -Idir add include path 'dir'\n"
  41. " -Dsym[=val] define 'sym' with value 'val'\n"
  42. " -Usym undefine 'sym'\n"
  43. "Linker options:\n"
  44. " -Ldir add library path 'dir'\n"
  45. " -llib link with dynamic or static library 'lib'\n"
  46. " -shared generate a shared library\n"
  47. " -soname set name for shared library to be used at runtime\n"
  48. " -static static linking\n"
  49. " -rdynamic export all global symbols to dynamic linker\n"
  50. " -r generate (relocatable) object file\n"
  51. "Debugger options:\n"
  52. " -g generate runtime debug info\n"
  53. #ifdef CONFIG_TCC_BCHECK
  54. " -b compile with built-in memory and bounds checker (implies -g)\n"
  55. #endif
  56. #ifdef CONFIG_TCC_BACKTRACE
  57. " -bt N show N callers in stack traces\n"
  58. #endif
  59. );
  60. }
  61. static char **files;
  62. static int nb_files, nb_libraries;
  63. static int multiple_files;
  64. static int print_search_dirs;
  65. static int output_type;
  66. static int reloc_output;
  67. static const char *outfile;
  68. static int do_bench = 0;
  69. #define TCC_OPTION_HAS_ARG 0x0001
  70. #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
  71. typedef struct TCCOption {
  72. const char *name;
  73. uint16_t index;
  74. uint16_t flags;
  75. } TCCOption;
  76. enum {
  77. TCC_OPTION_HELP,
  78. TCC_OPTION_I,
  79. TCC_OPTION_D,
  80. TCC_OPTION_U,
  81. TCC_OPTION_L,
  82. TCC_OPTION_B,
  83. TCC_OPTION_l,
  84. TCC_OPTION_bench,
  85. TCC_OPTION_bt,
  86. TCC_OPTION_b,
  87. TCC_OPTION_g,
  88. TCC_OPTION_c,
  89. TCC_OPTION_static,
  90. TCC_OPTION_shared,
  91. TCC_OPTION_soname,
  92. TCC_OPTION_o,
  93. TCC_OPTION_r,
  94. TCC_OPTION_Wl,
  95. TCC_OPTION_W,
  96. TCC_OPTION_O,
  97. TCC_OPTION_m,
  98. TCC_OPTION_f,
  99. TCC_OPTION_nostdinc,
  100. TCC_OPTION_nostdlib,
  101. TCC_OPTION_print_search_dirs,
  102. TCC_OPTION_rdynamic,
  103. TCC_OPTION_run,
  104. TCC_OPTION_v,
  105. TCC_OPTION_w,
  106. TCC_OPTION_pipe,
  107. TCC_OPTION_E,
  108. };
  109. static const TCCOption tcc_options[] = {
  110. { "h", TCC_OPTION_HELP, 0 },
  111. { "?", TCC_OPTION_HELP, 0 },
  112. { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
  113. { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
  114. { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
  115. { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
  116. { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
  117. { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  118. { "bench", TCC_OPTION_bench, 0 },
  119. { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
  120. #ifdef CONFIG_TCC_BCHECK
  121. { "b", TCC_OPTION_b, 0 },
  122. #endif
  123. { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  124. { "c", TCC_OPTION_c, 0 },
  125. { "static", TCC_OPTION_static, 0 },
  126. { "shared", TCC_OPTION_shared, 0 },
  127. { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
  128. { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
  129. { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  130. { "rdynamic", TCC_OPTION_rdynamic, 0 },
  131. { "r", TCC_OPTION_r, 0 },
  132. { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  133. { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  134. { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  135. { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
  136. { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  137. { "nostdinc", TCC_OPTION_nostdinc, 0 },
  138. { "nostdlib", TCC_OPTION_nostdlib, 0 },
  139. { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
  140. { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
  141. { "w", TCC_OPTION_w, 0 },
  142. { "pipe", TCC_OPTION_pipe, 0},
  143. { "E", TCC_OPTION_E, 0},
  144. { NULL },
  145. };
  146. static int64_t getclock_us(void)
  147. {
  148. #ifdef _WIN32
  149. struct _timeb tb;
  150. _ftime(&tb);
  151. return (tb.time * 1000LL + tb.millitm) * 1000LL;
  152. #else
  153. struct timeval tv;
  154. gettimeofday(&tv, NULL);
  155. return tv.tv_sec * 1000000LL + tv.tv_usec;
  156. #endif
  157. }
  158. static int strstart(const char *str, const char *val, const char **ptr)
  159. {
  160. const char *p, *q;
  161. p = str;
  162. q = val;
  163. while (*q != '\0') {
  164. if (*p != *q)
  165. return 0;
  166. p++;
  167. q++;
  168. }
  169. if (ptr)
  170. *ptr = p;
  171. return 1;
  172. }
  173. /* convert 'str' into an array of space separated strings */
  174. static int expand_args(char ***pargv, const char *str)
  175. {
  176. const char *s1;
  177. char **argv, *arg;
  178. int argc, len;
  179. argc = 0;
  180. argv = NULL;
  181. for(;;) {
  182. while (is_space(*str))
  183. str++;
  184. if (*str == '\0')
  185. break;
  186. s1 = str;
  187. while (*str != '\0' && !is_space(*str))
  188. str++;
  189. len = str - s1;
  190. arg = tcc_malloc(len + 1);
  191. memcpy(arg, s1, len);
  192. arg[len] = '\0';
  193. dynarray_add((void ***)&argv, &argc, arg);
  194. }
  195. *pargv = argv;
  196. return argc;
  197. }
  198. int parse_args(TCCState *s, int argc, char **argv)
  199. {
  200. int optind;
  201. const TCCOption *popt;
  202. const char *optarg, *p1, *r1;
  203. char *r;
  204. optind = 0;
  205. while (optind < argc) {
  206. r = argv[optind++];
  207. if (r[0] != '-' || r[1] == '\0') {
  208. /* add a new file */
  209. dynarray_add((void ***)&files, &nb_files, r);
  210. if (!multiple_files) {
  211. optind--;
  212. /* argv[0] will be this file */
  213. break;
  214. }
  215. } else {
  216. /* find option in table (match only the first chars */
  217. popt = tcc_options;
  218. for(;;) {
  219. p1 = popt->name;
  220. if (p1 == NULL)
  221. error("invalid option -- '%s'", r);
  222. r1 = r + 1;
  223. for(;;) {
  224. if (*p1 == '\0')
  225. goto option_found;
  226. if (*r1 != *p1)
  227. break;
  228. p1++;
  229. r1++;
  230. }
  231. popt++;
  232. }
  233. option_found:
  234. if (popt->flags & TCC_OPTION_HAS_ARG) {
  235. if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) {
  236. optarg = r1;
  237. } else {
  238. if (optind >= argc)
  239. error("argument to '%s' is missing", r);
  240. optarg = argv[optind++];
  241. }
  242. } else {
  243. if (*r1 != '\0')
  244. return 0;
  245. optarg = NULL;
  246. }
  247. switch(popt->index) {
  248. case TCC_OPTION_HELP:
  249. return 0;
  250. case TCC_OPTION_I:
  251. if (tcc_add_include_path(s, optarg) < 0)
  252. error("too many include paths");
  253. break;
  254. case TCC_OPTION_D:
  255. {
  256. char *sym, *value;
  257. sym = (char *)optarg;
  258. value = strchr(sym, '=');
  259. if (value) {
  260. *value = '\0';
  261. value++;
  262. }
  263. tcc_define_symbol(s, sym, value);
  264. }
  265. break;
  266. case TCC_OPTION_U:
  267. tcc_undefine_symbol(s, optarg);
  268. break;
  269. case TCC_OPTION_L:
  270. tcc_add_library_path(s, optarg);
  271. break;
  272. case TCC_OPTION_B:
  273. /* set tcc utilities path (mainly for tcc development) */
  274. tcc_set_lib_path(s, optarg);
  275. break;
  276. case TCC_OPTION_l:
  277. dynarray_add((void ***)&files, &nb_files, r);
  278. nb_libraries++;
  279. break;
  280. case TCC_OPTION_bench:
  281. do_bench = 1;
  282. break;
  283. #ifdef CONFIG_TCC_BACKTRACE
  284. case TCC_OPTION_bt:
  285. num_callers = atoi(optarg);
  286. break;
  287. #endif
  288. #ifdef CONFIG_TCC_BCHECK
  289. case TCC_OPTION_b:
  290. s->do_bounds_check = 1;
  291. s->do_debug = 1;
  292. break;
  293. #endif
  294. case TCC_OPTION_g:
  295. s->do_debug = 1;
  296. break;
  297. case TCC_OPTION_c:
  298. multiple_files = 1;
  299. output_type = TCC_OUTPUT_OBJ;
  300. break;
  301. case TCC_OPTION_static:
  302. s->static_link = 1;
  303. break;
  304. case TCC_OPTION_shared:
  305. output_type = TCC_OUTPUT_DLL;
  306. break;
  307. case TCC_OPTION_soname:
  308. s->soname = optarg;
  309. break;
  310. case TCC_OPTION_o:
  311. multiple_files = 1;
  312. outfile = optarg;
  313. break;
  314. case TCC_OPTION_r:
  315. /* generate a .o merging several output files */
  316. reloc_output = 1;
  317. output_type = TCC_OUTPUT_OBJ;
  318. break;
  319. case TCC_OPTION_nostdinc:
  320. s->nostdinc = 1;
  321. break;
  322. case TCC_OPTION_nostdlib:
  323. s->nostdlib = 1;
  324. break;
  325. case TCC_OPTION_print_search_dirs:
  326. print_search_dirs = 1;
  327. break;
  328. case TCC_OPTION_run:
  329. {
  330. int argc1;
  331. char **argv1;
  332. argc1 = expand_args(&argv1, optarg);
  333. if (argc1 > 0) {
  334. parse_args(s, argc1, argv1);
  335. }
  336. multiple_files = 0;
  337. output_type = TCC_OUTPUT_MEMORY;
  338. }
  339. break;
  340. case TCC_OPTION_v:
  341. do {
  342. if (0 == s->verbose++)
  343. printf("tcc version %s\n", TCC_VERSION);
  344. } while (*optarg++ == 'v');
  345. break;
  346. case TCC_OPTION_f:
  347. if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported)
  348. goto unsupported_option;
  349. break;
  350. case TCC_OPTION_W:
  351. if (tcc_set_warning(s, optarg, 1) < 0 &&
  352. s->warn_unsupported)
  353. goto unsupported_option;
  354. break;
  355. case TCC_OPTION_w:
  356. s->warn_none = 1;
  357. break;
  358. case TCC_OPTION_rdynamic:
  359. s->rdynamic = 1;
  360. break;
  361. case TCC_OPTION_Wl:
  362. {
  363. const char *p;
  364. if (strstart(optarg, "-Ttext,", &p)) {
  365. s->text_addr = strtoul(p, NULL, 16);
  366. s->has_text_addr = 1;
  367. } else if (strstart(optarg, "--oformat,", &p)) {
  368. if (strstart(p, "elf32-", NULL)) {
  369. s->output_format = TCC_OUTPUT_FORMAT_ELF;
  370. } else if (!strcmp(p, "binary")) {
  371. s->output_format = TCC_OUTPUT_FORMAT_BINARY;
  372. } else
  373. #ifdef TCC_TARGET_COFF
  374. if (!strcmp(p, "coff")) {
  375. s->output_format = TCC_OUTPUT_FORMAT_COFF;
  376. } else
  377. #endif
  378. {
  379. error("target %s not found", p);
  380. }
  381. } else {
  382. error("unsupported linker option '%s'", optarg);
  383. }
  384. }
  385. break;
  386. case TCC_OPTION_E:
  387. output_type = TCC_OUTPUT_PREPROCESS;
  388. break;
  389. default:
  390. if (s->warn_unsupported) {
  391. unsupported_option:
  392. warning("unsupported option '%s'", r);
  393. }
  394. break;
  395. }
  396. }
  397. }
  398. return optind + 1;
  399. }
  400. int main(int argc, char **argv)
  401. {
  402. int i;
  403. TCCState *s;
  404. int nb_objfiles, ret, optind;
  405. char objfilename[1024];
  406. int64_t start_time = 0;
  407. s = tcc_new();
  408. #ifdef _WIN32
  409. tcc_set_lib_path_w32(s);
  410. #endif
  411. output_type = TCC_OUTPUT_EXE;
  412. outfile = NULL;
  413. multiple_files = 1;
  414. files = NULL;
  415. nb_files = 0;
  416. nb_libraries = 0;
  417. reloc_output = 0;
  418. print_search_dirs = 0;
  419. ret = 0;
  420. optind = parse_args(s, argc - 1, argv + 1);
  421. if (print_search_dirs) {
  422. /* enough for Linux kernel */
  423. printf("install: %s/\n", s->tcc_lib_path);
  424. return 0;
  425. }
  426. if (optind == 0 || nb_files == 0) {
  427. if (optind && s->verbose)
  428. return 0;
  429. help();
  430. return 1;
  431. }
  432. nb_objfiles = nb_files - nb_libraries;
  433. /* if outfile provided without other options, we output an
  434. executable */
  435. if (outfile && output_type == TCC_OUTPUT_MEMORY)
  436. output_type = TCC_OUTPUT_EXE;
  437. /* check -c consistency : only single file handled. XXX: checks file type */
  438. if (output_type == TCC_OUTPUT_OBJ && !reloc_output) {
  439. /* accepts only a single input file */
  440. if (nb_objfiles != 1)
  441. error("cannot specify multiple files with -c");
  442. if (nb_libraries != 0)
  443. error("cannot specify libraries with -c");
  444. }
  445. if (output_type == TCC_OUTPUT_PREPROCESS) {
  446. if (!outfile) {
  447. s->outfile = stdout;
  448. } else {
  449. s->outfile = fopen(outfile, "w");
  450. if (!s->outfile)
  451. error("could not open '%s", outfile);
  452. }
  453. } else if (output_type != TCC_OUTPUT_MEMORY) {
  454. if (!outfile) {
  455. /* compute default outfile name */
  456. char *ext;
  457. const char *name =
  458. strcmp(files[0], "-") == 0 ? "a" : tcc_basename(files[0]);
  459. pstrcpy(objfilename, sizeof(objfilename), name);
  460. ext = tcc_fileextension(objfilename);
  461. #ifdef TCC_TARGET_PE
  462. if (output_type == TCC_OUTPUT_DLL)
  463. strcpy(ext, ".dll");
  464. else
  465. if (output_type == TCC_OUTPUT_EXE)
  466. strcpy(ext, ".exe");
  467. else
  468. #endif
  469. if (output_type == TCC_OUTPUT_OBJ && !reloc_output && *ext)
  470. strcpy(ext, ".o");
  471. else
  472. pstrcpy(objfilename, sizeof(objfilename), "a.out");
  473. outfile = objfilename;
  474. }
  475. }
  476. if (do_bench) {
  477. start_time = getclock_us();
  478. }
  479. tcc_set_output_type(s, output_type);
  480. /* compile or add each files or library */
  481. for(i = 0; i < nb_files && ret == 0; i++) {
  482. const char *filename;
  483. filename = files[i];
  484. if (filename[0] == '-' && filename[1]) {
  485. if (tcc_add_library(s, filename + 2) < 0) {
  486. error_noabort("cannot find %s", filename);
  487. ret = 1;
  488. }
  489. } else {
  490. if (1 == s->verbose)
  491. printf("-> %s\n", filename);
  492. if (tcc_add_file(s, filename) < 0)
  493. ret = 1;
  494. }
  495. }
  496. /* free all files */
  497. tcc_free(files);
  498. if (ret)
  499. goto the_end;
  500. if (do_bench)
  501. tcc_print_stats(s, getclock_us() - start_time);
  502. if (s->output_type == TCC_OUTPUT_PREPROCESS) {
  503. if (outfile)
  504. fclose(s->outfile);
  505. } else if (s->output_type == TCC_OUTPUT_MEMORY) {
  506. ret = tcc_run(s, argc - optind, argv + optind);
  507. } else
  508. ret = tcc_output_file(s, outfile) ? 1 : 0;
  509. the_end:
  510. /* XXX: cannot do it with bound checking because of the malloc hooks */
  511. if (!s->do_bounds_check)
  512. tcc_delete(s);
  513. #ifdef MEM_DEBUG
  514. if (do_bench) {
  515. printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size);
  516. }
  517. #endif
  518. return ret;
  519. }