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