3 set(RunCMake_GENERATOR "Ninja")
4 set(RunCMake_GENERATOR_IS_MULTI_CONFIG 0)
6 # Detect ninja version so we know what tests can be supported.
8 COMMAND "${RunCMake_MAKE_PROGRAM}" --version
9 OUTPUT_VARIABLE ninja_out
10 ERROR_VARIABLE ninja_out
11 RESULT_VARIABLE ninja_res
12 OUTPUT_STRIP_TRAILING_WHITESPACE
14 if(ninja_res EQUAL 0 AND "x${ninja_out}" MATCHES "^x[0-9]+\\.[0-9]+")
15 set(ninja_version "${ninja_out}")
16 message(STATUS "ninja version: ${ninja_version}")
18 message(FATAL_ERROR "'ninja --version' reported:\n${ninja_out}")
22 run_cmake(SelectCompilerWindows)
24 run_cmake(SelectCompilerUNIX)
27 function(run_NinjaToolMissing)
28 set(RunCMake_MAKE_PROGRAM ninja-tool-missing)
29 run_cmake(NinjaToolMissing)
31 run_NinjaToolMissing()
33 function(run_NoWorkToDo)
35 set(RunCMake_TEST_NO_CLEAN 1)
36 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/NoWorkToDo-build)
37 run_cmake_command(NoWorkToDo-build ${CMAKE_COMMAND} --build .)
38 run_cmake_command(NoWorkToDo-nowork ${CMAKE_COMMAND} --build . -- -d explain)
42 function(run_VerboseBuild)
43 run_cmake(VerboseBuild)
44 set(RunCMake_TEST_NO_CLEAN 1)
45 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VerboseBuild-build)
46 run_cmake_command(VerboseBuild-build ${CMAKE_COMMAND} --build . -v --clean-first)
47 run_cmake_command(VerboseBuild-nowork ${CMAKE_COMMAND} --build . --verbose)
51 function(run_CMP0058 case)
52 # Use a single build tree for a few tests without cleaning.
53 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0058-${case}-build)
54 set(RunCMake_TEST_NO_CLEAN 1)
55 file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
56 file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
57 run_cmake(CMP0058-${case})
58 run_cmake_command(CMP0058-${case}-build ${CMAKE_COMMAND} --build .)
68 run_cmake(CustomCommandDepfile)
69 run_cmake(CustomCommandJobPool)
70 run_cmake(JobPoolUsesTerminal)
75 run_cmake(RspFileFortran)
78 function(run_CommandConcat)
79 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommandConcat-build)
80 set(RunCMake_TEST_NO_CLEAN 1)
81 file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
82 file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
83 run_cmake(CommandConcat)
84 run_cmake_command(CommandConcat-build ${CMAKE_COMMAND} --build .)
89 # Use a single build tree for a few tests without cleaning.
90 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build)
91 set(RunCMake_TEST_NO_CLEAN 1)
92 file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
93 file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
96 set(SubDir_all [[SubDir\all]])
97 set(SubDir_test [[SubDir\test]])
98 set(SubDir_install [[SubDir\install]])
99 set(SubDirBinary_test [[SubDirBinary\test]])
100 set(SubDirBinary_all [[SubDirBinary\all]])
101 set(SubDirBinary_install [[SubDirBinary\install]])
103 set(SubDir_all [[SubDir/all]])
104 set(SubDir_test [[SubDir/test]])
105 set(SubDir_install [[SubDir/install]])
106 set(SubDirBinary_all [[SubDirBinary/all]])
107 set(SubDirBinary_test [[SubDirBinary/test]])
108 set(SubDirBinary_install [[SubDirBinary/install]])
110 run_cmake_command(SubDir-build ${CMAKE_COMMAND} --build . --target ${SubDir_all})
111 run_cmake_command(SubDir-test ${CMAKE_COMMAND} --build . --target ${SubDir_test})
112 run_cmake_command(SubDir-install ${CMAKE_COMMAND} --build . --target ${SubDir_install})
113 run_cmake_command(SubDirBinary-build ${CMAKE_COMMAND} --build . --target ${SubDirBinary_all})
114 run_cmake_command(SubDirBinary-test ${CMAKE_COMMAND} --build . --target ${SubDirBinary_test})
115 run_cmake_command(SubDirBinary-install ${CMAKE_COMMAND} --build . --target ${SubDirBinary_install})
119 function(run_ninja dir)
121 COMMAND "${RunCMake_MAKE_PROGRAM}" ${ARGN}
122 WORKING_DIRECTORY "${dir}"
123 OUTPUT_VARIABLE ninja_stdout
124 ERROR_VARIABLE ninja_stderr
125 RESULT_VARIABLE ninja_result
127 if(NOT ninja_result EQUAL 0)
129 ============ beginning of ninja's stdout ============
131 =============== end of ninja's stdout ===============
134 ============ beginning of ninja's stderr ============
136 =============== end of ninja's stderr ===============
139 "top ninja build failed exited with status ${ninja_result}")
141 set(ninja_stdout "${ninja_stdout}" PARENT_SCOPE)
142 endfunction(run_ninja)
144 function (run_LooseObjectDepends)
145 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LooseObjectDepends-build)
146 run_cmake(LooseObjectDepends)
147 run_ninja("${RunCMake_TEST_BINARY_DIR}" "CMakeFiles/top.dir/top.c${CMAKE_C_OUTPUT_EXTENSION}")
148 if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}dep${CMAKE_SHARED_LIBRARY_SUFFIX}")
150 "The `dep` library was created when requesting an object file to be "
151 "built; this should no longer be necessary.")
153 if (EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/dep.dir/dep.c${CMAKE_C_OUTPUT_EXTENSION}")
155 "The `dep.c` object file was created when requesting an object file to "
156 "be built; this should no longer be necessary.")
159 run_LooseObjectDepends()
161 function (run_AssumedSources)
162 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AssumedSources-build)
163 run_cmake(AssumedSources)
164 run_ninja("${RunCMake_TEST_BINARY_DIR}" "target.c")
165 if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/target.c")
167 "Dependencies for an assumed source did not hook up properly for 'target.c'.")
169 run_ninja("${RunCMake_TEST_BINARY_DIR}" "target-no-depends.c")
170 if (EXISTS "${RunCMake_TEST_BINARY_DIR}/target-no-depends.c")
172 "Dependencies for an assumed source were magically hooked up for 'target-no-depends.c'.")
177 function(sleep delay)
179 COMMAND ${CMAKE_COMMAND} -E sleep ${delay}
180 RESULT_VARIABLE result
182 if(NOT result EQUAL 0)
183 message(FATAL_ERROR "failed to sleep for ${delay} second.")
189 COMMAND ${CMAKE_COMMAND} -E touch ${path}
190 RESULT_VARIABLE result
192 if(NOT result EQUAL 0)
193 message(FATAL_ERROR "failed to touch main ${path} file.")
197 macro(ninja_escape_path path out)
198 string(REPLACE "\$ " "\$\$" "${out}" "${path}")
199 string(REPLACE " " "\$ " "${out}" "${${out}}")
200 string(REPLACE ":" "\$:" "${out}" "${${out}}")
201 endmacro(ninja_escape_path)
203 macro(shell_escape string out)
204 string(REPLACE "\"" "\\\"" "${out}" "${string}")
205 endmacro(shell_escape)
207 function(run_sub_cmake test ninja_output_path_prefix)
208 set(top_build_dir "${RunCMake_BINARY_DIR}/${test}-build/")
209 file(REMOVE_RECURSE "${top_build_dir}")
210 file(MAKE_DIRECTORY "${top_build_dir}")
212 ninja_escape_path("${ninja_output_path_prefix}"
213 escaped_ninja_output_path_prefix)
215 # Generate top build ninja file.
216 set(top_build_ninja "${top_build_dir}/build.ninja")
217 shell_escape("${top_build_ninja}" escaped_top_build_ninja)
218 set(build_ninja_dep "${top_build_dir}/build_ninja_dep")
219 ninja_escape_path("${build_ninja_dep}" escaped_build_ninja_dep)
220 shell_escape("${CMAKE_COMMAND}" escaped_CMAKE_COMMAND)
221 file(WRITE "${build_ninja_dep}" "fake dependency of top build.ninja file\n")
223 set(cmd_prefix "cmd.exe /C \"")
229 set(fs_delay 3) # We assume the system as 1 sec timestamp resolution.
230 file(WRITE "${top_build_ninja}" "\
231 subninja ${escaped_ninja_output_path_prefix}/build.ninja
232 default ${escaped_ninja_output_path_prefix}/all
234 # Sleep for long enough before regenerating to make sure the timestamp of
235 # the top build.ninja will be strictly greater than the timestamp of the
236 # sub/build.ninja file.
238 command = ${cmd_prefix}\"${escaped_CMAKE_COMMAND}\" -E sleep ${fs_delay} && \"${escaped_CMAKE_COMMAND}\" -E touch \"${escaped_top_build_ninja}\"${cmd_suffix}
239 description = Testing regeneration
242 build build.ninja: RERUN ${escaped_build_ninja_dep} || ${escaped_ninja_output_path_prefix}/build.ninja
246 # Run sub cmake project.
247 set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_OUTPUT_PATH_PREFIX=${ninja_output_path_prefix}")
248 set(RunCMake_TEST_BINARY_DIR "${top_build_dir}/${ninja_output_path_prefix}")
251 # Check there is no 'default' statement in Ninja file generated by CMake.
252 set(sub_build_ninja "${RunCMake_TEST_BINARY_DIR}/build.ninja")
253 file(READ "${sub_build_ninja}" sub_build_ninja_file)
254 if(sub_build_ninja_file MATCHES "\ndefault [^\n][^\n]*all\n")
256 "unexpected 'default' statement found in '${sub_build_ninja}'")
259 # Run ninja from the top build directory.
260 run_ninja("${top_build_dir}")
262 # Test regeneration rules run in order.
263 set(main_cmakelists "${RunCMake_SOURCE_DIR}/CMakeLists.txt")
265 touch("${main_cmakelists}")
266 touch("${build_ninja_dep}")
267 run_ninja("${top_build_dir}")
268 file(TIMESTAMP "${main_cmakelists}" mtime_main_cmakelists UTC)
269 file(TIMESTAMP "${sub_build_ninja}" mtime_sub_build_ninja UTC)
270 file(TIMESTAMP "${top_build_ninja}" mtime_top_build_ninja UTC)
272 # Check sub build.ninja is regenerated.
273 if(mtime_main_cmakelists STRGREATER mtime_sub_build_ninja)
275 "sub build.ninja not regenerated:
276 CMakeLists.txt = ${mtime_main_cmakelists}
277 sub/build.ninja = ${mtime_sub_build_ninja}")
280 # Check top build.ninja is regenerated after sub build.ninja.
281 if(NOT mtime_top_build_ninja STRGREATER mtime_sub_build_ninja)
283 "top build.ninja not regenerated strictly after sub build.ninja:
284 sub/build.ninja = ${mtime_sub_build_ninja}
285 build.ninja = ${mtime_top_build_ninja}")
288 endfunction(run_sub_cmake)
290 if("${ninja_version}" VERSION_LESS 1.6)
291 message(WARNING "Ninja is too old; skipping rest of test.")
295 foreach(ninja_output_path_prefix "sub space" "sub")
296 run_sub_cmake(Executable "${ninja_output_path_prefix}")
297 run_sub_cmake(StaticLib "${ninja_output_path_prefix}")
298 run_sub_cmake(SharedLib "${ninja_output_path_prefix}")
299 run_sub_cmake(TwoLibs "${ninja_output_path_prefix}")
300 run_sub_cmake(SubDirPrefix "${ninja_output_path_prefix}")
301 run_sub_cmake(CustomCommandWorkingDirectory "${ninja_output_path_prefix}")
302 endforeach(ninja_output_path_prefix)
304 function (run_PreventTargetAliasesDupBuildRule)
305 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PreventTargetAliasesDupBuildRule-build)
306 run_cmake(PreventTargetAliasesDupBuildRule)
307 run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
309 run_PreventTargetAliasesDupBuildRule()
311 function (run_PreventConfigureFileDupBuildRule)
312 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PreventConfigureFileDupBuildRule-build)
313 run_cmake(PreventConfigureFileDupBuildRule)
314 run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
316 run_PreventConfigureFileDupBuildRule()
318 function (run_ChangeBuildType)
319 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ChangeBuildType-build)
320 set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=Debug")
321 run_cmake(ChangeBuildType)
322 unset(RunCMake_TEST_OPTIONS)
323 run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
325 run_ChangeBuildType()
327 function(run_Qt5AutoMocDeps)
328 if(CMake_TEST_Qt5 AND CMAKE_TEST_Qt5Core_Version VERSION_GREATER_EQUAL 5.15.0)
329 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Qt5AutoMocDeps-build)
330 run_cmake(Qt5AutoMocDeps)
331 unset(RunCMake_TEST_OPTIONS)
333 run_ninja("${RunCMake_TEST_BINARY_DIR}")
334 # Touch just the library source file, which shouldn't cause a rerun of AUTOMOC
335 # for app_with_qt target.
336 touch("${RunCMake_SOURCE_DIR}/simple_lib.cpp")
337 # Build and assert that AUTOMOC was not run for app_with_qt.
338 run_ninja("${RunCMake_TEST_BINARY_DIR}")
339 if(ninja_stdout MATCHES "Automatic MOC for target app_with_qt")
341 "AUTOMOC should not have executed for 'app_with_qt' target:\nstdout:\n${ninja_stdout}")