2 cmake_minimum_required(VERSION 3.1)
3 cmake_policy(SET CMP0057 NEW)
5 project(CompileFeatures)
10 macro(run_test feature lang)
11 if (${feature} IN_LIST CMAKE_${lang}_COMPILE_FEATURES)
12 add_library(test_${feature} OBJECT ${feature}.${ext_${lang}})
13 set_property(TARGET test_${feature}
14 PROPERTY COMPILE_FEATURES "${feature}"
17 list(APPEND ${lang}_non_features ${feature})
21 if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IBMClang|IntelLLVM|Fujitsu|FujitsuClang)$")
22 get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
23 list(FILTER c_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
24 foreach(feature ${c_features})
25 run_test(${feature} C)
29 if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IBMClang|IntelLLVM|Fujitsu|FujitsuClang)$")
30 get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
31 list(FILTER cxx_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
32 foreach(feature ${cxx_features})
33 run_test(${feature} CXX)
37 if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
38 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
39 # AppleClang prior to 5.1 does not set any preprocessor define to distinguish
40 # c++1y from c++11, so CMake does not support c++1y features before AppleClang 5.1.
41 list(REMOVE_ITEM CXX_non_features
42 cxx_attribute_deprecated
47 if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
48 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2)
49 # AppleClang prior to 4.1 reports false for __has_feature(cxx_local_type_template_args)
50 # and __has_feature(cxx_unrestricted_unions) but it happens to pass these tests.
51 list(REMOVE_ITEM CXX_non_features
52 cxx_local_type_template_args
53 cxx_unrestricted_unions
57 if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
58 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.15)
59 # SunPro 5.14 accepts -std=c++14 and compiles two features but does
60 # not define __cplusplus to a value different than with -std=c++11.
61 list(REMOVE_ITEM CXX_non_features
62 cxx_aggregate_default_initializers
67 # FIXME: Do any of these work correctly on SunPro 5.13 or above?
68 list(REMOVE_ITEM CXX_non_features
69 cxx_attribute_deprecated
70 cxx_contextual_conversions
71 cxx_extended_friend_declarations
78 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
79 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5)
80 # The cxx_raw_string_literals feature happens to work in some distributions
81 # of GNU 4.4, but it is first documented as available with GNU 4.5.
82 list(REMOVE_ITEM CXX_non_features
83 cxx_raw_string_literals
86 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
87 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
88 # The cxx_constexpr feature happens to work (for *this* testcase) with
89 # GNU 4.5, but it is first documented as available with GNU 4.6.
90 list(REMOVE_ITEM CXX_non_features
94 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
95 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
96 # The cxx_alignof feature happens to work (for *this* testcase) with
97 # GNU 4.7, but it is first documented as available with GNU 4.8.
98 list(REMOVE_ITEM CXX_non_features
102 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
103 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
104 # GNU prior to 4.9 does not set any preprocessor define to distinguish
105 # c++1y from c++11, so CMake does not support c++1y features before GNU 4.9.
106 list(REMOVE_ITEM CXX_non_features
107 # GNU 4.8 knows cxx_attributes, but doesn't know [[deprecated]]
108 # and warns that it is unknown and ignored.
109 cxx_attribute_deprecated
111 cxx_lambda_init_captures
112 cxx_return_type_deduction
116 if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
117 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
118 list(REMOVE_ITEM CXX_non_features
119 # The cxx_contextual_conversions feature happens to work
120 # (for *this* testcase) with VS 2010 and VS 2012, but
121 # they do not document support until VS 2013.
122 cxx_contextual_conversions
124 elseif (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0)
125 list(REMOVE_ITEM CXX_non_features
126 # The cxx_deleted_functions and cxx_nonstatic_member_init
127 # features happen to work (for *this* testcase) with VS 2013,
128 # but they do not document support until VS 2015.
129 cxx_deleted_functions
130 cxx_nonstatic_member_init
135 if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
136 if (CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"
137 AND CMAKE_CXX_SIMULATE_VERSION VERSION_LESS 19.10)
138 list(REMOVE_ITEM CXX_non_features
139 cxx_relaxed_constexpr
142 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
143 if (CMAKE_CXX_COMIPLER_VERSION VERSION_EQUAL 15.0)
144 list(REMOVE_ITEM CXX_non_features
145 # The cxx_contextual_conversions feature happens to work
146 # (for *this* testcase) with Intel 13/14/15, but they do not
147 # document support until 16.
148 cxx_contextual_conversions
151 elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14.0)
152 list(REMOVE_ITEM CXX_non_features
155 # not supposed to work until 15
156 cxx_attribute_deprecated
158 # The cxx_contextual_conversions feature happens to work
159 # (for *this* testcase) with Intel 13/14/15, but they do not
160 # document support until 16.
161 cxx_contextual_conversions
164 elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
165 list(REMOVE_ITEM CXX_non_features
166 # These features happen to work but aren't documented to
169 cxx_enum_forward_declarations
174 # not supposed to work until 15
175 cxx_attribute_deprecated
176 cxx_nonstatic_member_init
178 # The cxx_contextual_conversions feature happens to work
179 # (for *this* testcase) with Intel 13/14/15, but they do not
180 # document support until 16.
181 cxx_contextual_conversions
183 # This is an undocumented feature; it does not work in future versions
184 cxx_aggregate_default_initializers
190 if (CMAKE_C_COMPILER_ID STREQUAL "Intel")
191 if (CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.2)
192 # This works on some pre-15.0.2 versions and not others.
193 list(REMOVE_ITEM C_non_features
199 if (CMAKE_C_COMPILE_FEATURES)
200 set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
201 list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
203 if (CMAKE_CXX_COMPILE_FEATURES)
204 set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
205 list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
208 set(C_standard_flag 11)
210 set(CXX_standard_flag 14)
212 if (${lang}_expected_features)
213 foreach(feature ${${lang}_non_features})
214 message("Testing feature : ${feature}")
215 try_compile(${feature}_works
216 "${CMAKE_CURRENT_BINARY_DIR}/${feature}_test"
217 "${CMAKE_CURRENT_SOURCE_DIR}/feature_test.${${lang}_ext}"
218 COMPILE_DEFINITIONS "-DTEST=${feature}.${${lang}_ext}"
219 CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD=${${lang}_standard_flag}"
220 "-DINCLUDE_DIRECTORIES=${CMAKE_CURRENT_SOURCE_DIR}"
221 OUTPUT_VARIABLE OUTPUT
223 if (${feature}_works)
225 "Feature ${feature} expected not to work for ${lang} ${CMAKE_${lang}_COMPILER_ID}-${CMAKE_${lang}_COMPILER_VERSION}.
226 Update the supported features or blacklist it.\n${OUTPUT}")
228 message("Testing feature : ${feature} -- Fails, as expected.")
234 if (C_expected_features)
235 if (CMAKE_C_STANDARD_DEFAULT)
236 string(FIND "${CMAKE_C_FLAGS}" "-std=" std_flag_idx)
237 if (std_flag_idx EQUAL -1)
238 add_executable(default_dialect_C default_dialect.c)
239 target_compile_definitions(default_dialect_C PRIVATE
240 DEFAULT_C23=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},23>
241 DEFAULT_C17=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},17>
242 DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11>
243 DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99>
244 DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90>
249 add_executable(CompileFeaturesGenex_C genex_test.c)
250 set_property(TARGET CompileFeaturesGenex_C PROPERTY C_STANDARD 11)
255 c_function_prototypes
257 if(${f} IN_LIST C_expected_features)
262 string(TOUPPER "${f}" F)
263 target_compile_definitions(CompileFeaturesGenex_C PRIVATE
264 EXPECT_${F}=${expect_${f}}
265 HAVE_${F}=$<COMPILE_FEATURES:${f}>
270 if (CMAKE_CXX_COMPILE_FEATURES)
271 if (CMAKE_CXX_STANDARD_DEFAULT)
272 string(FIND "${CMAKE_CXX_FLAGS}" "-std=" std_flag_idx)
273 if (std_flag_idx EQUAL -1)
274 add_executable(default_dialect default_dialect.cpp)
275 target_compile_definitions(default_dialect PRIVATE
276 DEFAULT_CXX23=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},23>
277 DEFAULT_CXX20=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},20>
278 DEFAULT_CXX17=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},17>
279 DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14>
280 DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11>
281 DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98>
287 # always add a target "CompileFeatures"
288 if ((NOT CXX_expected_features) OR
289 (NOT cxx_auto_type IN_LIST CXX_expected_features))
290 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
291 "int main(int,char**) { return 0; }\n"
293 add_executable(CompileFeatures "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp")
295 # these tests only work if at least cxx_auto_type is available
296 add_executable(CompileFeatures main.cpp)
297 set_property(TARGET CompileFeatures
298 PROPERTY COMPILE_FEATURES "cxx_auto_type"
300 set_property(TARGET CompileFeatures
301 PROPERTY CXX_STANDARD_REQUIRED TRUE
304 add_executable(GenexCompileFeatures main.cpp)
305 set_property(TARGET GenexCompileFeatures
306 PROPERTY COMPILE_FEATURES "$<1:cxx_auto_type>;$<0:not_a_feature>"
309 add_library(iface INTERFACE)
310 set_property(TARGET iface
311 PROPERTY INTERFACE_COMPILE_FEATURES "cxx_auto_type"
313 add_executable(IfaceCompileFeatures main.cpp)
314 target_link_libraries(IfaceCompileFeatures iface)
320 cxx_inheriting_constructors
322 if(${f} IN_LIST CXX_expected_features)
329 if(expect_cxx_final AND expect_cxx_override)
330 set(expect_override_control 1)
332 set(expect_override_control 0)
334 if(expect_cxx_inheriting_constructors AND expect_cxx_final)
335 set(expect_inheriting_constructors_and_final 1)
337 set(expect_inheriting_constructors_and_final 0)
341 HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>
342 HAVE_AUTO_TYPE=$<COMPILE_FEATURES:cxx_auto_type>
343 HAVE_INHERITING_CONSTRUCTORS=$<COMPILE_FEATURES:cxx_inheriting_constructors>
344 HAVE_FINAL=$<COMPILE_FEATURES:cxx_final>
345 HAVE_INHERITING_CONSTRUCTORS_AND_FINAL=$<COMPILE_FEATURES:cxx_inheriting_constructors,cxx_final>
346 EXPECT_OVERRIDE_CONTROL=${expect_override_control}
347 EXPECT_INHERITING_CONSTRUCTORS=${expect_cxx_inheriting_constructors}
348 EXPECT_FINAL=${expect_cxx_final}
349 EXPECT_INHERITING_CONSTRUCTORS_AND_FINAL=${expect_inheriting_constructors_and_final}
351 if (CMAKE_CXX_STANDARD_DEFAULT)
352 list(APPEND genex_test_defs
354 HAVE_CXX_STD_11=$<COMPILE_FEATURES:cxx_std_11>
355 HAVE_CXX_STD_14=$<COMPILE_FEATURES:cxx_std_14>
356 HAVE_CXX_STD_17=$<COMPILE_FEATURES:cxx_std_17>
357 HAVE_CXX_STD_20=$<COMPILE_FEATURES:cxx_std_20>
358 HAVE_CXX_STD_23=$<COMPILE_FEATURES:cxx_std_23>
359 HAVE_CXX_STD_26=$<COMPILE_FEATURES:cxx_std_26>
363 add_executable(CompileFeaturesGenex genex_test.cpp)
364 set_property(TARGET CompileFeaturesGenex PROPERTY CXX_STANDARD 11)
365 target_compile_definitions(CompileFeaturesGenex PRIVATE ${genex_test_defs})
367 add_executable(CompileFeaturesGenex2 genex_test.cpp)
368 target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_std_11)
369 target_compile_definitions(CompileFeaturesGenex2 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
371 add_library(std_11_iface INTERFACE)
372 target_compile_features(std_11_iface INTERFACE cxx_std_11)
373 add_executable(CompileFeaturesGenex3 genex_test.cpp)
374 target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
375 target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)