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