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  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 in2(cpp_out());
108 
109  while(!in2.fail() && std::getline(in2, line))
110  {
111  if(line.empty() || line[0] == '#')
112  continue;
113 
114  auto split = split_string(line, ' ');
115 
116  if(split.size() == 2 && split[0] == "default_cxx_standard")
117  {
118  if(split[1] == "199711L")
120  else if(split[1] == "201103L")
122  else if(split[1] == "201402L")
124  }
125  }
126  }
127  }
128  }
129 }
130 
132  unsigned _major,
133  unsigned _minor,
134  unsigned _patchlevel) const
135 {
136  return v_major > _major || (v_major == _major && v_minor > _minor) ||
137  (v_major == _major && v_minor == _minor &&
138  v_patchlevel >= _patchlevel);
139 }
140 
141 std::ostream &operator<<(std::ostream &out, const gcc_versiont &v)
142 {
143  return out << v.v_major << '.' << v.v_minor << '.' << v.v_patchlevel;
144 }
145 
146 void configure_gcc(const gcc_versiont &gcc_version)
147 {
148  // ISO/IEC TS 18661-3:2015 support was introduced with gcc 7.0
149  if(
150  gcc_version.flavor == gcc_versiont::flavort::GCC &&
151  gcc_version.is_at_least(7u))
152  {
154  }
155 
156  const auto gcc_float128_minor_version =
157  config.ansi_c.arch == "x86_64" ? 3u : 5u;
158 
159  // __float128 exists (as a typedef) since gcc 4.5 everywhere,
160  // and since 4.3 on x86_64
162  gcc_version.flavor == gcc_versiont::flavort::GCC &&
163  gcc_version.is_at_least(4u, gcc_float128_minor_version);
164 }
configt::ansi_ct::ts_18661_3_Floatn_types
bool ts_18661_3_Floatn_types
Definition: config.h:46
configt::cppt::cpp_standardt::CPP98
@ CPP98
tempfile.h
gcc_versiont::get
void get(const std::string &executable)
Definition: gcc_version.cpp:19
string_utils.h
gcc_version.h
prefix.h
configure_gcc
void configure_gcc(const gcc_versiont &gcc_version)
Definition: gcc_version.cpp:146
gcc_versiont::flavor
enum gcc_versiont::flavort flavor
run
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:49
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:40
gcc_versiont::v_major
unsigned v_major
Definition: gcc_version.h:22
configt::ansi_ct::arch
irep_idt arch
Definition: config.h:85
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:131
config
configt config
Definition: config.cpp:24
gcc_versiont::flavort::CLANG
@ CLANG
configt::ansi_ct::c_standardt::C99
@ C99
gcc_versiont
Definition: gcc_version.h:20
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:38
operator<<
std::ostream & operator<<(std::ostream &out, const gcc_versiont &v)
Definition: gcc_version.cpp:141
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:47
gcc_versiont::v_patchlevel
unsigned v_patchlevel
Definition: gcc_version.h:22
temporary_filet
Definition: tempfile.h:24