cprover
gcc_version.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: GCC Mode
4 
5 Author: Daniel Kroening, 2018
6 
7 \*******************************************************************/
8 
9 #include "gcc_version.h"
10 
11 #include <util/prefix.h>
12 #include <util/run.h>
13 #include <util/string2int.h>
14 #include <util/string_utils.h>
15 #include <util/tempfile.h>
16 
17 #include <fstream>
18 
19 void gcc_versiont::get(const std::string &executable)
20 {
21  temporary_filet tmp_file_in("goto-gcc.", ".in");
22  temporary_filet tmp_file_out("goto-gcc.", ".out");
23  temporary_filet tmp_file_err("goto-gcc.", ".err");
24 
25  {
26  std::ofstream out(tmp_file_in());
27 
28  out << "#if defined(__clang_major__)\n"
29  "clang __clang_major__ __clang_minor__ __clang_patchlevel__\n"
30  "#elif defined(__BCC__)\n"
31  "bcc 0 0 0\n"
32  "#else\n"
33  "gcc __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__\n"
34  "#endif\n"
35  "default_c_standard __STDC_VERSION__\n";
36  }
37 
38  // some variants output stuff on stderr, say Apple LLVM,
39  // which we silence.
40  int result = run(
41  executable,
42  {executable, "-E", "-", "-o", "-"},
43  tmp_file_in(),
44  tmp_file_out(),
45  tmp_file_err());
46 
49 
50  if(result >= 0)
51  {
52  std::ifstream in(tmp_file_out());
53  std::string line;
54 
55  while(!in.fail() && std::getline(in, line))
56  {
57  if(line.empty() || line[0] == '#')
58  continue;
59 
60  auto split = split_string(line, ' ');
61 
62  if(split.size() >= 4)
63  {
64  if(split[0] == "gcc")
66  else if(split[0] == "bcc")
68  else if(split[0] == "clang")
70 
71  v_major = unsafe_string2unsigned(split[1]);
72  v_minor = unsafe_string2unsigned(split[2]);
74  }
75  else if(split.size() == 2 && split[0] == "default_c_standard")
76  {
77  if(split[1] == "199901L")
79  else if(split[1] == "201112L")
81  }
82  }
83 
85  {
86  // Grab the default C++ standard. Unfortunately this requires another
87  // run, as the compiler can't preprocess two files in one go.
88 
89  temporary_filet cpp_in("goto-gcc.", ".cpp");
90  temporary_filet cpp_out("goto-gcc.", ".out");
91  temporary_filet cpp_err("goto-gcc.", ".err");
92 
93  {
94  std::ofstream out(cpp_in());
95  out << "default_cxx_standard __cplusplus\n";
96  }
97 
98  int result = run(
99  executable,
100  {executable, "-E", "-x", "c++", "-", "-o", "-"},
101  cpp_in(),
102  cpp_out(),
103  cpp_err());
104 
105  if(result >= 0)
106  {
107  std::ifstream in(cpp_out());
108  std::string line;
109 
110  while(!in.fail() && std::getline(in, line))
111  {
112  if(line.empty() || line[0] == '#')
113  continue;
114 
115  auto split = split_string(line, ' ');
116 
117  if(split.size() == 2 && split[0] == "default_cxx_standard")
118  {
119  if(split[1] == "199711L")
121  else if(split[1] == "201103L")
123  else if(split[1] == "201402L")
125  }
126  }
127  }
128  }
129  }
130 }
131 
133  unsigned _major,
134  unsigned _minor,
135  unsigned _patchlevel) const
136 {
137  return v_major > _major || (v_major == _major && v_minor > _minor) ||
138  (v_major == _major && v_minor == _minor &&
139  v_patchlevel >= _patchlevel);
140 }
141 
142 std::ostream &operator<<(std::ostream &out, const gcc_versiont &v)
143 {
144  return out << v.v_major << '.' << v.v_minor << '.' << v.v_patchlevel;
145 }
enum gcc_versiont::flavort flavor
unsigned unsafe_string2unsigned(const std::string &str, int base)
Definition: string2int.cpp:69
int run(const std::string &what, const std::vector< std::string > &argv, const std::string &std_input, const std::string &std_output, const std::string &std_error)
Definition: run.cpp:82
unsigned v_minor
Definition: gcc_version.h:22
void get(const std::string &executable)
Definition: gcc_version.cpp:19
unsigned v_patchlevel
Definition: gcc_version.h:22
unsigned v_major
Definition: gcc_version.h:22
bool is_at_least(unsigned v_major, unsigned v_minor=0, unsigned v_patchlevel=0) const
configt::ansi_ct::c_standardt default_c_standard
Definition: gcc_version.h:39
std::ostream & operator<<(std::ostream &out, const gcc_versiont &v)
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)
Given a string s, split into a sequence of substrings when separated by specified delimiter...
configt::cppt::cpp_standardt default_cxx_standard
Definition: gcc_version.h:40