cprover
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 <cstring>
15 #include <fstream>
16 #include <iostream>
17 #include <sstream>
18 
19 #include <util/prefix.h>
20 
21 // clang-format off
22 // non-gcc options
24 {
25  "--verbosity",
26  "--function",
27  "--native-compiler",
28  "--native-linker",
29  "--print-rejected-preprocessed-source",
30  "--mangle-suffix",
31  "--object-bits",
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  "--no-arch",
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  "-z",
115  nullptr
116 };
117 
119 {
120  "-d",
121  "-g",
122  "-A",
123  nullptr
124 };
125 
127 {
128  "--help",
129  "-h",
130  "-r", // for ld mimicking
131  "-dylib", // for ld mimicking on MacOS
132  "-c",
133  "-S",
134  "-E",
135  "-combine",
136  "-pipe",
137  "-pass-exit-codes",
138  "-v",
139  "-###",
140  "-help",
141  "-target-help",
142  "--version",
143  "-ansi",
144  "-trigraphs",
145  "-no-integrated-cpp",
146  "-traditional",
147  "-traditional-cpp",
148  "-nostdinc++",
149  "-gen-decls",
150  "-pedantic",
151  "-pedantic-errors",
152  "-w",
153  "-dumpspecs",
154  "-dumpmachine",
155  "-dumpversion",
156  "-g",
157  "-gcoff",
158  "-gdwarf-2",
159  "-ggdb",
160  "-gstabs",
161  "-gstabs+",
162  "-gvms",
163  "-gxcoff",
164  "-gxcoff+",
165  "-p",
166  "-pg",
167  "-print-libgcc-file-name",
168  "-print-multi-directory",
169  "-print-multi-lib",
170  "-print-search-dirs",
171  "-print-sysroot",
172  "-print-sysroot-headers-suffix",
173  "-Q",
174  "-Qn",
175  "-Qy",
176  "-pthread",
177  "-save-temps",
178  "-time",
179  "-O",
180  "-O0",
181  "-O1",
182  "-O2",
183  "-O3",
184  "-O6",
185  "-Os",
186  "-Oz", // Apple only
187  "-C",
188  "-E",
189  "-H",
190  "-M",
191  "-MM",
192  "-MG",
193  "-MP",
194  "-MD",
195  "-MMD",
196  "-mno-unaligned-access",
197  "-mthumb",
198  "-mthumb-interwork",
199  "-nostdinc",
200  "-P",
201  "-remap",
202  "-undef",
203  "-nostdinc",
204  "-nostartfiles",
205  "-nodefaultlibs",
206  "-nostdlib",
207  "-pie",
208  "-rdynamic",
209  "-s",
210  "-static",
211  "-static-libgcc",
212  "--static",
213  "-shared",
214  "--shared",
215  "-shared-libgcc",
216  "-symbolic",
217  "-EB",
218  "-EL",
219  "-fast", // Apple only
220  "-coverage",
221  nullptr
222 };
223 // clang-format on
224 
228 bool gcc_cmdlinet::parse(int argc, const char **argv)
229 {
230  assert(argc>0);
231  add_arg(argv[0]);
232 
233  argst current_args;
234  current_args.reserve(argc - 1);
235 
236  for(int i=1; i<argc; i++)
237  current_args.push_back(argv[i]);
238 
239  bool result = parse_arguments(current_args, false);
240 
241  parse_specs();
242 
243  return result;
244 }
245 
247  const argst &args_to_parse,
248  bool in_spec_file)
249 {
250  for(argst::const_iterator it = args_to_parse.begin();
251  it != args_to_parse.end();
252  ++it)
253  {
254  const std::string &argv_i=*it;
255 
256  // options file?
257  if(has_prefix(argv_i, "@"))
258  {
259  std::ifstream opts_file(argv_i.substr(1));
260  std::ostringstream all_lines;
261  std::string line;
262 
263  while(std::getline(opts_file, line))
264  all_lines << ' ' << line;
265 
266  line = all_lines.str();
267  // erase leading whitespace
268  line.erase(0, line.find_first_not_of("\t "));
269 
270  if(!line.empty())
271  parse_specs_line(line, false);
272 
273  continue;
274  }
275 
276  // file?
277  if(argv_i=="-" || !has_prefix(argv_i, "-"))
278  {
279  if(!in_spec_file)
280  add_infile_arg(argv_i);
281  continue;
282  }
283 
284  if(!in_spec_file)
285  {
286  argst::const_iterator next=it;
287  ++next;
288 
289  bool found=false;
290 
291  if(in_list(argv_i.c_str(),
292  goto_cc_options_without_argument)) // without argument
293  {
294  set(argv_i);
295  found=true;
296  }
297 
298  // separated only, and also allow concatenation with "="
299  for(const char **o=goto_cc_options_with_separated_argument;
300  *o!=nullptr && !found;
301  ++o)
302  {
303  if(argv_i==*o) // separated
304  {
305  found=true;
306  if(next != args_to_parse.end())
307  {
308  set(argv_i, *next);
309  ++it;
310  }
311  else
312  set(argv_i, "");
313  }
314  // concatenated with "="
315  else if(has_prefix(argv_i, std::string(*o)+"="))
316  {
317  found=true;
318  set(*o, argv_i.substr(strlen(*o)+1));
319  }
320  }
321 
322  if(found)
323  continue;
324 
325  // add to new_argv
326  add_arg(argv_i);
327  }
328 
329  // also store in cmdlinet
330 
331  if(has_prefix(argv_i, "-f")) // f-options
332  {
333  set(argv_i);
334  }
335  else if(has_prefix(argv_i, "-W")) // W-options
336  {
337  // "Wp,..." is s special case. These are to pass stuff
338  // to the preprocessor.
339  if(has_prefix(argv_i, "-Wp,"))
340  {
341  std::string value=argv_i.substr(4);
342  set("-WP,", value);
343  }
344  else
345  set(argv_i);
346  }
347  else if(has_prefix(argv_i, "-m")) // m-options
348  {
349  // these sometimes come with a value separated by '=', e.g.,
350  // -march=cpu_type
351  std::size_t equal_pos=argv_i.find('=');
352 
353  if(equal_pos==std::string::npos)
354  set(argv_i); // no value
355  else
356  set(argv_i.substr(0, equal_pos), argv_i.substr(equal_pos+1));
357  }
358  // without argument
359  else if(in_list(argv_i.c_str(), gcc_options_without_argument))
360  {
361  set(argv_i);
362  }
363  else
364  {
365  argst::const_iterator next=it;
366  ++next;
367 
368  bool found=false;
369 
370  // separated only, and also allow concatenation with "="
371  for(const char **o=gcc_options_with_separated_argument;
372  *o!=nullptr && !found;
373  ++o)
374  {
375  if(argv_i==*o) // separated
376  {
377  found=true;
378  if(next != args_to_parse.end())
379  {
380  set(argv_i, *next);
381  if(!in_spec_file)
382  add_arg(*next);
383  ++it;
384  }
385  else
386  set(argv_i, "");
387  }
388  // concatenated with "="
389  else if(has_prefix(argv_i, std::string(*o)+"="))
390  {
391  found=true;
392  set(*o, argv_i.substr(strlen(*o)+1));
393  }
394  }
395 
396  // concatenated _or_ separated, e.g., -I
397  for(const char **o=gcc_options_with_argument;
398  *o!=nullptr && !found;
399  ++o)
400  {
401  if(argv_i==*o) // separated
402  {
403  found=true;
404  if(next != args_to_parse.end())
405  {
406  set(argv_i, *next);
407  if(!in_spec_file)
408  add_arg(*next);
409  ++it;
410  }
411  else
412  set(argv_i, "");
413  }
414  else if(has_prefix(argv_i, *o)) // concatenated
415  {
416  found=true;
417  set(*o, argv_i.substr(strlen(*o)));
418  }
419  }
420 
421  // concatenated only
422  for(const char **o=gcc_options_with_concatenated_argument;
423  *o!=nullptr && !found;
424  ++o)
425  {
426  if(has_prefix(argv_i, *o)) // concatenated
427  {
428  found=true;
429  set(*o, argv_i.substr(strlen(*o)));
430  }
431  }
432 
433  if(!found)
434  {
435  // unrecognized option
436  std::cerr << "Warning: uninterpreted gcc option '" << argv_i
437  << "'\n";
438  }
439  }
440  }
441 
442  return false;
443 }
444 
446 void gcc_cmdlinet::parse_specs_line(const std::string &line, bool in_spec_file)
447 {
448  // initial whitespace has been stripped
449  assert(!line.empty());
450  assert(line[0]!=' ' && line[0]!='\t');
451 
452  argst args_from_specs;
453 
454  for(std::string::size_type arg_start=0, arg_end=0;
455  arg_end!=std::string::npos;
456  arg_start=line.find_first_not_of("\t ", arg_end))
457  {
458  arg_end=line.find_first_of("\t ", arg_start);
459  args_from_specs.push_back(line.substr(arg_start, arg_end - arg_start));
460  }
461 
462  parse_arguments(args_from_specs, in_spec_file);
463 }
464 
467 {
468  const std::string &specs_file_name=get_value("specs");
469  if(specs_file_name.empty())
470  return;
471 
472  std::ifstream specs_file(specs_file_name);
473  std::string line;
474  bool use_line=false;
475 
476  while(std::getline(specs_file, line))
477  {
478  // erase leading whitespace
479  line.erase(0, line.find_first_not_of("\t "));
480 
481  if(line.empty())
482  // blank lines reset the mode
483  use_line=false;
484  else if(!use_line &&
485  (line=="*link_libgcc:" ||
486  line=="*lib:" ||
487  line=="*libgcc:" ||
488  line=="*link:"))
489  use_line=true;
490  else if(use_line)
491  parse_specs_line(line, true);
492  else
493  {
494  // TODO need message interface
495  // debug() << "Warning: ignoring spec " << line << eom;
496  }
497  }
498 }
unsignedbv_typet size_type()
Definition: c_types.cpp:68
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:23
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:63
A special command line object for the gcc-like options.