2 * Command line argument parsing for TCC
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
22 #define TCC_OPTION_HAS_ARG 0x0001
23 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
25 typedef struct TCCOption
{
56 TCC_OPTION_print_search_dirs
,
66 static const TCCOption tcc_options
[] = {
67 { "h", TCC_OPTION_HELP
, 0 },
68 { "?", TCC_OPTION_HELP
, 0 },
69 { "I", TCC_OPTION_I
, TCC_OPTION_HAS_ARG
},
70 { "D", TCC_OPTION_D
, TCC_OPTION_HAS_ARG
},
71 { "U", TCC_OPTION_U
, TCC_OPTION_HAS_ARG
},
72 { "L", TCC_OPTION_L
, TCC_OPTION_HAS_ARG
},
73 { "B", TCC_OPTION_B
, TCC_OPTION_HAS_ARG
},
74 { "l", TCC_OPTION_l
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
75 { "bench", TCC_OPTION_bench
, 0 },
76 { "bt", TCC_OPTION_bt
, TCC_OPTION_HAS_ARG
},
77 #ifdef CONFIG_TCC_BCHECK
78 { "b", TCC_OPTION_b
, 0 },
80 { "g", TCC_OPTION_g
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
81 { "c", TCC_OPTION_c
, 0 },
82 { "static", TCC_OPTION_static
, 0 },
83 { "shared", TCC_OPTION_shared
, 0 },
84 { "soname", TCC_OPTION_soname
, TCC_OPTION_HAS_ARG
},
85 { "o", TCC_OPTION_o
, TCC_OPTION_HAS_ARG
},
86 { "run", TCC_OPTION_run
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
87 { "rdynamic", TCC_OPTION_rdynamic
, 0 },
88 { "r", TCC_OPTION_r
, 0 },
89 { "Wl,", TCC_OPTION_Wl
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
90 { "W", TCC_OPTION_W
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
91 { "O", TCC_OPTION_O
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
92 { "m", TCC_OPTION_m
, TCC_OPTION_HAS_ARG
},
93 { "f", TCC_OPTION_f
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
94 { "nostdinc", TCC_OPTION_nostdinc
, 0 },
95 { "nostdlib", TCC_OPTION_nostdlib
, 0 },
96 { "print-search-dirs", TCC_OPTION_print_search_dirs
, 0 },
97 { "v", TCC_OPTION_v
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
98 { "w", TCC_OPTION_w
, 0 },
99 { "pipe", TCC_OPTION_pipe
, 0},
100 { "E", TCC_OPTION_E
, 0},
101 { "x", TCC_OPTION_x
, TCC_OPTION_HAS_ARG
},
105 static int strstart(const char *str
, const char *val
, const char **ptr
)
121 /* convert 'str' into an array of space separated strings */
122 static int expand_args(char ***pargv
, const char *str
)
131 while (is_space(*str
))
136 while (*str
!= '\0' && !is_space(*str
))
139 arg
= tcc_malloc(len
+ 1);
140 memcpy(arg
, s1
, len
);
142 dynarray_add((void ***)&argv
, &argc
, arg
);
149 void init_tcc_config(TCCConfig
*config
)
151 config
->output_type
= TCC_OUTPUT_EXE
;
152 config
->outfile
= NULL
;
153 config
->multiple_files
= 1;
154 config
->files
= NULL
;
155 config
->nb_files
= 0;
156 config
->nb_libraries
= 0;
157 config
->reloc_output
= 0;
158 config
->print_search_dirs
= 0;
159 config
->do_bench
= 0;
162 int parse_args(TCCConfig
*config
, TCCState
*s
, int argc
, char **argv
)
165 const TCCOption
*popt
;
166 const char *optarg
, *p1
, *r1
;
170 while (optind
< argc
) {
173 if (r
[0] != '-' || r
[1] == '\0') {
175 dynarray_add((void ***)&config
->files
, &config
->nb_files
, r
);
176 if (!config
->multiple_files
) {
178 /* argv[0] will be this file */
182 /* find option in table (match only the first chars */
187 error("invalid option -- '%s'", r
);
200 if (popt
->flags
& TCC_OPTION_HAS_ARG
) {
201 if (*r1
!= '\0' || (popt
->flags
& TCC_OPTION_NOSEP
)) {
205 error("argument to '%s' is missing", r
);
206 optarg
= argv
[optind
++];
214 switch(popt
->index
) {
215 case TCC_OPTION_HELP
:
219 if (tcc_add_include_path(s
, optarg
) < 0)
220 error("too many include paths");
225 sym
= (char *)optarg
;
226 value
= strchr(sym
, '=');
231 tcc_define_symbol(s
, sym
, value
);
235 tcc_undefine_symbol(s
, optarg
);
238 tcc_add_library_path(s
, optarg
);
241 /* set tcc utilities path (mainly for tcc development) */
242 tcc_set_lib_path(s
, optarg
);
245 dynarray_add((void ***)&config
->files
, &config
->nb_files
, r
);
246 config
->nb_libraries
++;
248 case TCC_OPTION_bench
:
249 config
->do_bench
= 1;
251 #ifdef CONFIG_TCC_BACKTRACE
253 num_callers
= atoi(optarg
);
256 #ifdef CONFIG_TCC_BCHECK
258 s
->do_bounds_check
= 1;
266 config
->multiple_files
= 1;
267 config
->output_type
= TCC_OUTPUT_OBJ
;
269 case TCC_OPTION_static
:
272 case TCC_OPTION_shared
:
273 config
->output_type
= TCC_OUTPUT_DLL
;
275 case TCC_OPTION_soname
:
279 config
->multiple_files
= 1;
280 config
->outfile
= optarg
;
283 /* generate a .o merging several output files */
284 config
->reloc_output
= 1;
285 config
->output_type
= TCC_OUTPUT_OBJ
;
287 case TCC_OPTION_nostdinc
:
290 case TCC_OPTION_nostdlib
:
293 case TCC_OPTION_print_search_dirs
:
294 config
->print_search_dirs
= 1;
300 argc1
= expand_args(&argv1
, optarg
);
302 parse_args(config
, s
, argc1
, argv1
);
304 config
->multiple_files
= 0;
305 config
->output_type
= TCC_OUTPUT_MEMORY
;
310 if (0 == s
->verbose
++)
311 printf("tcc version %s\n", TCC_VERSION
);
312 } while (*optarg
++ == 'v');
315 if (tcc_set_flag(s
, optarg
, 1) < 0 && s
->warn_unsupported
)
316 goto unsupported_option
;
319 if (tcc_set_warning(s
, optarg
, 1) < 0 &&
321 goto unsupported_option
;
326 case TCC_OPTION_rdynamic
:
332 if (strstart(optarg
, "-Ttext,", &p
)) {
333 s
->text_addr
= strtoul(p
, NULL
, 16);
334 s
->has_text_addr
= 1;
335 } else if (strstart(optarg
, "--section-alignment,", &p
)) {
336 s
->section_align
= strtoul(p
, NULL
, 16);
337 } else if (strstart(optarg
, "--image-base,", &p
)) {
338 s
->text_addr
= strtoul(p
, NULL
, 16);
339 s
->has_text_addr
= 1;
341 } else if (strstart(optarg
, "--file-alignment,", &p
)) {
342 s
->pe_file_align
= strtoul(p
, NULL
, 16);
343 } else if (strstart(optarg
, "--subsystem,", &p
)) {
344 #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
345 if (!strcmp(p
, "native"))
347 else if (!strcmp(p
, "console"))
349 else if (!strcmp(p
, "gui"))
351 else if (!strcmp(p
, "posix"))
353 else if (!strcmp(p
, "efiapp"))
354 s
->pe_subsystem
= 10;
355 else if (!strcmp(p
, "efiboot"))
356 s
->pe_subsystem
= 11;
357 else if (!strcmp(p
, "efiruntime"))
358 s
->pe_subsystem
= 12;
359 else if (!strcmp(p
, "efirom"))
360 s
->pe_subsystem
= 13;
361 #elif defined(TCC_TARGET_ARM)
362 if (!strcmp(p
, "wince"))
366 error("invalid subsystem '%s'", p
);
369 } else if (strstart(optarg
, "--oformat,", &p
)) {
370 #if defined(TCC_TARGET_PE)
371 if (strstart(p
, "pe-", NULL
)) {
373 #if defined(TCC_TARGET_X86_64)
374 if (strstart(p
, "elf64-", NULL
)) {
376 if (strstart(p
, "elf32-", NULL
)) {
379 s
->output_format
= TCC_OUTPUT_FORMAT_ELF
;
380 } else if (!strcmp(p
, "binary")) {
381 s
->output_format
= TCC_OUTPUT_FORMAT_BINARY
;
383 #ifdef TCC_TARGET_COFF
384 if (!strcmp(p
, "coff")) {
385 s
->output_format
= TCC_OUTPUT_FORMAT_COFF
;
389 error("target %s not found", p
);
392 error("unsupported linker option '%s'", optarg
);
397 config
->output_type
= TCC_OUTPUT_PREPROCESS
;
402 if (s
->warn_unsupported
) {
404 warning("unsupported option '%s'", r
);