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