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 <cassert>
15 #include <cstring>
16 #include <iostream>
17 #include <fstream>
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  "-Os",
185  "-Oz", // Apple only
186  "-C",
187  "-E",
188  "-H",
189  "-M",
190  "-MM",
191  "-MG",
192  "-MP",
193  "-MD",
194  "-MMD",
195  "-mno-unaligned-access",
196  "-mthumb",
197  "-mthumb-interwork",
198  "-nostdinc",
199  "-P",
200  "-remap",
201  "-undef",
202  "-nostdinc",
203  "-nostartfiles",
204  "-nodefaultlibs",
205  "-nostdlib",
206  "-pie",
207  "-rdynamic",
208  "-s",
209  "-static",
210  "-static-libgcc",
211  "--static",
212  "-shared",
213  "--shared",
214  "-shared-libgcc",
215  "-symbolic",
216  "-EB",
217  "-EL",
218  "-fast", // Apple only
219  nullptr
220 };
221 // clang-format on
222 
226 bool gcc_cmdlinet::parse(int argc, const char **argv)
227 {
228  assert(argc>0);
229  add_arg(argv[0]);
230 
231  argst current_args;
232  current_args.reserve(argc - 1);
233 
234  for(int i=1; i<argc; i++)
235  current_args.push_back(argv[i]);
236 
237  bool result = parse_arguments(current_args, false);
238 
239  parse_specs();
240 
241  return result;
242 }
243 
245  const argst &args_to_parse,
246  bool in_spec_file)
247 {
248  for(argst::const_iterator it = args_to_parse.begin();
249  it != args_to_parse.end();
250  ++it)
251  {
252  const std::string &argv_i=*it;
253 
254  // options file?
255  if(has_prefix(argv_i, "@"))
256  {
257  std::ifstream opts_file(argv_i.substr(1));
258  std::string line;
259 
260  while(std::getline(opts_file, line))
261  {
262  // erase leading whitespace
263  line.erase(0, line.find_first_not_of("\t "));
264 
265  if(!line.empty())
266  parse_specs_line(line, false);
267  }
268 
269  continue;
270  }
271 
272  // file?
273  if(argv_i=="-" || !has_prefix(argv_i, "-"))
274  {
275  if(!in_spec_file)
276  add_infile_arg(argv_i);
277  continue;
278  }
279 
280  if(!in_spec_file)
281  {
282  argst::const_iterator next=it;
283  ++next;
284 
285  bool found=false;
286 
287  if(in_list(argv_i.c_str(),
288  goto_cc_options_without_argument)) // without argument
289  {
290  set(argv_i);
291  found=true;
292  }
293 
294  // separated only, and also allow concatenation with "="
295  for(const char **o=goto_cc_options_with_separated_argument;
296  *o!=nullptr && !found;
297  ++o)
298  {
299  if(argv_i==*o) // separated
300  {
301  found=true;
302  if(next != args_to_parse.end())
303  {
304  set(argv_i, *next);
305  ++it;
306  }
307  else
308  set(argv_i, "");
309  }
310  // concatenated with "="
311  else if(has_prefix(argv_i, std::string(*o)+"="))
312  {
313  found=true;
314  set(*o, argv_i.substr(strlen(*o)+1));
315  }
316  }
317 
318  if(found)
319  continue;
320 
321  // add to new_argv
322  add_arg(argv_i);
323  }
324 
325  // also store in cmdlinet
326 
327  if(has_prefix(argv_i, "-f")) // f-options
328  {
329  set(argv_i);
330  }
331  else if(has_prefix(argv_i, "-W")) // W-options
332  {
333  // "Wp,..." is s special case. These are to pass stuff
334  // to the preprocessor.
335  if(has_prefix(argv_i, "-Wp,"))
336  {
337  std::string value=argv_i.substr(4);
338  set("-WP,", value);
339  }
340  else
341  set(argv_i);
342  }
343  else if(has_prefix(argv_i, "-m")) // m-options
344  {
345  // these sometimes come with a value separated by '=', e.g.,
346  // -march=cpu_type
347  std::size_t equal_pos=argv_i.find('=');
348 
349  if(equal_pos==std::string::npos)
350  set(argv_i); // no value
351  else
352  set(argv_i.substr(0, equal_pos), argv_i.substr(equal_pos+1));
353  }
354  // without argument
355  else if(in_list(argv_i.c_str(), gcc_options_without_argument))
356  {
357  set(argv_i);
358  }
359  else
360  {
361  argst::const_iterator next=it;
362  ++next;
363 
364  bool found=false;
365 
366  // separated only, and also allow concatenation with "="
367  for(const char **o=gcc_options_with_separated_argument;
368  *o!=nullptr && !found;
369  ++o)
370  {
371  if(argv_i==*o) // separated
372  {
373  found=true;
374  if(next != args_to_parse.end())
375  {
376  set(argv_i, *next);
377  if(!in_spec_file)
378  add_arg(*next);
379  ++it;
380  }
381  else
382  set(argv_i, "");
383  }
384  // concatenated with "="
385  else if(has_prefix(argv_i, std::string(*o)+"="))
386  {
387  found=true;
388  set(*o, argv_i.substr(strlen(*o)+1));
389  }
390  }
391 
392  // concatenated _or_ separated, e.g., -I
393  for(const char **o=gcc_options_with_argument;
394  *o!=nullptr && !found;
395  ++o)
396  {
397  if(argv_i==*o) // separated
398  {
399  found=true;
400  if(next != args_to_parse.end())
401  {
402  set(argv_i, *next);
403  if(!in_spec_file)
404  add_arg(*next);
405  ++it;
406  }
407  else
408  set(argv_i, "");
409  }
410  else if(has_prefix(argv_i, *o)) // concatenated
411  {
412  found=true;
413  set(*o, argv_i.substr(strlen(*o)));
414  }
415  }
416 
417  // concatenated only
418  for(const char **o=gcc_options_with_concatenated_argument;
419  *o!=nullptr && !found;
420  ++o)
421  {
422  if(has_prefix(argv_i, *o)) // concatenated
423  {
424  found=true;
425  set(*o, argv_i.substr(strlen(*o)));
426  }
427  }
428 
429  if(!found)
430  {
431  // unrecognized option
432  std::cerr << "Warning: uninterpreted gcc option '" << argv_i
433  << "'\n";
434  }
435  }
436  }
437 
438  return false;
439 }
440 
442 void gcc_cmdlinet::parse_specs_line(const std::string &line, bool in_spec_file)
443 {
444  // initial whitespace has been stripped
445  assert(!line.empty());
446  assert(line[0]!=' ' && line[0]!='\t');
447 
448  argst args_from_specs;
449 
450  for(std::string::size_type arg_start=0, arg_end=0;
451  arg_end!=std::string::npos;
452  arg_start=line.find_first_not_of("\t ", arg_end))
453  {
454  arg_end=line.find_first_of("\t ", arg_start);
455  args_from_specs.push_back(line.substr(arg_start, arg_end - arg_start));
456  }
457 
458  parse_arguments(args_from_specs, in_spec_file);
459 }
460 
463 {
464  const std::string &specs_file_name=get_value("specs");
465  if(specs_file_name.empty())
466  return;
467 
468  std::ifstream specs_file(specs_file_name);
469  std::string line;
470  bool use_line=false;
471 
472  while(std::getline(specs_file, line))
473  {
474  // erase leading whitespace
475  line.erase(0, line.find_first_not_of("\t "));
476 
477  if(line.empty())
478  // blank lines reset the mode
479  use_line=false;
480  else if(!use_line &&
481  (line=="*link_libgcc:" ||
482  line=="*lib:" ||
483  line=="*libgcc:" ||
484  line=="*link:"))
485  use_line=true;
486  else if(use_line)
487  parse_specs_line(line, true);
488  else
489  {
490  // TODO need message interface
491  // debug() << "Warning: ignoring spec " << line << eom;
492  }
493  }
494 }
goto_cc_cmdlinet::set
void set(const std::string &opt, const char *value) override
Set option option to value.
Definition: goto_cc_cmdline.h:33
gcc_cmdlinet::parse_specs
void parse_specs()
Parse GCC spec files https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html.
Definition: gcc_cmdline.cpp:462
gcc_options_with_separated_argument
const char * gcc_options_with_separated_argument[]
Definition: gcc_cmdline.cpp:85
prefix.h
goto_cc_options_with_separated_argument
const char * goto_cc_options_with_separated_argument[]
Definition: gcc_cmdline.cpp:23
gcc_options_with_argument
const char * gcc_options_with_argument[]
Definition: gcc_cmdline.cpp:63
gcc_options_without_argument
const char * gcc_options_without_argument[]
Definition: gcc_cmdline.cpp:126
gcc_cmdline.h
A special command line object for the gcc-like options.
gcc_cmdlinet::parse_arguments
bool parse_arguments(const argst &args_to_parse, bool in_spec_file)
Definition: gcc_cmdline.cpp:244
gcc_cmdlinet::parse_specs_line
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.
Definition: gcc_cmdline.cpp:442
cmdlinet::get_value
std::string get_value(char option) const
Definition: cmdline.cpp:47
gcc_cmdlinet::argst
std::vector< std::string > argst
Definition: gcc_cmdline.h:30
goto_cc_options_without_argument
const char * goto_cc_options_without_argument[]
Definition: gcc_cmdline.cpp:36
goto_cc_cmdlinet::parse
virtual bool parse(int argc, const char **argv, const char *optstring)
Definition: cmdline.cpp:154
gcc_options_with_concatenated_argument
const char * gcc_options_with_concatenated_argument[]
Definition: gcc_cmdline.cpp:118
has_prefix
bool has_prefix(const std::string &s, const std::string &prefix)
Definition: converter.cpp:13
goto_cc_cmdlinet::add_infile_arg
void add_infile_arg(const std::string &arg)
Definition: goto_cc_cmdline.cpp:103
size_type
unsignedbv_typet size_type()
Definition: c_types.cpp:58
goto_cc_cmdlinet::add_arg
void add_arg(const std::string &arg)
Definition: goto_cc_cmdline.h:71
goto_cc_cmdlinet::in_list
static bool in_list(const char *option, const char **list)
Definition: goto_cc_cmdline.cpp:39