RunCMakeTest.cmake 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. include(RunCMake)
  2. # Detect ninja version so we know what tests can be supported.
  3. execute_process(
  4. COMMAND "${RunCMake_MAKE_PROGRAM}" --version
  5. OUTPUT_VARIABLE ninja_out
  6. ERROR_VARIABLE ninja_out
  7. RESULT_VARIABLE ninja_res
  8. OUTPUT_STRIP_TRAILING_WHITESPACE
  9. )
  10. if(ninja_res EQUAL 0 AND "x${ninja_out}" MATCHES "^x[0-9]+\\.[0-9]+")
  11. set(ninja_version "${ninja_out}")
  12. message(STATUS "ninja version: ${ninja_version}")
  13. else()
  14. message(FATAL_ERROR "'ninja --version' reported:\n${ninja_out}")
  15. endif()
  16. function(run_NinjaToolMissing)
  17. set(RunCMake_MAKE_PROGRAM ninja-tool-missing)
  18. run_cmake(NinjaToolMissing)
  19. endfunction()
  20. run_NinjaToolMissing()
  21. function(run_CMP0058 case)
  22. # Use a single build tree for a few tests without cleaning.
  23. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0058-${case}-build)
  24. set(RunCMake_TEST_NO_CLEAN 1)
  25. file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
  26. file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
  27. run_cmake(CMP0058-${case})
  28. run_cmake_command(CMP0058-${case}-build ${CMAKE_COMMAND} --build .)
  29. endfunction()
  30. run_CMP0058(OLD-no)
  31. run_CMP0058(OLD-by)
  32. run_CMP0058(WARN-no)
  33. run_CMP0058(WARN-by)
  34. run_CMP0058(NEW-no)
  35. run_CMP0058(NEW-by)
  36. run_cmake(CustomCommandDepfile)
  37. function(run_CommandConcat)
  38. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommandConcat-build)
  39. set(RunCMake_TEST_NO_CLEAN 1)
  40. file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
  41. file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
  42. run_cmake(CommandConcat)
  43. run_cmake_command(CommandConcat-build ${CMAKE_COMMAND} --build .)
  44. endfunction()
  45. run_CommandConcat()
  46. function(run_SubDir)
  47. # Use a single build tree for a few tests without cleaning.
  48. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build)
  49. set(RunCMake_TEST_NO_CLEAN 1)
  50. file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
  51. file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
  52. run_cmake(SubDir)
  53. if(WIN32)
  54. set(SubDir_all [[SubDir\all]])
  55. set(SubDir_test [[SubDir\test]])
  56. set(SubDir_install [[SubDir\install]])
  57. set(SubDirBinary_test [[SubDirBinary\test]])
  58. set(SubDirBinary_all [[SubDirBinary\all]])
  59. set(SubDirBinary_install [[SubDirBinary\install]])
  60. else()
  61. set(SubDir_all [[SubDir/all]])
  62. set(SubDir_test [[SubDir/test]])
  63. set(SubDir_install [[SubDir/install]])
  64. set(SubDirBinary_all [[SubDirBinary/all]])
  65. set(SubDirBinary_test [[SubDirBinary/test]])
  66. set(SubDirBinary_install [[SubDirBinary/install]])
  67. endif()
  68. run_cmake_command(SubDir-build ${CMAKE_COMMAND} --build . --target ${SubDir_all})
  69. run_cmake_command(SubDir-test ${CMAKE_COMMAND} --build . --target ${SubDir_test})
  70. run_cmake_command(SubDir-install ${CMAKE_COMMAND} --build . --target ${SubDir_install})
  71. run_cmake_command(SubDirBinary-build ${CMAKE_COMMAND} --build . --target ${SubDirBinary_all})
  72. run_cmake_command(SubDirBinary-test ${CMAKE_COMMAND} --build . --target ${SubDirBinary_test})
  73. run_cmake_command(SubDirBinary-install ${CMAKE_COMMAND} --build . --target ${SubDirBinary_install})
  74. endfunction()
  75. run_SubDir()
  76. function(run_ninja dir)
  77. execute_process(
  78. COMMAND "${RunCMake_MAKE_PROGRAM}" ${ARGN}
  79. WORKING_DIRECTORY "${dir}"
  80. OUTPUT_VARIABLE ninja_stdout
  81. ERROR_VARIABLE ninja_stderr
  82. RESULT_VARIABLE ninja_result
  83. )
  84. if(NOT ninja_result EQUAL 0)
  85. message(STATUS "
  86. ============ beginning of ninja's stdout ============
  87. ${ninja_stdout}
  88. =============== end of ninja's stdout ===============
  89. ")
  90. message(STATUS "
  91. ============ beginning of ninja's stderr ============
  92. ${ninja_stderr}
  93. =============== end of ninja's stderr ===============
  94. ")
  95. message(FATAL_ERROR
  96. "top ninja build failed exited with status ${ninja_result}")
  97. endif()
  98. endfunction(run_ninja)
  99. function (run_LooseObjectDepends)
  100. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LooseObjectDepends-build)
  101. run_cmake(LooseObjectDepends)
  102. run_ninja("${RunCMake_TEST_BINARY_DIR}" "CMakeFiles/top.dir/top.c${CMAKE_C_OUTPUT_EXTENSION}")
  103. if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}dep${CMAKE_SHARED_LIBRARY_SUFFIX}")
  104. message(FATAL_ERROR
  105. "The `dep` library was created when requesting an object file to be "
  106. "built; this should no longer be necessary.")
  107. endif ()
  108. if (EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/dep.dir/dep.c${CMAKE_C_OUTPUT_EXTENSION}")
  109. message(FATAL_ERROR
  110. "The `dep.c` object file was created when requesting an object file to "
  111. "be built; this should no longer be necessary.")
  112. endif ()
  113. endfunction ()
  114. run_LooseObjectDepends()
  115. function (run_AssumedSources)
  116. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AssumedSources-build)
  117. run_cmake(AssumedSources)
  118. run_ninja("${RunCMake_TEST_BINARY_DIR}" "target.c")
  119. if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/target.c")
  120. message(FATAL_ERROR
  121. "Dependencies for an assumed source did not hook up properly for 'target.c'.")
  122. endif ()
  123. run_ninja("${RunCMake_TEST_BINARY_DIR}" "target-no-depends.c")
  124. if (EXISTS "${RunCMake_TEST_BINARY_DIR}/target-no-depends.c")
  125. message(FATAL_ERROR
  126. "Dependencies for an assumed source were magically hooked up for 'target-no-depends.c'.")
  127. endif ()
  128. endfunction ()
  129. run_AssumedSources()
  130. function(sleep delay)
  131. execute_process(
  132. COMMAND ${CMAKE_COMMAND} -E sleep ${delay}
  133. RESULT_VARIABLE result
  134. )
  135. if(NOT result EQUAL 0)
  136. message(FATAL_ERROR "failed to sleep for ${delay} second.")
  137. endif()
  138. endfunction(sleep)
  139. function(touch path)
  140. execute_process(
  141. COMMAND ${CMAKE_COMMAND} -E touch ${path}
  142. RESULT_VARIABLE result
  143. )
  144. if(NOT result EQUAL 0)
  145. message(FATAL_ERROR "failed to touch main ${path} file.")
  146. endif()
  147. endfunction(touch)
  148. macro(ninja_escape_path path out)
  149. string(REPLACE "\$ " "\$\$" "${out}" "${path}")
  150. string(REPLACE " " "\$ " "${out}" "${${out}}")
  151. string(REPLACE ":" "\$:" "${out}" "${${out}}")
  152. endmacro(ninja_escape_path)
  153. macro(shell_escape string out)
  154. string(REPLACE "\"" "\\\"" "${out}" "${string}")
  155. endmacro(shell_escape)
  156. function(run_sub_cmake test ninja_output_path_prefix)
  157. set(top_build_dir "${RunCMake_BINARY_DIR}/${test}-build/")
  158. file(REMOVE_RECURSE "${top_build_dir}")
  159. file(MAKE_DIRECTORY "${top_build_dir}")
  160. ninja_escape_path("${ninja_output_path_prefix}"
  161. escaped_ninja_output_path_prefix)
  162. # Generate top build ninja file.
  163. set(top_build_ninja "${top_build_dir}/build.ninja")
  164. shell_escape("${top_build_ninja}" escaped_top_build_ninja)
  165. set(build_ninja_dep "${top_build_dir}/build_ninja_dep")
  166. ninja_escape_path("${build_ninja_dep}" escaped_build_ninja_dep)
  167. shell_escape("${CMAKE_COMMAND}" escaped_CMAKE_COMMAND)
  168. file(WRITE "${build_ninja_dep}" "fake dependency of top build.ninja file\n")
  169. if(WIN32)
  170. set(cmd_prefix "cmd.exe /C \"")
  171. set(cmd_suffix "\"")
  172. else()
  173. set(cmd_prefix "")
  174. set(cmd_suffix "")
  175. endif()
  176. file(WRITE "${top_build_ninja}" "\
  177. subninja ${escaped_ninja_output_path_prefix}/build.ninja
  178. default ${escaped_ninja_output_path_prefix}/all
  179. # Sleep for 1 second before to regenerate to make sure the timestamp of
  180. # the top build.ninja will be strictly greater than the timestamp of the
  181. # sub/build.ninja file. We assume the system as 1 sec timestamp resolution.
  182. rule RERUN
  183. command = ${cmd_prefix}\"${escaped_CMAKE_COMMAND}\" -E sleep 1 && \"${escaped_CMAKE_COMMAND}\" -E touch \"${escaped_top_build_ninja}\"${cmd_suffix}
  184. description = Testing regeneration
  185. generator = 1
  186. build build.ninja: RERUN ${escaped_build_ninja_dep} || ${escaped_ninja_output_path_prefix}/build.ninja
  187. pool = console
  188. ")
  189. # Run sub cmake project.
  190. set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_OUTPUT_PATH_PREFIX=${ninja_output_path_prefix}")
  191. set(RunCMake_TEST_BINARY_DIR "${top_build_dir}/${ninja_output_path_prefix}")
  192. run_cmake(${test})
  193. # Check there is no 'default' statement in Ninja file generated by CMake.
  194. set(sub_build_ninja "${RunCMake_TEST_BINARY_DIR}/build.ninja")
  195. file(READ "${sub_build_ninja}" sub_build_ninja_file)
  196. if(sub_build_ninja_file MATCHES "\ndefault [^\n][^\n]*all\n")
  197. message(FATAL_ERROR
  198. "unexpected 'default' statement found in '${sub_build_ninja}'")
  199. endif()
  200. # Run ninja from the top build directory.
  201. run_ninja("${top_build_dir}")
  202. # Test regeneration rules run in order.
  203. set(main_cmakelists "${RunCMake_SOURCE_DIR}/CMakeLists.txt")
  204. sleep(1) # Assume the system as 1 sec timestamp resolution.
  205. touch("${main_cmakelists}")
  206. touch("${build_ninja_dep}")
  207. run_ninja("${top_build_dir}")
  208. file(TIMESTAMP "${main_cmakelists}" mtime_main_cmakelists UTC)
  209. file(TIMESTAMP "${sub_build_ninja}" mtime_sub_build_ninja UTC)
  210. file(TIMESTAMP "${top_build_ninja}" mtime_top_build_ninja UTC)
  211. # Check sub build.ninja is regenerated.
  212. if(mtime_main_cmakelists STRGREATER mtime_sub_build_ninja)
  213. message(FATAL_ERROR
  214. "sub build.ninja not regenerated:
  215. CMakeLists.txt = ${mtime_main_cmakelists}
  216. sub/build.ninja = ${mtime_sub_build_ninja}")
  217. endif()
  218. # Check top build.ninja is regenerated after sub build.ninja.
  219. if(NOT mtime_top_build_ninja STRGREATER mtime_sub_build_ninja)
  220. message(FATAL_ERROR
  221. "top build.ninja not regenerated strictly after sub build.ninja:
  222. sub/build.ninja = ${mtime_sub_build_ninja}
  223. build.ninja = ${mtime_top_build_ninja}")
  224. endif()
  225. endfunction(run_sub_cmake)
  226. if("${ninja_version}" VERSION_LESS 1.6)
  227. message(WARNING "Ninja is too old; skipping rest of test.")
  228. return()
  229. endif()
  230. foreach(ninja_output_path_prefix "sub space" "sub")
  231. run_sub_cmake(Executable "${ninja_output_path_prefix}")
  232. run_sub_cmake(StaticLib "${ninja_output_path_prefix}")
  233. run_sub_cmake(SharedLib "${ninja_output_path_prefix}")
  234. run_sub_cmake(TwoLibs "${ninja_output_path_prefix}")
  235. run_sub_cmake(SubDirPrefix "${ninja_output_path_prefix}")
  236. run_sub_cmake(CustomCommandWorkingDirectory "${ninja_output_path_prefix}")
  237. endforeach(ninja_output_path_prefix)