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