CBMC
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/run.h>
12 #include <util/string2int.h>
13 #include <util/string_utils.h>
14 #include <util/tempfile.h>
15 
16 #include <fstream>
17 
18 void gcc_versiont::get(const std::string &executable)
19 {
20  temporary_filet tmp_file_in("goto-gcc.", ".in");
21  temporary_filet tmp_file_out("goto-gcc.", ".out");
22  temporary_filet tmp_file_err("goto-gcc.", ".err");
23 
24  {
25  std::ofstream out(tmp_file_in());
26 
27  out << "#if defined(__clang_major__)\n"
28  "clang __clang_major__ __clang_minor__ __clang_patchlevel__\n"
29  "#elif defined(__BCC__)\n"
30  "bcc 0 0 0\n"
31  "#else\n"
32  "gcc __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__\n"
33  "#endif\n"
34  "default_c_standard __STDC_VERSION__\n";
35  }
36 
37  // some variants output stuff on stderr, say Apple LLVM,
38  // which we silence.
39  int result = run(
40  executable,
41  {executable, "-E", "-", "-o", "-"},
42  tmp_file_in(),
43  tmp_file_out(),
44  tmp_file_err());
45 
48 
49  if(result >= 0)
50  {
51  std::ifstream in(tmp_file_out());
52  std::string line;
53 
54  while(!in.fail() && std::getline(in, line))
55  {
56  if(line.empty() || line[0] == '#')
57  continue;
58 
59  auto split = split_string(line, ' ');
60 
61  if(split.size() >= 4)
62  {
63  if(split[0] == "gcc")
65  else if(split[0] == "bcc")
67  else if(split[0] == "clang")
69 
70  v_major = unsafe_string2unsigned(split[1]);
71  v_minor = unsafe_string2unsigned(split[2]);
73  }
74  else if(split.size() == 2 && split[0] == "default_c_standard")
75  {
76  if(split[1] == "199901L")
78  else if(split[1] == "201112L")
80  }
81  }
82 
84  {
85  // Grab the default C++ standard. Unfortunately this requires another
86  // run, as the compiler can't preprocess two files in one go.
87 
88  temporary_filet cpp_in("goto-gcc.", ".cpp");
89  temporary_filet cpp_out("goto-gcc.", ".out");
90  temporary_filet cpp_err("goto-gcc.", ".err");
91 
92  {
93  std::ofstream out(cpp_in());
94  out << "default_cxx_standard __cplusplus\n";
95  }
96 
97  result = run(
98  executable,
99  {executable, "-E", "-x", "c++", "-", "-o", "-"},
100  cpp_in(),
101  cpp_out(),
102  cpp_err());
103 
104  if(result >= 0)
105  {
106  std::ifstream in2(cpp_out());
107 
108  while(!in2.fail() && std::getline(in2, line))
109  {
110  if(line.empty() || line[0] == '#')
111  continue;
112 
113  auto split = split_string(line, ' ');
114 
115  if(split.size() == 2 && split[0] == "default_cxx_standard")
116  {
117  if(split[1] == "199711L")
119  else if(split[1] == "201103L")
121  else if(split[1] == "201402L")
123  else if(split[1] == "201703L")
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 }
146 
147 void configure_gcc(const gcc_versiont &gcc_version)
148 {
149  // ISO/IEC TS 18661-3:2015 support was introduced with gcc 7.0
150  if(
151  gcc_version.flavor == gcc_versiont::flavort::GCC &&
152  gcc_version.is_at_least(7u))
153  {
155  }
156 
157  const auto gcc_float128_minor_version =
158  config.ansi_c.arch == "x86_64" ? 3u : 5u;
159 
160  // __float128 exists (as a typedef) since gcc 4.5 everywhere,
161  // and since 4.3 on x86_64
163  gcc_version.flavor == gcc_versiont::flavort::GCC &&
164  gcc_version.is_at_least(4u, gcc_float128_minor_version);
165 }
configt::ansi_ct::ts_18661_3_Floatn_types
bool ts_18661_3_Floatn_types
Definition: config.h:139
configt::cppt::cpp_standardt::CPP98
@ CPP98
tempfile.h
gcc_versiont::get
void get(const std::string &executable)
Definition: gcc_version.cpp:18
string_utils.h
gcc_version.h
configure_gcc
void configure_gcc(const gcc_versiont &gcc_version)
Definition: gcc_version.cpp:147
gcc_versiont::flavor
enum gcc_versiont::flavort flavor
run
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:48
configt::cppt::cpp_standardt::CPP17
@ CPP17
configt::ansi_c
struct configt::ansi_ct ansi_c
run.h
gcc_versiont::default_cxx_standard
configt::cppt::cpp_standardt default_cxx_standard
Definition: gcc_version.h:40
gcc_versiont::flavort::UNKNOWN
@ UNKNOWN
string2int.h
gcc_versiont::flavort::GCC
@ GCC
split_string
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)
Definition: string_utils.cpp:39
gcc_versiont::v_major
unsigned v_major
Definition: gcc_version.h:22
configt::ansi_ct::arch
irep_idt arch
Definition: config.h:206
gcc_versiont::is_at_least
bool is_at_least(unsigned v_major, unsigned v_minor=0, unsigned v_patchlevel=0) const
Definition: gcc_version.cpp:132
config
configt config
Definition: config.cpp:25
gcc_versiont::flavort::CLANG
@ CLANG
configt::ansi_ct::c_standardt::C99
@ C99
gcc_versiont
Definition: gcc_version.h:19
configt::ansi_ct::c_standardt::C11
@ C11
gcc_versiont::v_minor
unsigned v_minor
Definition: gcc_version.h:22
gcc_versiont::default_c_standard
configt::ansi_ct::c_standardt default_c_standard
Definition: gcc_version.h:39
unsafe_string2unsigned
unsigned unsafe_string2unsigned(const std::string &str, int base)
Definition: string2int.cpp:35
operator<<
std::ostream & operator<<(std::ostream &out, const gcc_versiont &v)
Definition: gcc_version.cpp:142
configt::cppt::cpp_standardt::CPP14
@ CPP14
configt::cppt::cpp_standardt::CPP11
@ CPP11
gcc_versiont::flavort::BCC
@ BCC
configt::ansi_ct::gcc__float128_type
bool gcc__float128_type
Definition: config.h:140
gcc_versiont::v_patchlevel
unsigned v_patchlevel
Definition: gcc_version.h:22
temporary_filet
Definition: tempfile.h:23