CBMC
gcc_cmdline.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: A special command line object for the gcc-like options
4 
5 Author: CM Wintersteiger, 2006
6 
7 \*******************************************************************/
8 
11 
12 #include "gcc_cmdline.h"
13 
14 #include <util/invariant.h>
15 #include <util/prefix.h>
16 
17 #include <cstring>
18 #include <fstream> // IWYU pragma: keep
19 #include <iostream>
20 #include <sstream> // IWYU pragma: keep
21 
22 // clang-format off
23 // non-gcc options
25 {
26  "--verbosity",
27  "--function",
28  "--native-compiler",
29  "--native-linker",
30  "--print-rejected-preprocessed-source",
31  "--mangle-suffix",
32  nullptr
33 };
34 
35 // non-gcc options
37 {
38  "--show-symbol-table",
39  "--show-function-table",
40  "--ppc-macos",
41  "--i386-linux",
42  "--i386-win32",
43  "--i386-macos",
44  "--winx64",
45  "--string-abstraction",
46  "--no-library",
47  "--16",
48  "--32",
49  "--64",
50  "--little-endian",
51  "--big-endian",
52  "--partial-inlining",
53  "--validate-goto-model",
54  "-?",
55  "--export-file-local-symbols",
56  // This is deprecated. Currently prints out a deprecation warning.
57  "--export-function-local-symbols",
58  nullptr
59 };
60 
61 // separated or concatenated
63 {
64  "-o",
65  "-x",
66  "-B",
67  "-iquote",
68  "-idirafter",
69  "-include",
70  "-I",
71  "-V",
72  "-D",
73  "-L",
74  "-l",
75  "-MT",
76  "-MQ",
77  "-MF",
78  "-U",
79  "-u", // goes to linker
80  "-T", // goes to linker
81  nullptr
82 };
83 
85 {
86  "-aux-info",
87  "-arch", // Apple only
88  "--param", // Apple only
89  "-imacros",
90  "-iprefix",
91  "-iwithprefix",
92  "-iwithprefixbefore",
93  "-isystem",
94  "-isysroot",
95  "-imultilib",
96  "-imultiarch",
97  "-mcpu",
98  "-mtune",
99  "-march",
100  "-Xpreprocessor",
101  "-Xassembler",
102  "-Xlinker",
103  "-b",
104  "-std",
105  "--std",
106  "-print-file-name",
107  "-print-prog-name",
108  "-specs",
109  "--sysroot",
110  "--include", // undocumented
111  "-current_version", // on the Mac
112  "-compatibility_version", // on the Mac
113  "-target",
114  "--target",
115  "-z",
116  nullptr
117 };
118 
120 {
121  "-d",
122  "-g",
123  "-A",
124  nullptr
125 };
126 
128 {
129  "--help",
130  "-h",
131  "-r", // for ld mimicking
132  "-dylib", // for ld mimicking on MacOS
133  "-c",
134  "-S",
135  "-E",
136  "-combine",
137  "-pipe",
138  "-pass-exit-codes",
139  "-v",
140  "-###",
141  "-help",
142  "-target-help",
143  "--version",
144  "-ansi",
145  "-trigraphs",
146  "-no-integrated-cpp",
147  "-traditional",
148  "-traditional-cpp",
149  "-nostdinc++",
150  "-gen-decls",
151  "-pedantic",
152  "-pedantic-errors",
153  "-w",
154  "-dumpspecs",
155  "-dumpmachine",
156  "-dumpversion",
157  "-g",
158  "-gcoff",
159  "-gdwarf-2",
160  "-ggdb",
161  "-gstabs",
162  "-gstabs+",
163  "-gvms",
164  "-gxcoff",
165  "-gxcoff+",
166  "-p",
167  "-pg",
168  "-print-libgcc-file-name",
169  "-print-multi-directory",
170  "-print-multi-lib",
171  "-print-search-dirs",
172  "-print-sysroot",
173  "-print-sysroot-headers-suffix",
174  "-Q",
175  "-Qn",
176  "-Qy",
177  "-pthread",
178  "-save-temps",
179  "-time",
180  "-O",
181  "-O0",
182  "-O1",
183  "-O2",
184  "-O3",
185  "-O6",
186  "-Os",
187  "-Oz", // Apple only
188  "-C",
189  "-E",
190  "-H",
191  "-M",
192  "-MM",
193  "-MG",
194  "-MP",
195  "-MD",
196  "-MMD",
197  "-mno-unaligned-access",
198  "-mthumb",
199  "-mthumb-interwork",
200  "-nostdinc",
201  "-P",
202  "-remap",
203  "-undef",
204  "-nostdinc",
205  "-nostartfiles",
206  "-nodefaultlibs",
207  "-nostdlib",
208  "-pie",
209  "-rdynamic",
210  "-s",
211  "-static",
212  "-static-libgcc",
213  "--static",
214  "-shared",
215  "--shared",
216  "-shared-libgcc",
217  "-symbolic",
218  "-EB",
219  "-EL",
220  "-fast", // Apple only
221  "-coverage",
222  nullptr
223 };
224 // clang-format on
225 
229 bool gcc_cmdlinet::parse(int argc, const char **argv)
230 {
231  PRECONDITION(argc > 0);
232  add_arg(argv[0]);
233 
234  argst current_args;
235  current_args.reserve(argc - 1);
236 
237  for(int i=1; i<argc; i++)
238  current_args.push_back(argv[i]);
239 
240  bool result = parse_arguments(current_args, false);
241 
242  parse_specs();
243 
244  return result;
245 }
246 
248  const argst &args_to_parse,
249  bool in_spec_file)
250 {
251  for(argst::const_iterator it = args_to_parse.begin();
252  it != args_to_parse.end();
253  ++it)
254  {
255  const std::string &argv_i=*it;
256 
257  // options file?
258  if(has_prefix(argv_i, "@"))
259  {
260  std::ifstream opts_file(argv_i.substr(1));
261  std::ostringstream all_lines;
262  std::string line;
263 
264  while(std::getline(opts_file, line))
265  all_lines << ' ' << line;
266 
267  line = all_lines.str();
268  // erase leading whitespace
269  line.erase(0, line.find_first_not_of("\t "));
270 
271  if(!line.empty())
272  parse_specs_line(line, false);
273 
274  continue;
275  }
276 
277  // file?
278  if(argv_i=="-" || !has_prefix(argv_i, "-"))
279  {
280  if(!in_spec_file)
281  add_infile_arg(argv_i);
282  continue;
283  }
284 
285  if(!in_spec_file)
286  {
287  argst::const_iterator next=it;
288  ++next;
289 
290  bool found=false;
291 
292  if(in_list(argv_i.c_str(),
293  goto_cc_options_without_argument)) // without argument
294  {
295  set(argv_i);
296  found=true;
297  }
298 
299  // separated only, and also allow concatenation with "="
300  for(const char **o=goto_cc_options_with_separated_argument;
301  *o!=nullptr && !found;
302  ++o)
303  {
304  if(argv_i==*o) // separated
305  {
306  found=true;
307  if(next != args_to_parse.end())
308  {
309  set(argv_i, *next);
310  ++it;
311  }
312  else
313  set(argv_i, "");
314  }
315  // concatenated with "="
316  else if(has_prefix(argv_i, std::string(*o)+"="))
317  {
318  found=true;
319  set(*o, argv_i.substr(strlen(*o)+1));
320  }
321  }
322 
323  if(found)
324  continue;
325 
326  // add to new_argv
327  add_arg(argv_i);
328  }
329 
330  // also store in cmdlinet
331 
332  if(has_prefix(argv_i, "-f")) // f-options
333  {
334  set(argv_i);
335  }
336  else if(has_prefix(argv_i, "-W")) // W-options
337  {
338  // "Wp,..." is s special case. These are to pass stuff
339  // to the preprocessor.
340  if(has_prefix(argv_i, "-Wp,"))
341  {
342  std::string value=argv_i.substr(4);
343  set("-WP,", value);
344  }
345  else
346  set(argv_i);
347  }
348  else if(has_prefix(argv_i, "-m")) // m-options
349  {
350  // these sometimes come with a value separated by '=', e.g.,
351  // -march=cpu_type
352  std::size_t equal_pos=argv_i.find('=');
353 
354  if(equal_pos==std::string::npos)
355  set(argv_i); // no value
356  else
357  set(argv_i.substr(0, equal_pos), argv_i.substr(equal_pos+1));
358  }
359  // without argument
360  else if(in_list(argv_i.c_str(), gcc_options_without_argument))
361  {
362  set(argv_i);
363  }
364  else
365  {
366  argst::const_iterator next=it;
367  ++next;
368 
369  bool found=false;
370 
371  // separated only, and also allow concatenation with "="
372  for(const char **o=gcc_options_with_separated_argument;
373  *o!=nullptr && !found;
374  ++o)
375  {
376  if(argv_i==*o) // separated
377  {
378  found=true;
379  if(next != args_to_parse.end())
380  {
381  set(argv_i, *next);
382  if(!in_spec_file)
383  add_arg(*next);
384  ++it;
385  }
386  else
387  set(argv_i, "");
388  }
389  // concatenated with "="
390  else if(has_prefix(argv_i, std::string(*o)+"="))
391  {
392  found=true;
393  set(*o, argv_i.substr(strlen(*o)+1));
394  }
395  }
396 
397  // concatenated _or_ separated, e.g., -I
398  for(const char **o=gcc_options_with_argument;
399  *o!=nullptr && !found;
400  ++o)
401  {
402  if(argv_i==*o) // separated
403  {
404  found=true;
405  if(next != args_to_parse.end())
406  {
407  set(argv_i, *next);
408  if(!in_spec_file)
409  add_arg(*next);
410  ++it;
411  }
412  else
413  set(argv_i, "");
414  }
415  else if(has_prefix(argv_i, *o)) // concatenated
416  {
417  found=true;
418  set(*o, argv_i.substr(strlen(*o)));
419  }
420  }
421 
422  // concatenated only
423  for(const char **o=gcc_options_with_concatenated_argument;
424  *o!=nullptr && !found;
425  ++o)
426  {
427  if(has_prefix(argv_i, *o)) // concatenated
428  {
429  found=true;
430  set(*o, argv_i.substr(strlen(*o)));
431  }
432  }
433 
434  if(!found)
435  {
436  // unrecognized option
437  std::cerr << "Warning: uninterpreted gcc option '" << argv_i
438  << "'\n";
439  }
440  }
441  }
442 
443  return false;
444 }
445 
447 void gcc_cmdlinet::parse_specs_line(const std::string &line, bool in_spec_file)
448 {
449  // initial whitespace has been stripped
450  PRECONDITION(!line.empty());
451  PRECONDITION(line[0] != ' ' && line[0] != '\t');
452 
453  argst args_from_specs;
454 
455  for(std::string::size_type arg_start=0, arg_end=0;
456  arg_end!=std::string::npos;
457  arg_start=line.find_first_not_of("\t ", arg_end))
458  {
459  arg_end=line.find_first_of("\t ", arg_start);
460  args_from_specs.push_back(line.substr(arg_start, arg_end - arg_start));
461  }
462 
463  parse_arguments(args_from_specs, in_spec_file);
464 }
465 
468 {
469  const std::string &specs_file_name=get_value("specs");
470  if(specs_file_name.empty())
471  return;
472 
473  std::ifstream specs_file(specs_file_name);
474  std::string line;
475  bool use_line=false;
476 
477  while(std::getline(specs_file, line))
478  {
479  // erase leading whitespace
480  line.erase(0, line.find_first_not_of("\t "));
481 
482  if(line.empty())
483  // blank lines reset the mode
484  use_line=false;
485  else if(!use_line &&
486  (line=="*link_libgcc:" ||
487  line=="*lib:" ||
488  line=="*libgcc:" ||
489  line=="*link:"))
490  use_line=true;
491  else if(use_line)
492  parse_specs_line(line, true);
493  else
494  {
495  // TODO need message interface
496  // debug() << "Warning: ignoring spec " << line << eom;
497  }
498  }
499 }
std::string get_value(char option) const
Definition: cmdline.cpp:48
bool parse_arguments(const argst &args_to_parse, bool in_spec_file)
void parse_specs()
Parse GCC spec files https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html.
std::vector< std::string > argst
Definition: gcc_cmdline.h:30
void parse_specs_line(const std::string &line, bool in_spec_file)
Parse GCC spec files https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html.
void set(const std::string &opt, const char *value) override
Set option option to value.
void add_infile_arg(const std::string &arg)
static bool in_list(const char *option, const char **list)
virtual bool parse(int argc, const char **argv, const char *optstring)
Parses a commandline according to a specification given in optstring.
Definition: cmdline.cpp:153
void add_arg(const std::string &arg)
bool has_prefix(const std::string &s, const std::string &prefix)
Definition: converter.cpp:13
const char * gcc_options_with_concatenated_argument[]
const char * gcc_options_with_separated_argument[]
Definition: gcc_cmdline.cpp:84
const char * goto_cc_options_with_separated_argument[]
Definition: gcc_cmdline.cpp:24
const char * gcc_options_without_argument[]
const char * goto_cc_options_without_argument[]
Definition: gcc_cmdline.cpp:36
const char * gcc_options_with_argument[]
Definition: gcc_cmdline.cpp:62
A special command line object for the gcc-like options.
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
size_t strlen(const char *s)
Definition: string.c:561
#define size_type
Definition: unistd.c:347