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