From 30d71042e4399b67e3834da5a2786739a181daba Mon Sep 17 00:00:00 2001 From: k1w1 Date: Sat, 5 Dec 2009 09:43:00 -0800 Subject: [PATCH] Split out argument parsing code so it can be reused by the tcc library. Added function to specify options in the TCCState structure. --- libtcc.c | 8 +- libtcc.h | 5 +- tcc.c | 785 ++++++++++++------------------------------------- tcc.h | 5 + tcc.c => tccargs.c | 272 +++-------------- tccutil.h => tccargs.h | 22 +- tccutil.c | 14 + tccutil.h | 1 + 8 files changed, 277 insertions(+), 835 deletions(-) rewrite tcc.c (72%) mode change 100644 => 100755 copy tcc.c => tccargs.c (63%) mode change 100644 => 100755 copy tccutil.h => tccargs.h (63%) diff --git a/libtcc.c b/libtcc.c index e488d671..00a0b59c 100755 --- a/libtcc.c +++ b/libtcc.c @@ -1497,9 +1497,13 @@ void tcc_print_stats(TCCState *s, int64_t total_time) total_bytes / tt / 1000000.0); } -void tcc_set_nostdlib(TCCState *s, int nostdlib) + +void tcc_set_options(TCCState *s, int argc, char **argv) { - s->nostdlib = nostdlib; + TCCConfig config; + init_tcc_config(&config); + parse_args(&config, s, argc, argv); + /* The config structure is ignored. It has no effect in library mode. */ } diff --git a/libtcc.h b/libtcc.h index b7b7f949..1eb781f9 100755 --- a/libtcc.h +++ b/libtcc.h @@ -101,8 +101,9 @@ LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); /* set CONFIG_TCCDIR at runtime */ LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); -/* set whether to include the standard library. */ -LIBTCCAPI void tcc_set_nostdlib(TCCState *s, int nostdlib); +/* Specify a set of options for the TCCState. Note that argv[0] is the + first argument and not the program name. */ +LIBTCCAPI void tcc_set_options(TCCState *s, int argc, char **argv); #ifdef __cplusplus } diff --git a/tcc.c b/tcc.c old mode 100644 new mode 100755 dissimilarity index 72% index ce5e09f9..d6e25838 --- a/tcc.c +++ b/tcc.c @@ -1,597 +1,188 @@ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * 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. - * - * 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. - * - * 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 - */ - -#ifdef TCC_USE_LIBTCC -#include "tcc.h" -#else -#include "libtcc.c" -#endif - -void help(void) -{ - printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n" - "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" - " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n" - " [-static] [infile1 infile2...] [-run infile args...]\n" - "\n" - "General options:\n" - " -v display current version, increase verbosity\n" - " -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" - " -w disable all warnings\n" - "Preprocessor options:\n" - " -E preprocess only\n" - " -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" - " -shared generate a shared library\n" - " -soname set name for shared library to be used at runtime\n" - " -static static linking\n" - " -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 - ); -} - -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; - -#define TCC_OPTION_HAS_ARG 0x0001 -#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ - -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_Wl, - TCC_OPTION_W, - TCC_OPTION_O, - TCC_OPTION_m, - TCC_OPTION_f, - TCC_OPTION_nostdinc, - TCC_OPTION_nostdlib, - TCC_OPTION_print_search_dirs, - TCC_OPTION_rdynamic, - TCC_OPTION_run, - TCC_OPTION_v, - TCC_OPTION_w, - TCC_OPTION_pipe, - TCC_OPTION_E, - TCC_OPTION_x, -}; - -static const TCCOption tcc_options[] = { - { "h", 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 }, - { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, -#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 }, - { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "rdynamic", TCC_OPTION_rdynamic, 0 }, - { "r", TCC_OPTION_r, 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 }, - { "nostdlib", TCC_OPTION_nostdlib, 0 }, - { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, - { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "w", TCC_OPTION_w, 0 }, - { "pipe", TCC_OPTION_pipe, 0}, - { "E", TCC_OPTION_E, 0}, - { "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 -} - -static int strstart(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - p = str; - q = val; - while (*q != '\0') { - if (*p != *q) - return 0; - p++; - q++; - } - if (ptr) - *ptr = p; - return 1; -} - -/* convert 'str' into an array of space separated strings */ -static int expand_args(char ***pargv, const char *str) -{ - 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; -} - -int parse_args(TCCState *s, int argc, char **argv) -{ - int optind; - const TCCOption *popt; - const char *optarg, *p1, *r1; - char *r; - - optind = 0; - 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') - return 0; - optarg = NULL; - } - - switch(popt->index) { - case TCC_OPTION_HELP: - 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) */ - tcc_set_lib_path(s, optarg); - break; - case TCC_OPTION_l: - dynarray_add((void ***)&files, &nb_files, r); - nb_libraries++; - break; - case TCC_OPTION_bench: - do_bench = 1; - break; -#ifdef CONFIG_TCC_BACKTRACE - case TCC_OPTION_bt: - 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; - 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: - do { - if (0 == s->verbose++) - 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; - case TCC_OPTION_w: - s->warn_none = 1; - break; - case TCC_OPTION_rdynamic: - s->rdynamic = 1; - break; - case TCC_OPTION_Wl: - { - const char *p; - if (strstart(optarg, "-Ttext,", &p)) { - s->text_addr = strtoul(p, NULL, 16); - s->has_text_addr = 1; - } else if (strstart(optarg, "--section-alignment,", &p)) { - s->section_align = strtoul(p, NULL, 16); - } else if (strstart(optarg, "--image-base,", &p)) { - s->text_addr = strtoul(p, NULL, 16); - s->has_text_addr = 1; -#ifdef TCC_TARGET_PE - } else if (strstart(optarg, "--file-alignment,", &p)) { - s->pe_file_align = strtoul(p, NULL, 16); - } else if (strstart(optarg, "--subsystem,", &p)) { -#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) - if (!strcmp(p, "native")) - s->pe_subsystem = 1; - else if (!strcmp(p, "console")) - s->pe_subsystem = 3; - else if (!strcmp(p, "gui")) - s->pe_subsystem = 2; - else if (!strcmp(p, "posix")) - s->pe_subsystem = 7; - else if (!strcmp(p, "efiapp")) - s->pe_subsystem = 10; - else if (!strcmp(p, "efiboot")) - s->pe_subsystem = 11; - else if (!strcmp(p, "efiruntime")) - s->pe_subsystem = 12; - else if (!strcmp(p, "efirom")) - s->pe_subsystem = 13; -#elif defined(TCC_TARGET_ARM) - if (!strcmp(p, "wince")) - s->pe_subsystem = 9; -#endif - else { - error("invalid subsystem '%s'", p); - } -#endif - } else if (strstart(optarg, "--oformat,", &p)) { -#if defined(TCC_TARGET_PE) - if (strstart(p, "pe-", NULL)) { -#else -#if defined(TCC_TARGET_X86_64) - if (strstart(p, "elf64-", NULL)) { -#else - if (strstart(p, "elf32-", NULL)) { -#endif -#endif - s->output_format = TCC_OUTPUT_FORMAT_ELF; - } else if (!strcmp(p, "binary")) { - s->output_format = TCC_OUTPUT_FORMAT_BINARY; - } else -#ifdef TCC_TARGET_COFF - if (!strcmp(p, "coff")) { - s->output_format = TCC_OUTPUT_FORMAT_COFF; - } else -#endif - { - error("target %s not found", p); - } - } else { - error("unsupported linker option '%s'", optarg); - } - } - break; - case TCC_OPTION_E: - output_type = TCC_OUTPUT_PREPROCESS; - break; - case TCC_OPTION_x: - break; - default: - if (s->warn_unsupported) { - unsupported_option: - warning("unsupported option '%s'", r); - } - break; - } - } - } - return optind + 1; -} - -int main(int argc, char **argv) -{ - int i; - TCCState *s; - int nb_objfiles, ret, optind; - char objfilename[1024]; - int64_t start_time = 0; - - s = tcc_new(); - - 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; - - 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; - } - if (optind == 0 || nb_files == 0) { - if (optind && s->verbose) - 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"); - } - - - if (output_type == TCC_OUTPUT_PREPROCESS) { - if (!outfile) { - s->outfile = stdout; - } else { - s->outfile = fopen(outfile, "w"); - if (!s->outfile) - error("could not open '%s", outfile); - } - } else if (output_type != TCC_OUTPUT_MEMORY) { - if (!outfile) { - /* compute default outfile name */ - char *ext; - const char *name = - strcmp(files[0], "-") == 0 ? "a" : tcc_basename(files[0]); - pstrcpy(objfilename, sizeof(objfilename), name); - ext = tcc_fileextension(objfilename); -#ifdef TCC_TARGET_PE - if (output_type == TCC_OUTPUT_DLL) - strcpy(ext, ".dll"); - else - if (output_type == TCC_OUTPUT_EXE) - strcpy(ext, ".exe"); - else -#endif - if (output_type == TCC_OUTPUT_OBJ && !reloc_output && *ext) - strcpy(ext, ".o"); - else - pstrcpy(objfilename, sizeof(objfilename), "a.out"); - outfile = objfilename; - } - } - - if (do_bench) { - start_time = getclock_us(); - } - - tcc_set_output_type(s, output_type); - - /* 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]) { - if (tcc_add_library(s, filename + 2) < 0) { - error_noabort("cannot find %s", filename); - ret = 1; - } - } else { - if (1 == s->verbose) - printf("-> %s\n", filename); - if (tcc_add_file(s, filename) < 0) - ret = 1; - } - } - - /* free all files */ - tcc_free(files); - - if (0 == ret) { - if (do_bench) - tcc_print_stats(s, getclock_us() - start_time); - - if (s->output_type == TCC_OUTPUT_PREPROCESS) { - if (outfile) - fclose(s->outfile); - } else if (s->output_type == TCC_OUTPUT_MEMORY) - ret = tcc_run(s, argc - optind, argv + optind); - else - ret = tcc_output_file(s, outfile) ? 1 : 0; - } - - 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; -} +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * 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. + * + * 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. + * + * 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 + */ + +#include "tcc.h" + +void help(void) +{ + printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n" + "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" + " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n" + " [-static] [infile1 infile2...] [-run infile args...]\n" + "\n" + "General options:\n" + " -v display current version, increase verbosity\n" + " -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" + " -w disable all warnings\n" + "Preprocessor options:\n" + " -E preprocess only\n" + " -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" + " -shared generate a shared library\n" + " -soname set name for shared library to be used at runtime\n" + " -static static linking\n" + " -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 + ); +} + +int main(int argc, char **argv) +{ + TCCConfig config; + int i; + TCCState *s; + int nb_objfiles, ret, optind; + char objfilename[1024]; + int64_t start_time = 0; + + s = tcc_new(); + init_tcc_config(&config); + + ret = 0; + + optind = parse_args(&config, s, argc - 1, argv + 1); + if (config.print_search_dirs) { + /* enough for Linux kernel */ + printf("install: %s/\n", s->tcc_lib_path); + return 0; + } + if (optind == 0 || config.nb_files == 0) { + if (optind && s->verbose) + return 0; + help(); + return 1; + } + + nb_objfiles = config.nb_files - config.nb_libraries; + + /* if outfile provided without other options, we output an + executable */ + if (config.outfile && config.output_type == TCC_OUTPUT_MEMORY) + config.output_type = TCC_OUTPUT_EXE; + + /* check -c consistency : only single file handled. XXX: checks file type */ + if (config.output_type == TCC_OUTPUT_OBJ && !config.reloc_output) { + /* accepts only a single input file */ + if (nb_objfiles != 1) + error("cannot specify multiple files with -c"); + if (config.nb_libraries != 0) + error("cannot specify libraries with -c"); + } + + + if (config.output_type == TCC_OUTPUT_PREPROCESS) { + if (!config.outfile) { + s->outfile = stdout; + } else { + s->outfile = fopen(config.outfile, "w"); + if (!s->outfile) + error("could not open '%s", config.outfile); + } + } else if (config.output_type != TCC_OUTPUT_MEMORY) { + if (!config.outfile) { + /* compute default outfile name */ + char *ext; + const char *name = + strcmp(config.files[0], "-") == 0 ? "a" : tcc_basename(config.files[0]); + pstrcpy(objfilename, sizeof(objfilename), name); + ext = tcc_fileextension(objfilename); +#ifdef TCC_TARGET_PE + if (config.output_type == TCC_OUTPUT_DLL) + strcpy(ext, ".dll"); + else + if (config.output_type == TCC_OUTPUT_EXE) + strcpy(ext, ".exe"); + else +#endif + if (config.output_type == TCC_OUTPUT_OBJ && !config.reloc_output && *ext) + strcpy(ext, ".o"); + else + pstrcpy(objfilename, sizeof(objfilename), "a.out"); + config.outfile = objfilename; + } + } + + if (config.do_bench) { + start_time = getclock_us(); + } + + tcc_set_output_type(s, config.output_type); + + /* compile or add each files or library */ + for(i = 0; i < config.nb_files && ret == 0; i++) { + const char *filename; + + filename = config.files[i]; + if (filename[0] == '-' && filename[1]) { + if (tcc_add_library(s, filename + 2) < 0) { + error_noabort("cannot find %s", filename); + ret = 1; + } + } else { + if (1 == s->verbose) + printf("-> %s\n", filename); + if (tcc_add_file(s, filename) < 0) + ret = 1; + } + } + + /* free all files */ + tcc_free(config.files); + + if (0 == ret) { + if (config.do_bench) + tcc_print_stats(s, getclock_us() - start_time); + + if (s->output_type == TCC_OUTPUT_PREPROCESS) { + if (config.outfile) + fclose(s->outfile); + } else if (s->output_type == TCC_OUTPUT_MEMORY) + ret = tcc_run(s, argc - optind, argv + optind); + else + ret = tcc_output_file(s, config.outfile) ? 1 : 0; + } + + 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; +} diff --git a/tcc.h b/tcc.h index 7de4725f..1408a6d0 100755 --- a/tcc.h +++ b/tcc.h @@ -55,6 +55,10 @@ #ifdef _WIN64 #define uplong unsigned long long #endif +#ifdef __BORLANDC__ +#define _timeb timeb +#define _ftime ftime +#endif #endif #ifndef _WIN32 @@ -1042,6 +1046,7 @@ extern struct TCCState *tcc_state; #include "tccld.h" #include "tccsym.h" #include "tccutil.h" +#include "tccargs.h" #ifdef TCC_TARGET_PE #include "tccpe.h" diff --git a/tcc.c b/tccargs.c old mode 100644 new mode 100755 similarity index 63% copy from tcc.c copy to tccargs.c index ce5e09f9..914a2afc --- a/tcc.c +++ b/tccargs.c @@ -1,5 +1,5 @@ -/* - * TCC - Tiny C Compiler +/* + * Command line argument parsing for TCC * * Copyright (c) 2001-2004 Fabrice Bellard * @@ -16,65 +16,10 @@ * 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 - */ - -#ifdef TCC_USE_LIBTCC -#include "tcc.h" -#else -#include "libtcc.c" -#endif - -void help(void) -{ - printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n" - "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" - " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n" - " [-static] [infile1 infile2...] [-run infile args...]\n" - "\n" - "General options:\n" - " -v display current version, increase verbosity\n" - " -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" - " -w disable all warnings\n" - "Preprocessor options:\n" - " -E preprocess only\n" - " -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" - " -shared generate a shared library\n" - " -soname set name for shared library to be used at runtime\n" - " -static static linking\n" - " -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 - ); -} - -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; - -#define TCC_OPTION_HAS_ARG 0x0001 + */ +#include "tcc.h" + +#define TCC_OPTION_HAS_ARG 0x0001 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ typedef struct TCCOption { @@ -155,22 +100,9 @@ static const TCCOption tcc_options[] = { { "E", TCC_OPTION_E, 0}, { "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 -} - -static int strstart(const char *str, const char *val, const char **ptr) +}; + +static int strstart(const char *str, const char *val, const char **ptr) { const char *p, *q; p = str; @@ -213,7 +145,21 @@ static int expand_args(char ***pargv, const char *str) return argc; } -int parse_args(TCCState *s, int argc, char **argv) + +void init_tcc_config(TCCConfig *config) +{ + config->output_type = TCC_OUTPUT_EXE; + config->outfile = NULL; + config->multiple_files = 1; + config->files = NULL; + config->nb_files = 0; + config->nb_libraries = 0; + config->reloc_output = 0; + config->print_search_dirs = 0; + config->do_bench = 0; +} + +int parse_args(TCCConfig *config, TCCState *s, int argc, char **argv) { int optind; const TCCOption *popt; @@ -226,8 +172,8 @@ int parse_args(TCCState *s, int argc, char **argv) r = argv[optind++]; if (r[0] != '-' || r[1] == '\0') { /* add a new file */ - dynarray_add((void ***)&files, &nb_files, r); - if (!multiple_files) { + dynarray_add((void ***)&config->files, &config->nb_files, r); + if (!config->multiple_files) { optind--; /* argv[0] will be this file */ break; @@ -296,15 +242,15 @@ int parse_args(TCCState *s, int argc, char **argv) tcc_set_lib_path(s, optarg); break; case TCC_OPTION_l: - dynarray_add((void ***)&files, &nb_files, r); - nb_libraries++; + dynarray_add((void ***)&config->files, &config->nb_files, r); + config->nb_libraries++; break; case TCC_OPTION_bench: - do_bench = 1; + config->do_bench = 1; break; #ifdef CONFIG_TCC_BACKTRACE case TCC_OPTION_bt: - num_callers = atoi(optarg); + config->num_callers = atoi(optarg); break; #endif #ifdef CONFIG_TCC_BCHECK @@ -317,26 +263,26 @@ int parse_args(TCCState *s, int argc, char **argv) s->do_debug = 1; break; case TCC_OPTION_c: - multiple_files = 1; - output_type = TCC_OUTPUT_OBJ; + config->multiple_files = 1; + config->output_type = TCC_OUTPUT_OBJ; break; case TCC_OPTION_static: s->static_link = 1; break; case TCC_OPTION_shared: - output_type = TCC_OUTPUT_DLL; + config->output_type = TCC_OUTPUT_DLL; break; case TCC_OPTION_soname: s->soname = optarg; break; case TCC_OPTION_o: - multiple_files = 1; - outfile = optarg; + config->multiple_files = 1; + config->outfile = optarg; break; case TCC_OPTION_r: /* generate a .o merging several output files */ - reloc_output = 1; - output_type = TCC_OUTPUT_OBJ; + config->reloc_output = 1; + config->output_type = TCC_OUTPUT_OBJ; break; case TCC_OPTION_nostdinc: s->nostdinc = 1; @@ -345,7 +291,7 @@ int parse_args(TCCState *s, int argc, char **argv) s->nostdlib = 1; break; case TCC_OPTION_print_search_dirs: - print_search_dirs = 1; + config->print_search_dirs = 1; break; case TCC_OPTION_run: { @@ -353,10 +299,10 @@ int parse_args(TCCState *s, int argc, char **argv) char **argv1; argc1 = expand_args(&argv1, optarg); if (argc1 > 0) { - parse_args(s, argc1, argv1); + parse_args(config, s, argc1, argv1); } - multiple_files = 0; - output_type = TCC_OUTPUT_MEMORY; + config->multiple_files = 0; + config->output_type = TCC_OUTPUT_MEMORY; } break; case TCC_OPTION_v: @@ -448,7 +394,7 @@ int parse_args(TCCState *s, int argc, char **argv) } break; case TCC_OPTION_E: - output_type = TCC_OUTPUT_PREPROCESS; + config->output_type = TCC_OUTPUT_PREPROCESS; break; case TCC_OPTION_x: break; @@ -462,136 +408,4 @@ int parse_args(TCCState *s, int argc, char **argv) } } return optind + 1; -} - -int main(int argc, char **argv) -{ - int i; - TCCState *s; - int nb_objfiles, ret, optind; - char objfilename[1024]; - int64_t start_time = 0; - - s = tcc_new(); - - 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; - - 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; - } - if (optind == 0 || nb_files == 0) { - if (optind && s->verbose) - 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"); - } - - - if (output_type == TCC_OUTPUT_PREPROCESS) { - if (!outfile) { - s->outfile = stdout; - } else { - s->outfile = fopen(outfile, "w"); - if (!s->outfile) - error("could not open '%s", outfile); - } - } else if (output_type != TCC_OUTPUT_MEMORY) { - if (!outfile) { - /* compute default outfile name */ - char *ext; - const char *name = - strcmp(files[0], "-") == 0 ? "a" : tcc_basename(files[0]); - pstrcpy(objfilename, sizeof(objfilename), name); - ext = tcc_fileextension(objfilename); -#ifdef TCC_TARGET_PE - if (output_type == TCC_OUTPUT_DLL) - strcpy(ext, ".dll"); - else - if (output_type == TCC_OUTPUT_EXE) - strcpy(ext, ".exe"); - else -#endif - if (output_type == TCC_OUTPUT_OBJ && !reloc_output && *ext) - strcpy(ext, ".o"); - else - pstrcpy(objfilename, sizeof(objfilename), "a.out"); - outfile = objfilename; - } - } - - if (do_bench) { - start_time = getclock_us(); - } - - tcc_set_output_type(s, output_type); - - /* 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]) { - if (tcc_add_library(s, filename + 2) < 0) { - error_noabort("cannot find %s", filename); - ret = 1; - } - } else { - if (1 == s->verbose) - printf("-> %s\n", filename); - if (tcc_add_file(s, filename) < 0) - ret = 1; - } - } - - /* free all files */ - tcc_free(files); - - if (0 == ret) { - if (do_bench) - tcc_print_stats(s, getclock_us() - start_time); - - if (s->output_type == TCC_OUTPUT_PREPROCESS) { - if (outfile) - fclose(s->outfile); - } else if (s->output_type == TCC_OUTPUT_MEMORY) - ret = tcc_run(s, argc - optind, argv + optind); - else - ret = tcc_output_file(s, outfile) ? 1 : 0; - } - - 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; -} +} diff --git a/tccutil.h b/tccargs.h similarity index 63% copy from tccutil.h copy to tccargs.h index 18ea24a0..530f0a1d 100755 --- a/tccutil.h +++ b/tccargs.h @@ -1,5 +1,5 @@ /* - * Utility functions for TCC + * Command line argument parsing for TCC * * Copyright (c) 2001-2004 Fabrice Bellard * @@ -17,9 +17,21 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __TCCUTIL_H__ -#define __TCCUTIL_H__ +#ifndef __TCCARGS_H__ +#define __TCCARGS_H__ -void set_pages_executable(void *ptr, unsigned long length); +typedef struct { + char **files; + int nb_files, nb_libraries; + int multiple_files; + int print_search_dirs; + int output_type; + int reloc_output; + const char *outfile; + int do_bench; +} TCCConfig; -#endif /* __TCCUTIL_H__ */ +void init_tcc_config(TCCConfig *config); +int parse_args(TCCConfig *config, TCCState *s, int argc, char **argv); + +#endif /* __TCCARGS_H__ */ diff --git a/tccutil.c b/tccutil.c index 6b426ca0..85dd7695 100755 --- a/tccutil.c +++ b/tccutil.c @@ -184,3 +184,17 @@ void dynarray_reset(void *pp, int *n) tcc_free(*(void**)pp); *(void**)pp = NULL; } + +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 +} + diff --git a/tccutil.h b/tccutil.h index 18ea24a0..da11348f 100755 --- a/tccutil.h +++ b/tccutil.h @@ -21,5 +21,6 @@ #define __TCCUTIL_H__ void set_pages_executable(void *ptr, unsigned long length); +int64_t getclock_us(void); #endif /* __TCCUTIL_H__ */ -- 2.11.4.GIT