-
Notifications
You must be signed in to change notification settings - Fork 47
/
cxx-standard.cmake
194 lines (188 loc) · 6.32 KB
/
cxx-standard.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#
# Copyright (C) 2020 LAAS-CNRS
#
# Author: Guilhem Saurel
#
# .rst: .. ifmode:: internal
#
# .. variable:: ENFORCE_MINIMAL_CXX_STANDARD
#
# When this is ON, every call to :cmake:command:`CHECK_MINIMAL_CXX_STANDARD`
# updates the :cmake:variable:`CMAKE_CXX_STANDARD`.
option(
ENFORCE_MINIMAL_CXX_STANDARD
"Set CMAKE_CXX_STANDARD if a dependency require it"
OFF
)
# .rst: .. ifmode:: user
#
# .. command:: CHECK_MINIMAL_CXX_STANDARD(STANDARD [ENFORCE])
#
# Ensure that a minimal C++ standard will be used.
#
# This will check the default standard of the current compiler, and set
# :cmake:variable:`CMAKE_CXX_STANDARD` if necessary, and `ENFORCE` is provided,
# or :cmake:variable:`ENFORCE_MINIMAL_CXX_STANDARD` is `ON`. Multiple calls to
# this macro will keep the highest standard.
#
# Supported values are 98, 11, 14, 17, and 20.
#
macro(CHECK_MINIMAL_CXX_STANDARD STANDARD)
set(options ENFORCE)
set(oneValueArgs)
set(multiValueArgs)
cmake_parse_arguments(
MINIMAL_CXX_STANDARD
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
# Get compiler default cxx standard, by printing "__cplusplus" (only once)
if(
NOT DEFINED _COMPILER_DEFAULT_CXX_STANDARD
AND
(
NOT CMAKE_CROSSCOMPILING
OR (CMAKE_CROSSCOMPILING AND CMAKE_CROSSCOMPILING_EMULATOR)
)
)
if(MSVC)
# See
# https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
string(APPEND CMAKE_CXX_FLAGS " /Zc:__cplusplus")
endif()
write_file(
${CMAKE_CURRENT_BINARY_DIR}/cmake/tmp-cxx-standard.cpp
"#include <iostream>\nint main(){std::cout << __cplusplus << std::endl;return 0;}"
)
try_run(
_cxx_standard_run_status
_cxx_standard_build_status
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/cmake/tmp-cxx-standard.cpp
RUN_OUTPUT_VARIABLE _COMPILER_DEFAULT_CXX_STANDARD
)
if(
_cxx_standard_run_status EQUAL FAILED_TO_RUN
OR NOT _cxx_standard_build_status
)
message(
WARNING
"Impossible to build or run the script to retrive the _COMPILER_DEFAULT_CXX_STANDARD quantity from current compiler. Setting _COMPILER_DEFAULT_CXX_STANDARD to 199711"
)
set(_COMPILER_DEFAULT_CXX_STANDARD "199711")
endif()
string(
STRIP
"${_COMPILER_DEFAULT_CXX_STANDARD}"
_COMPILER_DEFAULT_CXX_STANDARD
)
message(STATUS "Default C++ standard: ${_COMPILER_DEFAULT_CXX_STANDARD}")
endif()
# Check if we need to upgrade the current minimum
if(
NOT DEFINED _MINIMAL_CXX_STANDARD
OR
(
NOT ${STANDARD} EQUAL "98"
AND
(
_MINIMAL_CXX_STANDARD EQUAL "98"
OR _MINIMAL_CXX_STANDARD LESS ${STANDARD}
)
)
)
set(_MINIMAL_CXX_STANDARD "${STANDARD}" CACHE INTERNAL "")
message(STATUS "Minimal C++ standard upgraded to ${_MINIMAL_CXX_STANDARD}")
endif()
# Check if a non-trivial minimum has been requested
if(DEFINED _MINIMAL_CXX_STANDARD AND NOT _MINIMAL_CXX_STANDARD EQUAL 98)
if(DEFINED CMAKE_CXX_STANDARD)
set(_CURRENT_STANDARD ${CMAKE_CXX_STANDARD})
elseif(DEFINED _COMPILER_DEFAULT_CXX_STANDARD)
# ref
# https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros
# for constants
if(_COMPILER_DEFAULT_CXX_STANDARD EQUAL 199711)
set(_CURRENT_STANDARD 98)
elseif(_COMPILER_DEFAULT_CXX_STANDARD EQUAL 201103)
set(_CURRENT_STANDARD 11)
elseif(_COMPILER_DEFAULT_CXX_STANDARD EQUAL 201402)
set(_CURRENT_STANDARD 14)
elseif(_COMPILER_DEFAULT_CXX_STANDARD EQUAL 201703)
set(_CURRENT_STANDARD 17)
# C++20: g++-9 defines c++2a with literal 201709, g++-11 & clang-10
# define c++2a with literal 202002
elseif(
_COMPILER_DEFAULT_CXX_STANDARD EQUAL 201709
OR _COMPILER_DEFAULT_CXX_STANDARD EQUAL 202002
)
set(_CURRENT_STANDARD 20)
else()
message(
FATAL_ERROR
"Unknown current C++ standard ${_COMPILER_DEFAULT_CXX_STANDARD} while trying to check for >= ${_MINIMAL_CXX_STANDARD}"
)
endif()
else()
set(_CURRENT_STANDARD 98)
endif()
# Check that the requested minimum is higher than the currently selected
if(
_CURRENT_STANDARD EQUAL 98
OR _CURRENT_STANDARD LESS _MINIMAL_CXX_STANDARD
)
message(
STATUS
"Incompatible C++ standard detected: upgrade required from ${_CURRENT_STANDARD} to >= ${_MINIMAL_CXX_STANDARD}"
)
# Check that the requested minimum is higher than any pre-existing
# CMAKE_CXX_STANDARD
if(
NOT CMAKE_CXX_STANDARD
OR CMAKE_CXX_STANDARD EQUAL 98
OR CMAKE_CXX_STANDARD LESS _MINIMAL_CXX_STANDARD
)
# Throw error if a specific version is required and the currently
# desired one is incompatible
if(CMAKE_CXX_STANDARD_REQUIRED)
message(
FATAL_ERROR
"CMAKE_CXX_STANDARD_REQUIRED set - cannot upgrade incompatible standard"
)
endif()
# Enforcing a standard version is required - check if we can upgrade
# automatically
if(ENFORCE_MINIMAL_CXX_STANDARD OR MINIMAL_CXX_STANDARD_ENFORCE)
set(CMAKE_CXX_STANDARD ${_MINIMAL_CXX_STANDARD})
message(
STATUS
"CMAKE_CXX_STANDARD automatically upgraded from ${_CURRENT_STANDARD} to ${CMAKE_CXX_STANDARD}"
)
else()
message(
FATAL_ERROR
"CMAKE_CXX_STANDARD upgrade from ${_CURRENT_STANDARD} to >= ${_MINIMAL_CXX_STANDARD} required"
)
endif()
endif()
else() # requested minimum is higher than the currently selected
message(
STATUS
"C++ standard sufficient: Minimal required ${_MINIMAL_CXX_STANDARD}, currently defined: ${_CURRENT_STANDARD}"
)
# current C++ standard was not set in CMake but we enforce it
if(
NOT DEFINED CMAKE_CXX_STANDARD
AND (ENFORCE_MINIMAL_CXX_STANDARD OR MINIMAL_CXX_STANDARD_ENFORCE)
)
message(
STATUS
"CMAKE_CXX_STANDARD was not set: automatically set to currently defined standard ${_CURRENT_STANDARD}"
)
set(CMAKE_CXX_STANDARD ${_CURRENT_STANDARD})
endif()
endif() # requested minimum is higher than the currently selected
endif()
endmacro()