cprover
ms_cl_cmdline.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: A special command line object for the CL options
4 
5 Author: Daniel Kroening
6 
7 \*******************************************************************/
8 
11 
12 #include "ms_cl_cmdline.h"
13 
14 #include <climits>
15 #include <cstdlib>
16 #include <fstream>
17 #include <iostream>
18 
19 #include <util/unicode.h>
20 
24 // clang-format off
25 const char *non_ms_cl_options[]=
26 {
27  "--show-symbol-table",
28  "--show-function-table",
29  "--ppc-macos",
30  "--i386-linux",
31  "--i386-win32",
32  "--i386-macos",
33  "--string-abstraction",
34  "--no-library",
35  "--16",
36  "--32",
37  "--64",
38  "--little-endian",
39  "--big-endian",
40  "--unsigned-char",
41  "--no-arch",
42  "--help",
43  "--xml",
44  "--partial-inlining",
45  "--verbosity",
46  "--function",
47  "--validate-goto-model",
48  "--export-file-local-symbols",
49  "--mangle-suffix",
50  nullptr
51 };
52 // clang-format on
53 
54 bool ms_cl_cmdlinet::parse(const std::vector<std::string> &arguments)
55 {
56  for(std::size_t i = 0; i < arguments.size(); i++)
57  {
58  // is it a non-cl option?
59  if(std::string(arguments[i], 0, 2) == "--")
60  {
61  process_non_cl_option(arguments[i]);
62 
63  if(
64  arguments[i] == "--verbosity" || arguments[i] == "--function" ||
65  arguments[i] == "--mangle-suffix")
66  {
67  if(i < arguments.size() - 1)
68  {
69  set(arguments[i], arguments[i + 1]);
70  i++; // skip ahead
71  }
72  }
73  }
74  else if(!arguments[i].empty() && arguments[i][0] == '@')
75  {
76  // potentially recursive
77  process_response_file(std::string(arguments[i], 1, std::string::npos));
78  }
79  else if(arguments[i] == "/link" || arguments[i] == "-link")
80  {
81  // anything that follows goes to the linker
82  i = arguments.size() - 1;
83  }
84  else if(
85  arguments[i].size() == 2 &&
86  (arguments[i] == "/D" || arguments[i] == "-D") &&
87  i != arguments.size() - 1)
88  {
89  // this requires special treatment, as you can do "/D something"
90  std::string tmp = "/D" + arguments[i + 1];
91  i++;
92  process_cl_option(tmp);
93  }
94  else
95  process_cl_option(arguments[i]);
96  }
97 
98  return false;
99 }
100 
103 {
104  // first do environment
105 
106  #ifdef _WIN32
107 
108  const wchar_t *CL_env=_wgetenv(L"CL");
109 
110  if(CL_env!=NULL)
112 
113  #else
114 
115  const char *CL_env=getenv("CL");
116 
117  if(CL_env!=nullptr)
119 
120  #endif
121 }
122 
126 bool ms_cl_cmdlinet::parse(int argc, const char **argv)
127 {
128  // should really use "wide" argv from wmain()
129 
130  std::vector<std::string> arguments;
131 
132  // skip argv[0]
133  for(int i=1; i<argc; i++)
134  arguments.push_back(argv[i]);
135 
136  return parse(arguments);
137 }
138 
139 static std::istream &my_wgetline(std::istream &in, std::wstring &dest)
140 {
141  // We should support this properly,
142  // but will just strip right now.
143  dest.clear();
144 
145  while(in)
146  {
147  char ch1, ch2;
148  in.get(ch1);
149  in.get(ch2);
150 
151  if(!in)
152  {
153  if(!dest.empty())
154  in.clear();
155  break;
156  }
157 
158  if(ch1=='\r')
159  {
160  // ignore
161  }
162  else if(ch1=='\n')
163  {
164  in.clear();
165  break; // line end
166  }
167  else
168  dest += wchar_t(ch1 + (ch2 << CHAR_BIT));
169  }
170 
171  return in;
172 }
173 
176 {
177  std::ifstream infile(file);
178 
179  if(!infile)
180  {
181  std::cerr << "failed to open response file '" << file << "'\n";
182  return;
183  }
184 
185  // these may be Unicode -- which is indicated by 0xff 0xfe
186  std::string line;
187  getline(infile, line);
188  if(line.size()>=2 &&
189  line[0]==static_cast<char>(0xff) &&
190  line[1]==static_cast<char>(0xfe))
191  {
192  // Unicode, UTF-16 little endian
193 
194  #if 1
195  // Re-open -- should be using wifstream,
196  // but this isn't available everywhere.
197  std::ifstream infile2(file, std::ios::binary);
198  infile2.seekg(2);
199  std::wstring wline;
200 
201  while(my_wgetline(infile2, wline))
202  process_response_file_line(narrow(wline)); // we UTF-8 it
203 
204  #else
205 
206  std::wifstream infile2(file, std::ios::binary);
207  std::wstring wline;
208 
209  while(std::getline(infile2, wline))
210  process_response_file_line(narrow(wline)); // we UTF-8 it
211 
212  #endif
213  }
214  else if(line.size()>=3 &&
215  line[0]==static_cast<char>(0xef) &&
216  line[1]==static_cast<char>(0xbb) &&
217  line[2]==static_cast<char>(0xbf))
218  {
219  // This is the UTF-8 BOM. We can proceed as usual, since
220  // we use UTF-8 internally.
221  infile.seekg(3);
222 
223  while(getline(infile, line))
225  }
226  else
227  {
228  // normal ASCII
229  infile.seekg(0);
230  while(getline(infile, line))
232  }
233 }
234 
236 void ms_cl_cmdlinet::process_response_file_line(const std::string &line)
237 {
238  // In a response file, multiple compiler options and source-code files can
239  // appear on one line. A single compiler-option specification must appear
240  // on one line (cannot span multiple lines). Response files can have
241  // comments that begin with the # symbol.
242 
243  if(line.empty())
244  return;
245  if(line[0]=='#')
246  return; // comment
247 
248  std::vector<std::string> arguments;
249  std::string option;
250  bool in_quotes=false;
251  for(std::size_t i=0; i<line.size(); i++)
252  {
253  char ch=line[i];
254 
255  if(ch==' ' && !in_quotes)
256  {
257  if(!option.empty())
258  arguments.push_back(option);
259  option.clear();
260  }
261  else if(ch=='"')
262  {
263  in_quotes=!in_quotes;
264  }
265  else
266  option+=ch;
267  }
268 
269  if(!option.empty())
270  arguments.push_back(option);
271 
272  parse(arguments);
273 }
274 
277  const std::string &s)
278 {
279  set(s);
280 
281  for(unsigned j=0; non_ms_cl_options[j]!=nullptr; j++)
282  if(s==non_ms_cl_options[j])
283  return;
284 
285  // unrecognized option
286  std::cout << "Warning: uninterpreted non-CL option '" << s << "'\n";
287 }
288 
290 const char *ms_cl_flags[]=
291 {
292  "c", // compile only
293  nullptr
294 };
295 
296 const char *ms_cl_prefixes[]=
297 {
298  "O1", // minimize space
299  "O2", // maximize speed
300  "Ob", // <n> inline expansion (default n=0)
301  "Od", // disable optimizations (default)
302  "Og", // enable global optimization
303  "Oi", // [-] enable intrinsic functions
304  "Os", // favor code space
305  "Ot", // favor code speed
306  "Ox", // maximum optimizations
307  "Oy", // [-] enable frame pointer omission
308  "GF", // enable read-only string pooling
309  "Gm", // [-] enable minimal rebuild
310  "Gy", // [-] separate functions for linker
311  "GS", // [-] enable security checks
312  "GR", // [-] enable C++ RTTI
313  "GX", // [-] enable C++ EH (same as /EHsc)
314  "EHs", // enable C++ EH (no SEH exceptions)
315  "EHa", // enable C++ EH (w/ SEH exceptions)
316  "EHc", // extern "C" defaults to nothrow
317  "fp", // floating-point model
318  "GL", // [-] enable link-time code generation
319  "GA", // optimize for Windows Application
320  "Ge", // force stack checking for all funcs
321  "Gs", // [num] control stack checking calls
322  "Gh", // enable _penter function call
323  "GH", // enable _pexit function call
324  "GT", // generate fiber-safe TLS accesses
325  "RTC1", // Enable fast checks (/RTCsu)
326  "RTCc", // Convert to smaller type checks
327  "RTCs", // Stack Frame runtime checking
328  "RTCu", // Uninitialized local usage checks
329  "clr", // compile for common language runtime
330  "Gd", // __cdecl calling convention
331  "Gr", // __fastcall calling convention
332  "Gz", // __stdcall calling convention
333  "GZ", // Enable stack checks (/RTCs)
334  "QIfist", // [-] use FIST instead of ftol()
335  "hotpatch", // ensure function padding for hotpatchable images
336  "arch:", // <SSE|SSE2> minimum CPU architecture requirements
337  "Fa", // [file] name assembly listing file
338  "FA", // [scu] configure assembly listing
339  "Fd", // [file] name .PDB file
340  "Fe", // <file> name executable file
341  "Fm", // [file] name map file
342  "Fo", // <file> name object file
343  "Fp", // <file> name precompiled header file
344  "Fr", // [file] name source browser file
345  "FR", // [file] name extended .SBR file
346  "doc", // [file] process XML documentation comments
347  "AI", // <dir> add to assembly search path
348  "FU", // <file> forced using assembly/module
349  "C", // don't strip comments
350  "D", // <name>{=|#}<text> define macro
351  "E", // preprocess to stdout
352  "EP", // preprocess to stdout, no #line
353  "P", // preprocess to file
354  "Fx", // merge injected code to file
355  "FI", // <file> name forced include file
356  "U", // <name> remove predefined macro
357  "u", // remove all predefined macros
358  "I", // <dir> add to include search path
359  "X", // ignore "standard places"
360  "Zi", // enable debugging information
361  "Z7", // enable old-style debug info
362  "Zp", // [n] pack structs on n-byte boundary
363  "Za", // disable extensions
364  "Ze", // enable extensions (default)
365  "Zl", // omit default library name in .OBJ
366  "Zg", // generate function prototypes
367  "Zs", // syntax check only
368  "vd", // {0|1|2} disable/enable vtordisp
369  "vm", // <x> type of pointers to members
370  "Zc:", // arg1[,arg2] C++ language conformance, where arguments can be:
371  "ZI", // enable Edit and Continue debug info
372  "openmp", // enable OpenMP 2.0 language extensions
373  "analyze",
374  "errorReport",
375  "?",
376  "help", // print this help message
377  "FC", // use full pathnames in diagnostics /H<num> max external name length
378  "J", // default char type is unsigned
379  "nologo", // suppress copyright message
380  "show", // Includes show include file names
381  "Tc", // <source file> compile file as .c
382  "Tp", // <source file> compile file as .cpp
383  "TC", // compile all files as .c
384  "TP", // compile all files as .cpp
385  "V", // <string> set version string
386  "w", // disable all warnings
387  "wd", // <n> disable warning n
388  "we", // <n> treat warning n as an error
389  "wo", // <n> issue warning n once
390  "w", // <l><n> set warning level 1-4 for n
391  "W", // <n> set warning level (default n=1)
392  "Wall", // enable all warnings
393  "WL", // enable one line diagnostics
394  "WX", // treat warnings as errors
395  "Yc", // [file] create .PCH file
396  "Yd", // put debug info in every .OBJ
397  "Yl", // [sym] inject .PCH ref for debug lib
398  "Yu", // [file] use .PCH file
399  "Y", // - disable all PCH options
400  "Zm", // <n> max memory alloc (% of default)
401  "Wp64", // enable 64 bit porting warnings
402  "LD", // Create .DLL
403  "LDd", // Create .DLL debug library
404  "LN", // Create a .netmodule
405  "F", // <num> set stack size
406  "link", // [linker options and libraries]
407  "MD", // link with MSVCRT.LIB
408  "MT", // link with LIBCMT.LIB
409  "MDd", // link with MSVCRTD.LIB debug lib
410  "MTd", // link with LIBCMTD.LIB debug lib
411  "std", // specify C++ language standard
412  "sdl", // Enable Additional Security Checks
413  "diagnostics", // unknown
414  nullptr
415 };
416 
417 void ms_cl_cmdlinet::process_cl_option(const std::string &s)
418 {
419  if(s.empty())
420  return;
421 
422  if(s[0]!='/' && s[0]!='-')
423  {
424  args.push_back(s);
425  return;
426  }
427 
428  for(std::size_t j=0; ms_cl_flags[j]!=nullptr; j++)
429  {
430  if(std::string(s, 1, std::string::npos)==ms_cl_flags[j])
431  {
432  cmdlinet::optiont option;
434 
435  if(s.size()==2)
436  {
437  option.islong=false;
438  option.optstring.clear();
439  option.optchar=s[1];
440  optnr=getoptnr(option.optchar);
441  }
442  else
443  {
444  option.islong=true;
445  option.optstring=std::string(s, 1, std::string::npos);
446  option.optchar=0;
447  optnr=getoptnr(option.optstring);
448  }
449 
450  if(!optnr.has_value())
451  {
452  options.push_back(option);
453  optnr=options.size()-1;
454  }
455 
456  options[*optnr].isset=true;
457  return;
458  }
459  }
460 
461  for(std::size_t j=0; ms_cl_prefixes[j]!=nullptr; j++)
462  {
463  std::string ms_cl_prefix=ms_cl_prefixes[j];
464 
465  if(std::string(s, 1, ms_cl_prefix.size())==ms_cl_prefix)
466  {
467  cmdlinet::optiont option;
468 
470 
471  if(ms_cl_prefix.size()==1)
472  {
473  option.islong=false;
474  option.optstring.clear();
475  option.optchar=ms_cl_prefix[0];
476  optnr=getoptnr(option.optchar);
477  }
478  else
479  {
480  option.islong=true;
481  option.optstring=ms_cl_prefix;
482  option.optchar=0;
483  optnr=getoptnr(option.optstring);
484  }
485 
486  if(!optnr.has_value())
487  {
488  options.push_back(option);
489  optnr=options.size()-1;
490  }
491 
492  options[*optnr].isset=true;
493  options[*optnr].values.push_back(
494  std::string(s, ms_cl_prefix.size()+1, std::string::npos));
495 
496  return;
497  }
498  }
499 
500  // unrecognized option
501  std::cout << "Warning: uninterpreted CL option '" << s << "'\n";
502 }
argst args
Definition: cmdline.h:143
optionalt< std::size_t > getoptnr(char option) const
Definition: cmdline.cpp:136
std::vector< optiont > options
Definition: cmdline.h:182
void set(const std::string &opt, const char *value) override
Set option option to value.
virtual bool parse(int argc, const char **argv, const char *optstring)
Parses a commandline according to a specification given in optstring.
Definition: cmdline.cpp:154
void process_response_file(const std::string &file)
void process_response_file_line(const std::string &line)
void process_non_cl_option(const std::string &s)
void process_cl_option(const std::string &s)
static std::string binary(const constant_exprt &src)
Definition: json_expr.cpp:205
const char * ms_cl_prefixes[]
const char * non_ms_cl_options[]
parses the command line options into a cmdlinet
const char * ms_cl_flags[]
static std::istream & my_wgetline(std::istream &in, std::wstring &dest)
A special command line object for the gcc-like options.
output_type narrow(input_type input)
Run-time checked narrowing cast.
Definition: narrow.h:34
nonstd::optional< T > optionalt
Definition: optional.h:35
std::string optstring
Definition: cmdline.h:159
Definition: kdev_t.h:19