CMakeLists.txt 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. cmake_minimum_required(VERSION 3.10)
  2. project(CompileFeatures)
  3. set(ext_C c)
  4. set(ext_CXX cpp)
  5. set(std_C 90 99 11 17 23)
  6. set(std_CXX 98 11 14 17 20 23 26)
  7. if(CMake_TEST_CUDA)
  8. enable_language(CUDA)
  9. set(ext_CUDA cu)
  10. set(std_CUDA 03 11 14 17 20 23 26)
  11. endif()
  12. if(CMake_TEST_HIP)
  13. enable_language(HIP)
  14. set(ext_HIP hip)
  15. set(std_HIP 98 11 14 17 20 23 26)
  16. endif()
  17. foreach(lang C CXX CUDA HIP)
  18. foreach(std IN LISTS std_${lang})
  19. string(TOLOWER "${lang}_std_${std}" feature)
  20. if("${std}" IN_LIST CMake_TEST_${lang}_STANDARDS
  21. OR CMAKE_${lang}${std}_STANDARD_COMPILE_OPTION)
  22. add_library(test_${feature} OBJECT ${feature}.${ext_${lang}})
  23. target_compile_features(test_${feature} PRIVATE ${feature})
  24. endif()
  25. endforeach()
  26. endforeach()
  27. if(("23" IN_LIST CMake_TEST_CXX_STANDARDS OR CMAKE_CXX23_STANDARD_COMPILE_OPTION)
  28. AND ("11" IN_LIST CMake_TEST_C_STANDARDS OR CMAKE_C11_STANDARD_COMPILE_OPTION))
  29. add_library(test_cxx_std_23_with_c_std_11 OBJECT cxx_std_23.cpp c_std_11.c)
  30. target_compile_features(test_cxx_std_23_with_c_std_11 PRIVATE cxx_std_23 c_std_11)
  31. endif()
  32. if(("23" IN_LIST CMake_TEST_C_STANDARDS OR CMAKE_C23_STANDARD_COMPILE_OPTION)
  33. AND ("17" IN_LIST CMake_TEST_CXX_STANDARDS OR CMAKE_CXX17_STANDARD_COMPILE_OPTION)
  34. # FIXME: "clang-cl -stc:clatest" does not enable C23.
  35. AND NOT CMAKE_GENERATOR MATCHES "Visual Studio"
  36. )
  37. add_library(test_c_std_23_with_cxx_std_17 OBJECT c_std_23.c cxx_std_17.cpp)
  38. target_compile_features(test_c_std_23_with_cxx_std_17 PRIVATE c_std_23 cxx_std_17)
  39. endif()
  40. macro(run_test feature lang)
  41. if (${feature} IN_LIST CMAKE_${lang}_COMPILE_FEATURES)
  42. add_library(test_${feature} OBJECT ${feature}.${ext_${lang}})
  43. set_property(TARGET test_${feature}
  44. PROPERTY COMPILE_FEATURES "${feature}"
  45. )
  46. else()
  47. list(APPEND ${lang}_non_features ${feature})
  48. endif()
  49. endmacro()
  50. if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IBMClang|IntelLLVM|Fujitsu|FujitsuClang|OrangeC)$")
  51. get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
  52. list(FILTER c_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
  53. foreach(feature ${c_features})
  54. run_test(${feature} C)
  55. endforeach()
  56. endif()
  57. if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IBMClang|IntelLLVM|Fujitsu|FujitsuClang|OrangeC)$")
  58. get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
  59. list(FILTER cxx_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
  60. foreach(feature ${cxx_features})
  61. run_test(${feature} CXX)
  62. endforeach()
  63. endif()
  64. if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
  65. AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
  66. # AppleClang prior to 5.1 does not set any preprocessor define to distinguish
  67. # c++1y from c++11, so CMake does not support c++1y features before AppleClang 5.1.
  68. list(REMOVE_ITEM CXX_non_features
  69. cxx_attribute_deprecated
  70. cxx_binary_literals
  71. )
  72. endif()
  73. if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"
  74. AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2)
  75. # AppleClang prior to 4.1 reports false for __has_feature(cxx_local_type_template_args)
  76. # and __has_feature(cxx_unrestricted_unions) but it happens to pass these tests.
  77. list(REMOVE_ITEM CXX_non_features
  78. cxx_local_type_template_args
  79. cxx_unrestricted_unions
  80. )
  81. endif()
  82. if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro)
  83. if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.15)
  84. # SunPro 5.14 accepts -std=c++14 and compiles two features but does
  85. # not define __cplusplus to a value different than with -std=c++11.
  86. list(REMOVE_ITEM CXX_non_features
  87. cxx_aggregate_default_initializers
  88. cxx_digit_separators
  89. )
  90. endif()
  91. # FIXME: Do any of these work correctly on SunPro 5.13 or above?
  92. list(REMOVE_ITEM CXX_non_features
  93. cxx_attribute_deprecated
  94. cxx_contextual_conversions
  95. cxx_extended_friend_declarations
  96. cxx_long_long_type
  97. cxx_sizeof_member
  98. cxx_variadic_macros
  99. )
  100. endif()
  101. if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
  102. AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5)
  103. # The cxx_raw_string_literals feature happens to work in some distributions
  104. # of GNU 4.4, but it is first documented as available with GNU 4.5.
  105. list(REMOVE_ITEM CXX_non_features
  106. cxx_raw_string_literals
  107. )
  108. endif()
  109. if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
  110. AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
  111. # The cxx_constexpr feature happens to work (for *this* testcase) with
  112. # GNU 4.5, but it is first documented as available with GNU 4.6.
  113. list(REMOVE_ITEM CXX_non_features
  114. cxx_constexpr
  115. )
  116. endif()
  117. if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
  118. AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
  119. # The cxx_alignof feature happens to work (for *this* testcase) with
  120. # GNU 4.7, but it is first documented as available with GNU 4.8.
  121. list(REMOVE_ITEM CXX_non_features
  122. cxx_alignof
  123. )
  124. endif()
  125. if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
  126. AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
  127. # GNU prior to 4.9 does not set any preprocessor define to distinguish
  128. # c++1y from c++11, so CMake does not support c++1y features before GNU 4.9.
  129. list(REMOVE_ITEM CXX_non_features
  130. # GNU 4.8 knows cxx_attributes, but doesn't know [[deprecated]]
  131. # and warns that it is unknown and ignored.
  132. cxx_attribute_deprecated
  133. cxx_binary_literals
  134. cxx_lambda_init_captures
  135. cxx_return_type_deduction
  136. )
  137. endif()
  138. if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  139. if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
  140. list(REMOVE_ITEM CXX_non_features
  141. # The cxx_contextual_conversions feature happens to work
  142. # (for *this* testcase) with VS 2010 and VS 2012, but
  143. # they do not document support until VS 2013.
  144. cxx_contextual_conversions
  145. )
  146. elseif (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0)
  147. list(REMOVE_ITEM CXX_non_features
  148. # The cxx_deleted_functions and cxx_nonstatic_member_init
  149. # features happen to work (for *this* testcase) with VS 2013,
  150. # but they do not document support until VS 2015.
  151. cxx_deleted_functions
  152. cxx_nonstatic_member_init
  153. )
  154. endif()
  155. endif()
  156. if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
  157. if (CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"
  158. AND CMAKE_CXX_SIMULATE_VERSION VERSION_LESS 19.10)
  159. list(REMOVE_ITEM CXX_non_features
  160. cxx_relaxed_constexpr
  161. )
  162. endif()
  163. if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
  164. if (CMAKE_CXX_COMIPLER_VERSION VERSION_EQUAL 15.0)
  165. list(REMOVE_ITEM CXX_non_features
  166. # The cxx_contextual_conversions feature happens to work
  167. # (for *this* testcase) with Intel 13/14/15, but they do not
  168. # document support until 16.
  169. cxx_contextual_conversions
  170. )
  171. elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14.0)
  172. list(REMOVE_ITEM CXX_non_features
  173. cxx_alignof
  174. # not supposed to work until 15
  175. cxx_attribute_deprecated
  176. # The cxx_contextual_conversions feature happens to work
  177. # (for *this* testcase) with Intel 13/14/15, but they do not
  178. # document support until 16.
  179. cxx_contextual_conversions
  180. )
  181. elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
  182. list(REMOVE_ITEM CXX_non_features
  183. # These features happen to work but aren't documented to
  184. # do so until 14.0
  185. cxx_constexpr
  186. cxx_enum_forward_declarations
  187. cxx_sizeof_member
  188. cxx_strong_enums
  189. cxx_unicode_literals
  190. # not supposed to work until 15
  191. cxx_attribute_deprecated
  192. cxx_nonstatic_member_init
  193. # The cxx_contextual_conversions feature happens to work
  194. # (for *this* testcase) with Intel 13/14/15, but they do not
  195. # document support until 16.
  196. cxx_contextual_conversions
  197. # This is an undocumented feature; it does not work in future versions
  198. cxx_aggregate_default_initializers
  199. )
  200. endif()
  201. endif()
  202. endif()
  203. if (CMAKE_C_COMPILER_ID STREQUAL "Intel")
  204. if (CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.2)
  205. # This works on some pre-15.0.2 versions and not others.
  206. list(REMOVE_ITEM C_non_features
  207. c_static_assert
  208. )
  209. endif()
  210. endif()
  211. if (CMAKE_C_COMPILE_FEATURES)
  212. set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
  213. list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
  214. endif()
  215. if (CMAKE_CXX_COMPILE_FEATURES)
  216. set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
  217. list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
  218. endif ()
  219. set(C_ext c)
  220. set(C_standard_flag 11)
  221. set(CXX_ext cpp)
  222. set(CXX_standard_flag 14)
  223. foreach(lang CXX C)
  224. if (${lang}_expected_features)
  225. foreach(feature ${${lang}_non_features})
  226. message("Testing feature : ${feature}")
  227. try_compile(${feature}_works
  228. "${CMAKE_CURRENT_BINARY_DIR}/${feature}_test"
  229. "${CMAKE_CURRENT_SOURCE_DIR}/feature_test.${${lang}_ext}"
  230. COMPILE_DEFINITIONS "-DTEST=${feature}.${${lang}_ext}"
  231. CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD=${${lang}_standard_flag}"
  232. "-DINCLUDE_DIRECTORIES=${CMAKE_CURRENT_SOURCE_DIR}"
  233. OUTPUT_VARIABLE OUTPUT
  234. )
  235. if (${feature}_works)
  236. message(SEND_ERROR
  237. "Feature ${feature} expected not to work for ${lang} ${CMAKE_${lang}_COMPILER_ID}-${CMAKE_${lang}_COMPILER_VERSION}.
  238. Update the supported features or blacklist it.\n${OUTPUT}")
  239. else()
  240. message("Testing feature : ${feature} -- Fails, as expected.")
  241. endif()
  242. endforeach()
  243. endif()
  244. endforeach()
  245. if (C_expected_features)
  246. if (CMAKE_C_STANDARD_DEFAULT)
  247. string(FIND "${CMAKE_C_FLAGS}" "-std=" std_flag_idx)
  248. if (std_flag_idx EQUAL -1)
  249. add_executable(default_dialect_C default_dialect.c)
  250. target_compile_definitions(default_dialect_C PRIVATE
  251. DEFAULT_C23=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},23>
  252. DEFAULT_C17=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},17>
  253. DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11>
  254. DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99>
  255. DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90>
  256. )
  257. endif()
  258. endif()
  259. add_executable(CompileFeaturesGenex_C genex_test.c)
  260. set_property(TARGET CompileFeaturesGenex_C PROPERTY C_STANDARD 11)
  261. foreach(f
  262. c_restrict
  263. c_static_assert
  264. c_function_prototypes
  265. )
  266. if(${f} IN_LIST C_expected_features)
  267. set(expect_${f} 1)
  268. else()
  269. set(expect_${f} 0)
  270. endif()
  271. string(TOUPPER "${f}" F)
  272. target_compile_definitions(CompileFeaturesGenex_C PRIVATE
  273. EXPECT_${F}=${expect_${f}}
  274. HAVE_${F}=$<COMPILE_FEATURES:${f}>
  275. )
  276. endforeach()
  277. endif()
  278. if (CMAKE_CXX_COMPILE_FEATURES)
  279. if (CMAKE_CXX_STANDARD_DEFAULT)
  280. string(FIND "${CMAKE_CXX_FLAGS}" "-std=" std_flag_idx)
  281. if (std_flag_idx EQUAL -1)
  282. add_executable(default_dialect default_dialect.cpp)
  283. target_compile_definitions(default_dialect PRIVATE
  284. DEFAULT_CXX26=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},26>
  285. DEFAULT_CXX23=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},23>
  286. DEFAULT_CXX20=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},20>
  287. DEFAULT_CXX17=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},17>
  288. DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14>
  289. DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11>
  290. DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98>
  291. )
  292. endif()
  293. endif()
  294. endif ()
  295. if (CMake_TEST_CUDA
  296. AND CMAKE_CUDA_COMPILE_FEATURES
  297. AND CMAKE_CUDA_STANDARD_DEFAULT
  298. AND NOT CMAKE_CUDA_FLAGS MATCHES "-std=")
  299. add_executable(default_dialect_cuda default_dialect.cu)
  300. target_compile_definitions(default_dialect_cuda PRIVATE
  301. DEFAULT_CXX26=$<EQUAL:${CMAKE_CUDA_STANDARD_DEFAULT},26>
  302. DEFAULT_CXX23=$<EQUAL:${CMAKE_CUDA_STANDARD_DEFAULT},23>
  303. DEFAULT_CXX20=$<EQUAL:${CMAKE_CUDA_STANDARD_DEFAULT},20>
  304. DEFAULT_CXX17=$<EQUAL:${CMAKE_CUDA_STANDARD_DEFAULT},17>
  305. DEFAULT_CXX14=$<EQUAL:${CMAKE_CUDA_STANDARD_DEFAULT},14>
  306. DEFAULT_CXX11=$<EQUAL:${CMAKE_CUDA_STANDARD_DEFAULT},11>
  307. DEFAULT_CXX98=$<EQUAL:${CMAKE_CUDA_STANDARD_DEFAULT},03>
  308. )
  309. endif ()
  310. # always add a target "CompileFeatures"
  311. if ((NOT CXX_expected_features) OR
  312. (NOT cxx_auto_type IN_LIST CXX_expected_features))
  313. file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
  314. "int main(int,char**) { return 0; }\n"
  315. )
  316. add_executable(CompileFeatures "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp")
  317. else()
  318. # these tests only work if at least cxx_auto_type is available
  319. add_executable(CompileFeatures main.cpp)
  320. set_property(TARGET CompileFeatures
  321. PROPERTY COMPILE_FEATURES "cxx_auto_type"
  322. )
  323. set_property(TARGET CompileFeatures
  324. PROPERTY CXX_STANDARD_REQUIRED TRUE
  325. )
  326. add_executable(GenexCompileFeatures main.cpp)
  327. set_property(TARGET GenexCompileFeatures
  328. PROPERTY COMPILE_FEATURES "$<1:cxx_auto_type>;$<0:not_a_feature>"
  329. )
  330. add_library(iface INTERFACE)
  331. set_property(TARGET iface
  332. PROPERTY INTERFACE_COMPILE_FEATURES "cxx_auto_type"
  333. )
  334. add_executable(IfaceCompileFeatures main.cpp)
  335. target_link_libraries(IfaceCompileFeatures iface)
  336. foreach(f
  337. cxx_final
  338. cxx_override
  339. cxx_auto_type
  340. cxx_inheriting_constructors
  341. )
  342. if(${f} IN_LIST CXX_expected_features)
  343. set(expect_${f} 1)
  344. else()
  345. set(expect_${f} 0)
  346. endif()
  347. endforeach()
  348. if(expect_cxx_final AND expect_cxx_override)
  349. set(expect_override_control 1)
  350. else()
  351. set(expect_override_control 0)
  352. endif()
  353. if(expect_cxx_inheriting_constructors AND expect_cxx_final)
  354. set(expect_inheriting_constructors_and_final 1)
  355. else()
  356. set(expect_inheriting_constructors_and_final 0)
  357. endif()
  358. set(genex_test_defs
  359. HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>
  360. HAVE_AUTO_TYPE=$<COMPILE_FEATURES:cxx_auto_type>
  361. HAVE_INHERITING_CONSTRUCTORS=$<COMPILE_FEATURES:cxx_inheriting_constructors>
  362. HAVE_FINAL=$<COMPILE_FEATURES:cxx_final>
  363. HAVE_INHERITING_CONSTRUCTORS_AND_FINAL=$<COMPILE_FEATURES:cxx_inheriting_constructors,cxx_final>
  364. EXPECT_OVERRIDE_CONTROL=${expect_override_control}
  365. EXPECT_INHERITING_CONSTRUCTORS=${expect_cxx_inheriting_constructors}
  366. EXPECT_FINAL=${expect_cxx_final}
  367. EXPECT_INHERITING_CONSTRUCTORS_AND_FINAL=${expect_inheriting_constructors_and_final}
  368. )
  369. if (CMAKE_CXX_STANDARD_DEFAULT)
  370. list(APPEND genex_test_defs
  371. TEST_CXX_STD
  372. HAVE_CXX_STD_11=$<COMPILE_FEATURES:cxx_std_11>
  373. HAVE_CXX_STD_14=$<COMPILE_FEATURES:cxx_std_14>
  374. HAVE_CXX_STD_17=$<COMPILE_FEATURES:cxx_std_17>
  375. HAVE_CXX_STD_20=$<COMPILE_FEATURES:cxx_std_20>
  376. HAVE_CXX_STD_23=$<COMPILE_FEATURES:cxx_std_23>
  377. HAVE_CXX_STD_26=$<COMPILE_FEATURES:cxx_std_26>
  378. )
  379. endif()
  380. add_executable(CompileFeaturesGenex genex_test.cpp)
  381. set_property(TARGET CompileFeaturesGenex PROPERTY CXX_STANDARD 11)
  382. target_compile_definitions(CompileFeaturesGenex PRIVATE ${genex_test_defs})
  383. add_executable(CompileFeaturesGenex2 genex_test.cpp)
  384. target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_std_11)
  385. target_compile_definitions(CompileFeaturesGenex2 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
  386. add_library(std_11_iface INTERFACE)
  387. target_compile_features(std_11_iface INTERFACE cxx_std_11)
  388. add_executable(CompileFeaturesGenex3 genex_test.cpp)
  389. target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
  390. target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
  391. endif()
  392. if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"
  393. AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.30
  394. # The MSVC 14.29.30133 toolset supports C++20,
  395. # but MSBuild puts the flags in the wrong order.
  396. OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30129 AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
  397. )
  398. )
  399. add_library(msvc_permissive msvc_permissive.cxx)
  400. target_compile_features(msvc_permissive PRIVATE cxx_std_20)
  401. # The `-std:c++20` flag implies `-permissive-`. Test passing `-permissive` afterward.
  402. target_compile_options(msvc_permissive PRIVATE -permissive)
  403. endif()