RunCMakeTest.cmake 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. include(RunCMake)
  2. set(stdlib_custom_json)
  3. if (CMake_TEST_CXX_STDLIB_MODULES_JSON)
  4. list(APPEND stdlib_custom_json
  5. -DCMAKE_CXX_STDLIB_MODULES_JSON=${CMake_TEST_CXX_STDLIB_MODULES_JSON})
  6. endif ()
  7. run_cmake(Inspect ${stdlib_custom_json})
  8. include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake")
  9. if (RunCMake_GENERATOR MATCHES "Ninja")
  10. execute_process(
  11. COMMAND "${CMAKE_MAKE_PROGRAM}" --version
  12. RESULT_VARIABLE res
  13. OUTPUT_VARIABLE ninja_version
  14. ERROR_VARIABLE err
  15. OUTPUT_STRIP_TRAILING_WHITESPACE
  16. ERROR_STRIP_TRAILING_WHITESPACE)
  17. if (res)
  18. message(WARNING
  19. "Failed to determine `ninja` version: ${err}")
  20. set(ninja_version "0")
  21. endif ()
  22. endif ()
  23. set(generator_supports_cxx_modules 0)
  24. if (RunCMake_GENERATOR MATCHES "Ninja" AND
  25. ninja_version VERSION_GREATER_EQUAL "1.11" AND
  26. "cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
  27. set(generator_supports_cxx_modules 1)
  28. endif ()
  29. if (RunCMake_GENERATOR MATCHES "Visual Studio" AND
  30. CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "19.34")
  31. set(generator_supports_cxx_modules 1)
  32. endif ()
  33. # Test behavior when the generator does not support C++20 modules.
  34. if (NOT generator_supports_cxx_modules)
  35. # Bail; the remaining tests require the generator to successfully generate
  36. # with C++20 modules in the source list.
  37. return ()
  38. endif ()
  39. # This performs actual compilation tests; avoid it when not requested.
  40. if (NOT CMake_TEST_MODULE_COMPILATION)
  41. return ()
  42. endif ()
  43. # Module compilation features:
  44. # Compiler-based:
  45. # - `named`: basic support for named modules is available
  46. # - `shared`: shared libraries are supported
  47. # - `partitions`: module partitions are supported
  48. # - `internal_partitions`: internal module partitions are supported
  49. # - `bmionly`: the compiler supports BMI-only builds
  50. # - `import_std23`: the compiler supports `import std` for C++23
  51. #
  52. # Generator-based:
  53. # - `compile_commands`: the generator supports `compile_commands.json`
  54. # - `collation`: the generator supports module collation features
  55. # - `export_bmi`: the generator supports exporting BMIs
  56. # - `ninja`: a `ninja` binary is available to perform `Ninja`-only testing
  57. # (assumed if the generator matches `Ninja`).
  58. string(REPLACE "," ";" CMake_TEST_MODULE_COMPILATION "${CMake_TEST_MODULE_COMPILATION}")
  59. if (RunCMake_GENERATOR MATCHES "Ninja")
  60. list(APPEND CMake_TEST_MODULE_COMPILATION
  61. "ninja")
  62. endif ()
  63. function (run_cxx_module_test directory)
  64. set(test_name "${directory}")
  65. if (NOT ARGN STREQUAL "")
  66. list(POP_FRONT ARGN test_name)
  67. endif ()
  68. set(RunCMake_TEST_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${directory}")
  69. set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${test_name}-build")
  70. if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
  71. set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
  72. else ()
  73. set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
  74. endif ()
  75. if (directory MATCHES "imp-std")
  76. list(APPEND RunCMake_TEST_OPTIONS
  77. ${stdlib_custom_json})
  78. endif ()
  79. if (RunCMake_CXXModules_INSTALL)
  80. set(prefix "${RunCMake_BINARY_DIR}/${test_name}-install")
  81. file(REMOVE_RECURSE "${prefix}")
  82. list(APPEND RunCMake_TEST_OPTIONS
  83. "-DCMAKE_INSTALL_PREFIX=${prefix}")
  84. endif ()
  85. list(APPEND RunCMake_TEST_OPTIONS
  86. "-DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES}"
  87. ${ARGN})
  88. run_cmake("${test_name}")
  89. set(RunCMake_TEST_NO_CLEAN 1)
  90. if (RunCMake_CXXModules_TARGET)
  91. run_cmake_command("${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug --target "${RunCMake_CXXModules_TARGET}")
  92. else ()
  93. run_cmake_command("${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug)
  94. foreach (RunCMake_CXXModules_TARGET IN LISTS RunCMake_CXXModules_TARGETS)
  95. set(RunCMake_CXXModules_CONFIG "Debug")
  96. set(RunCMake_CXXModules_NAME_SUFFIX "")
  97. if (RunCMake_CXXModules_TARGET MATCHES "(.*)@(.*)")
  98. set(RunCMake_CXXModules_TARGET "${CMAKE_MATCH_1}")
  99. set(RunCMake_CXXModules_CONFIG "${CMAKE_MATCH_2}")
  100. set(RunCMake_CXXModules_NAME_SUFFIX "-${RunCMake_CXXModules_CONFIG}")
  101. endif ()
  102. run_cmake_command("${test_name}-target-${RunCMake_CXXModules_TARGET}${RunCMake_CXXModules_NAME_SUFFIX}" "${CMAKE_COMMAND}" --build . --target "${RunCMake_CXXModules_TARGET}" --config "${RunCMake_CXXModules_CONFIG}")
  103. endforeach ()
  104. endif ()
  105. if (RunCMake_CXXModules_INSTALL)
  106. run_cmake_command("${test_name}-install" "${CMAKE_COMMAND}" --build . --target install --config Debug)
  107. endif ()
  108. if (NOT RunCMake_CXXModules_NO_TEST)
  109. run_cmake_command("${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure)
  110. endif ()
  111. if (RunCMake_CXXModules_REBUILD)
  112. execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.125) # handle 1s resolution
  113. include("${RunCMake_TEST_SOURCE_DIR}/pre-rebuild.cmake")
  114. execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.125) # handle 1s resolution
  115. run_cmake_command("${test_name}-rebuild" "${CMAKE_COMMAND}" --build . --config Debug)
  116. endif ()
  117. endfunction ()
  118. function (run_cxx_module_test_target directory target)
  119. set(RunCMake_CXXModules_TARGET "${target}")
  120. set(RunCMake_CXXModules_NO_TEST 1)
  121. run_cxx_module_test("${directory}" ${ARGN})
  122. endfunction ()
  123. function (run_cxx_module_test_rebuild directory)
  124. set(RunCMake_CXXModules_INSTALL 0)
  125. set(RunCMake_CXXModules_NO_TEST 1)
  126. set(RunCMake_CXXModules_REBUILD 1)
  127. run_cxx_module_test("${directory}" ${ARGN})
  128. endfunction ()
  129. if (RunCMake_GENERATOR MATCHES "Ninja")
  130. if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
  131. set(ninja_cmp0154_target "CMakeFiles/ninja_cmp0154.dir/Debug/unrelated.cxx${CMAKE_CXX_OUTPUT_EXTENSION}")
  132. else ()
  133. set(ninja_cmp0154_target "CMakeFiles/ninja_cmp0154.dir/unrelated.cxx${CMAKE_CXX_OUTPUT_EXTENSION}")
  134. endif ()
  135. run_cxx_module_test_target(ninja-cmp0154 "${ninja_cmp0154_target}")
  136. endif ()
  137. run_cxx_module_test(scan-with-pch)
  138. # Tests which use named modules.
  139. if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION)
  140. run_cxx_module_test(simple)
  141. run_cxx_module_test(file-sets-with-dot)
  142. run_cxx_module_test(vs-without-flags)
  143. run_cxx_module_test(library library-static -DBUILD_SHARED_LIBS=OFF)
  144. run_cxx_module_test(unity-build)
  145. run_cxx_module_test(object-library)
  146. run_cxx_module_test(generated)
  147. run_cxx_module_test(deep-chain)
  148. run_cxx_module_test(non-trivial-collation-order)
  149. run_cxx_module_test(non-trivial-collation-order-randomized)
  150. run_cxx_module_test(duplicate)
  151. set(RunCMake_CXXModules_NO_TEST 1)
  152. run_cxx_module_test(imp-from-object)
  153. run_cxx_module_test(circular)
  154. run_cxx_module_test(try-compile)
  155. run_cxx_module_test(try-run)
  156. unset(RunCMake_CXXModules_NO_TEST)
  157. run_cxx_module_test(same-src-name)
  158. run_cxx_module_test(scan_props)
  159. run_cxx_module_test(target-objects)
  160. if ("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES AND
  161. "import_std23" IN_LIST CMake_TEST_MODULE_COMPILATION)
  162. run_cxx_module_test(imp-std)
  163. set(RunCMake_CXXModules_NO_TEST 1)
  164. run_cxx_module_test(imp-std-no-std-prop)
  165. unset(RunCMake_CXXModules_NO_TEST)
  166. run_cxx_module_test(imp-std-exp-no-std-build)
  167. set(RunCMake_CXXModules_INSTALL 1)
  168. run_cxx_module_test(imp-std-exp-no-std-install)
  169. unset(RunCMake_CXXModules_INSTALL)
  170. if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION)
  171. run_cxx_module_test(imp-std-not-in-exp-build)
  172. run_cxx_module_test(imp-std-trans imp-std-trans-not-in-exp-build "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/imp-std-not-in-exp-build-build")
  173. set(RunCMake_CXXModules_INSTALL 1)
  174. run_cxx_module_test(imp-std-not-in-exp-install)
  175. unset(RunCMake_CXXModules_INSTALL)
  176. run_cxx_module_test(imp-std-trans imp-std-trans-not-in-exp-install "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/imp-std-not-in-exp-install-install")
  177. run_cxx_module_test(imp-std-trans imp-std-trans-exp-no-std-build "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/imp-std-exp-no-std-build-build" -DEXPORT_NO_STD=1)
  178. run_cxx_module_test(imp-std-trans imp-std-trans-exp-no-std-install "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/imp-std-exp-no-std-install-install" -DEXPORT_NO_STD=1)
  179. endif ()
  180. endif ()
  181. endif ()
  182. # Tests which require compile commands support.
  183. if ("compile_commands" IN_LIST CMake_TEST_MODULE_COMPILATION)
  184. run_cxx_module_test(exp-compile-commands)
  185. endif ()
  186. macro (setup_export_build_database_targets)
  187. set(RunCMake_CXXModules_TARGETS
  188. cmake_build_database-CXX
  189. cmake_build_database)
  190. if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
  191. list(INSERT RunCMake_CXXModules_TARGETS 0
  192. cmake_build_database-CXX-Debug
  193. cmake_build_database-Debug
  194. # Other config targets.
  195. cmake_build_database-CXX-Release@Release
  196. cmake_build_database-Release@Release)
  197. endif ()
  198. endmacro ()
  199. # Tests which require build database support.
  200. if ("build_database" IN_LIST CMake_TEST_MODULE_COMPILATION)
  201. setup_export_build_database_targets()
  202. set(RunCMake_CXXModules_NO_TEST 1)
  203. run_cxx_module_test(exp-builddb)
  204. unset(RunCMake_CXXModules_NO_TEST)
  205. unset(RunCMake_CXXModules_TARGETS)
  206. endif ()
  207. # Tests which require collation work.
  208. if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION)
  209. run_cxx_module_test(duplicate-sources)
  210. run_cxx_module_test(public-req-priv)
  211. set(RunCMake_CXXModules_NO_TEST 1)
  212. run_cxx_module_test(req-priv-other-target)
  213. unset(RunCMake_CXXModules_NO_TEST)
  214. run_cxx_module_test_rebuild(depchain-modmap)
  215. run_cxx_module_test_rebuild(depchain-mods-json-file)
  216. if (RunCMake_GENERATOR MATCHES "Ninja")
  217. run_cxx_module_test_rebuild(depchain-collation-restat)
  218. endif ()
  219. endif ()
  220. # Tests which use named modules in shared libraries.
  221. if ("shared" IN_LIST CMake_TEST_MODULE_COMPILATION)
  222. run_cxx_module_test(library library-shared -DBUILD_SHARED_LIBS=ON)
  223. endif ()
  224. # Tests which use partitions.
  225. if ("partitions" IN_LIST CMake_TEST_MODULE_COMPILATION)
  226. run_cxx_module_test(partitions)
  227. endif ()
  228. # Tests which use internal partitions.
  229. if ("internal_partitions" IN_LIST CMake_TEST_MODULE_COMPILATION)
  230. run_cxx_module_test(internal-partitions)
  231. endif ()
  232. function (run_cxx_module_import_test type name)
  233. set(RunCMake_CXXModules_INSTALL 0)
  234. if ("EXPORT_BUILD_DATABASE" IN_LIST ARGN)
  235. list(REMOVE_ITEM ARGN EXPORT_BUILD_DATABASE)
  236. list(APPEND ARGN -DCMAKE_EXPORT_BUILD_DATABASE=1)
  237. endif ()
  238. run_cxx_module_test(imp-mods "imp-mods-${name}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/${name}-${type}" ${ARGN})
  239. endfunction ()
  240. # Tests which install BMIs
  241. if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
  242. run_cxx_module_test(exp-iface-no-props-build)
  243. run_cxx_module_test(exp-iface-build)
  244. run_cxx_module_test(exp-incdirs-build)
  245. run_cxx_module_test(exp-incdirs-old-cmake-build)
  246. run_cxx_module_test(exp-usage-build)
  247. run_cxx_module_test(exp-bmi-and-iface-build)
  248. run_cxx_module_test(exp-command-sepdir-build)
  249. run_cxx_module_test(exp-trans-targets-build)
  250. run_cxx_module_test(exp-trans-mods1-build)
  251. run_cxx_module_test(exp-trans-mods-build exp-trans-mods-build "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/exp-trans-mods1-build-build" )
  252. run_cxx_module_test(exp-with-headers-build)
  253. if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
  254. "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
  255. run_cxx_module_import_test(build exp-iface-build)
  256. run_cxx_module_import_test(build exp-iface-no-props-build -DNO_PROPERTIES=1)
  257. run_cxx_module_import_test(build exp-incdirs-build -DINCLUDE_PROPERTIES=1)
  258. run_cxx_module_import_test(build exp-bmi-and-iface-build -DWITH_BMIS=1)
  259. run_cxx_module_import_test(build exp-command-sepdir-build -DEXPORT_COMMAND_SEPDIR=1)
  260. run_cxx_module_import_test(build exp-trans-targets-build -DTRANSITIVE_TARGETS=1)
  261. run_cxx_module_import_test(build exp-trans-mods-build -DTRANSITIVE_MODULES=1)
  262. run_cxx_module_import_test(build exp-with-headers-build -DWITH_HEADERS=1)
  263. if ("build_database" IN_LIST CMake_TEST_MODULE_COMPILATION)
  264. setup_export_build_database_targets()
  265. run_cxx_module_import_test(build exp-builddb -DBUILD_DATABASE=1 EXPORT_BUILD_DATABASE)
  266. unset(RunCMake_CXXModules_TARGETS)
  267. endif ()
  268. endif ()
  269. endif ()
  270. # All of the following tests perform installation.
  271. set(RunCMake_CXXModules_INSTALL 1)
  272. # Tests which install BMIs
  273. if ("install_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
  274. run_cxx_module_test(install-bmi)
  275. run_cxx_module_test(install-bmi-and-ifaces)
  276. if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
  277. run_cxx_module_test(exp-iface-no-props-install)
  278. run_cxx_module_test(exp-iface-install)
  279. run_cxx_module_test(exp-incdirs-install)
  280. run_cxx_module_test(exp-incdirs-old-cmake-install)
  281. run_cxx_module_test(exp-usage-install)
  282. run_cxx_module_test(exp-bmi-and-iface-install)
  283. run_cxx_module_test(exp-command-sepdir-install)
  284. run_cxx_module_test(exp-trans-targets-install)
  285. run_cxx_module_test(exp-trans-mods1-install)
  286. run_cxx_module_test(exp-trans-mods-install exp-trans-mods-install "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/exp-trans-mods1-install-install" )
  287. run_cxx_module_test(exp-with-headers-install)
  288. if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
  289. "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
  290. run_cxx_module_import_test(install exp-iface-install)
  291. run_cxx_module_import_test(install exp-iface-no-props-install -DNO_PROPERTIES=1)
  292. run_cxx_module_import_test(install exp-incdirs-install -DINCLUDE_PROPERTIES=1)
  293. run_cxx_module_import_test(install exp-bmi-and-iface-install -DWITH_BMIS=1)
  294. run_cxx_module_import_test(install exp-command-sepdir-install -DEXPORT_COMMAND_SEPDIR=1)
  295. run_cxx_module_import_test(install exp-trans-targets-install -DTRANSITIVE_TARGETS=1)
  296. run_cxx_module_import_test(install exp-trans-mods-install -DTRANSITIVE_MODULES=1)
  297. run_cxx_module_import_test(install exp-with-headers-install -DWITH_HEADERS=1)
  298. endif ()
  299. endif ()
  300. endif ()
  301. # All remaining tests require a working `Ninja` generator to set up a test case
  302. # for the current generator.
  303. if (NOT "ninja" IN_LIST CMake_TEST_MODULE_COMPILATION)
  304. return ()
  305. endif ()
  306. # All remaining tests require `bmionly` in order to consume from the `ninja`
  307. # build.
  308. if (NOT "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
  309. return ()
  310. endif ()
  311. function (run_cxx_module_test_ninja directory)
  312. set(RunCMake_GENERATOR "Ninja")
  313. set(RunCMake_CXXModules_NO_TEST 1)
  314. set(RunCMake_CXXModules_INSTALL 1)
  315. # `Ninja` is not a multi-config generator.
  316. set(RunCMake_GENERATOR_IS_MULTI_CONFIG 0)
  317. run_cxx_module_test("${directory}" "${directory}-ninja" ${ARGN})
  318. endfunction ()
  319. # Installation happens within `run_cxx_module_test_ninja`.
  320. set(RunCMake_CXXModules_INSTALL 0)
  321. set(test_set mods-from-ninja)
  322. run_cxx_module_test_ninja("exp-${test_set}")
  323. run_cxx_module_test(imp-mods "imp-${test_set}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/exp-${test_set}-ninja-install" -DFROM_NINJA=1)