Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Tests / RunCMake / Ninja / RunCMakeTest.cmake
1 include(RunCMake)
2
3 set(RunCMake_GENERATOR "Ninja")
4 set(RunCMake_GENERATOR_IS_MULTI_CONFIG 0)
5
6 # Detect ninja version so we know what tests can be supported.
7 execute_process(
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
13   )
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}")
17 else()
18   message(FATAL_ERROR "'ninja --version' reported:\n${ninja_out}")
19 endif()
20
21 # Sanitize NINJA_STATUS since we expect default behavior.
22 unset(ENV{NINJA_STATUS})
23
24 if(CMAKE_HOST_WIN32)
25   run_cmake(SelectCompilerWindows)
26 else()
27   run_cmake(SelectCompilerUNIX)
28 endif()
29
30 function(run_NinjaToolMissing)
31   set(RunCMake_MAKE_PROGRAM ninja-tool-missing)
32   run_cmake(NinjaToolMissing)
33 endfunction()
34 run_NinjaToolMissing()
35
36 function(run_Intl)
37   run_cmake(Intl)
38   set(RunCMake_TEST_NO_CLEAN 1)
39   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Intl-build)
40   set(RunCMake_TEST_OUTPUT_MERGE 1)
41   run_cmake_command(Intl-build ${CMAKE_COMMAND} --build .)
42 endfunction()
43 run_Intl()
44
45 if(WIN32)
46   if(RunCMake_MAKE_PROGRAM)
47     set(maybe_MAKE_PROGRAM "-DRunCMake_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}")
48   endif()
49   run_cmake_script(ShowIncludes-54936 -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
50   run_cmake_script(ShowIncludes-65001 -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
51   unset(maybe_MAKE_PROGRAM)
52 endif()
53
54 function(run_NoWorkToDo)
55   run_cmake(NoWorkToDo)
56   set(RunCMake_TEST_NO_CLEAN 1)
57   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/NoWorkToDo-build)
58   set(RunCMake_TEST_OUTPUT_MERGE 1)
59   run_cmake_command(NoWorkToDo-build ${CMAKE_COMMAND} --build .)
60   run_cmake_command(NoWorkToDo-nowork ${CMAKE_COMMAND} --build . -- -d explain)
61 endfunction()
62 run_NoWorkToDo()
63
64 function(run_VerboseBuild)
65   run_cmake(VerboseBuild)
66   set(RunCMake_TEST_NO_CLEAN 1)
67   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VerboseBuild-build)
68   set(RunCMake_TEST_OUTPUT_MERGE 1)
69   run_cmake_command(VerboseBuild-build ${CMAKE_COMMAND} --build . -v --clean-first)
70   run_cmake_command(VerboseBuild-nowork ${CMAKE_COMMAND} --build . --verbose)
71 endfunction()
72 run_VerboseBuild()
73
74 function(run_CMP0058 case)
75   # Use a single build tree for a few tests without cleaning.
76   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0058-${case}-build)
77   set(RunCMake_TEST_NO_CLEAN 1)
78   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
79   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
80   run_cmake(CMP0058-${case})
81   run_cmake_command(CMP0058-${case}-build ${CMAKE_COMMAND} --build .)
82 endfunction()
83
84 run_CMP0058(OLD-no)
85 run_CMP0058(OLD-by)
86 run_CMP0058(WARN-no)
87 run_CMP0058(WARN-by)
88 run_CMP0058(NEW-no)
89 run_CMP0058(NEW-by)
90
91 run_cmake_with_options(CustomCommandDepfile -DCMAKE_BUILD_TYPE=Debug)
92 run_cmake(CustomCommandJobPool)
93 run_cmake(JobPoolUsesTerminal)
94
95 run_cmake(RspFileC)
96 run_cmake(RspFileCXX)
97 if(TEST_Fortran)
98   run_cmake(RspFileFortran)
99 endif()
100
101 function(run_CommandConcat)
102   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommandConcat-build)
103   set(RunCMake_TEST_NO_CLEAN 1)
104   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
105   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
106   run_cmake(CommandConcat)
107   run_cmake_command(CommandConcat-build ${CMAKE_COMMAND} --build .)
108 endfunction()
109 run_CommandConcat()
110
111 function(run_SubDir)
112   # Use a single build tree for a few tests without cleaning.
113   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build)
114   set(RunCMake_TEST_NO_CLEAN 1)
115   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
116   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
117   run_cmake(SubDir)
118   if(WIN32)
119     set(SubDir_all [[SubDir\all]])
120     set(SubDir_test [[SubDir\test]])
121     set(SubDir_install [[SubDir\install]])
122     set(SubDirBinary_test [[SubDirBinary\test]])
123     set(SubDirBinary_all [[SubDirBinary\all]])
124     set(SubDirBinary_install [[SubDirBinary\install]])
125   else()
126     set(SubDir_all [[SubDir/all]])
127     set(SubDir_test [[SubDir/test]])
128     set(SubDir_install [[SubDir/install]])
129     set(SubDirBinary_all [[SubDirBinary/all]])
130     set(SubDirBinary_test [[SubDirBinary/test]])
131     set(SubDirBinary_install [[SubDirBinary/install]])
132   endif()
133   run_cmake_command(SubDir-build ${CMAKE_COMMAND} --build . --target ${SubDir_all})
134   run_cmake_command(SubDir-test ${CMAKE_COMMAND} --build . --target ${SubDir_test})
135   run_cmake_command(SubDir-install ${CMAKE_COMMAND} --build . --target ${SubDir_install})
136   run_cmake_command(SubDirBinary-build ${CMAKE_COMMAND} --build . --target ${SubDirBinary_all})
137   run_cmake_command(SubDirBinary-test ${CMAKE_COMMAND} --build . --target ${SubDirBinary_test})
138   run_cmake_command(SubDirBinary-install ${CMAKE_COMMAND} --build . --target ${SubDirBinary_install})
139 endfunction()
140 run_SubDir()
141
142 function(run_ninja dir)
143   execute_process(
144     COMMAND "${RunCMake_MAKE_PROGRAM}" ${ARGN}
145     WORKING_DIRECTORY "${dir}"
146     OUTPUT_VARIABLE ninja_stdout
147     ERROR_VARIABLE ninja_stderr
148     RESULT_VARIABLE ninja_result
149     )
150   if(NOT ninja_result EQUAL 0)
151     message(STATUS "
152 ============ beginning of ninja's stdout ============
153 ${ninja_stdout}
154 =============== end of ninja's stdout ===============
155 ")
156     message(STATUS "
157 ============ beginning of ninja's stderr ============
158 ${ninja_stderr}
159 =============== end of ninja's stderr ===============
160 ")
161     message(FATAL_ERROR
162       "top ninja build failed exited with status ${ninja_result}")
163   endif()
164   set(ninja_stdout "${ninja_stdout}" PARENT_SCOPE)
165 endfunction(run_ninja)
166
167 function (run_LooseObjectDepends)
168   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LooseObjectDepends-build)
169   run_cmake(LooseObjectDepends)
170   run_ninja("${RunCMake_TEST_BINARY_DIR}" "CMakeFiles/top.dir/top.c${CMAKE_C_OUTPUT_EXTENSION}")
171   if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}dep${CMAKE_SHARED_LIBRARY_SUFFIX}")
172     message(FATAL_ERROR
173       "The `dep` library was created when requesting an object file to be "
174       "built; this should no longer be necessary.")
175   endif ()
176   if (EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/dep.dir/dep.c${CMAKE_C_OUTPUT_EXTENSION}")
177     message(FATAL_ERROR
178       "The `dep.c` object file was created when requesting an object file to "
179       "be built; this should no longer be necessary.")
180   endif ()
181 endfunction ()
182 run_LooseObjectDepends()
183
184 function (run_AssumedSources)
185   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AssumedSources-build)
186   run_cmake(AssumedSources)
187   run_ninja("${RunCMake_TEST_BINARY_DIR}" "${RunCMake_TEST_BINARY_DIR}/target.c")
188   if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/target.c")
189     message(FATAL_ERROR
190       "Dependencies for an assumed source did not hook up properly for 'target.c'.")
191   endif ()
192   run_ninja("${RunCMake_TEST_BINARY_DIR}" "${RunCMake_TEST_BINARY_DIR}/target-no-depends.c")
193   if (EXISTS "${RunCMake_TEST_BINARY_DIR}/target-no-depends.c")
194     message(FATAL_ERROR
195       "Dependencies for an assumed source were magically hooked up for 'target-no-depends.c'.")
196   endif ()
197 endfunction ()
198 run_AssumedSources()
199
200 function(sleep delay)
201   execute_process(
202     COMMAND ${CMAKE_COMMAND} -E sleep ${delay}
203     RESULT_VARIABLE result
204     )
205   if(NOT result EQUAL 0)
206     message(FATAL_ERROR "failed to sleep for ${delay} second.")
207   endif()
208 endfunction(sleep)
209
210 macro(ninja_escape_path path out)
211   string(REPLACE "\$ " "\$\$" "${out}" "${path}")
212   string(REPLACE " " "\$ " "${out}" "${${out}}")
213   string(REPLACE ":" "\$:" "${out}" "${${out}}")
214 endmacro(ninja_escape_path)
215
216 macro(shell_escape string out)
217   string(REPLACE "\"" "\\\"" "${out}" "${string}")
218 endmacro(shell_escape)
219
220 function(run_sub_cmake test ninja_output_path_prefix)
221   set(top_build_dir "${RunCMake_BINARY_DIR}/${test}-build/")
222   file(REMOVE_RECURSE "${top_build_dir}")
223   file(MAKE_DIRECTORY "${top_build_dir}")
224
225   ninja_escape_path("${ninja_output_path_prefix}"
226     escaped_ninja_output_path_prefix)
227
228   # Generate top build ninja file.
229   set(top_build_ninja "${top_build_dir}/build.ninja")
230   shell_escape("${top_build_ninja}" escaped_top_build_ninja)
231   set(build_ninja_dep "${top_build_dir}/build_ninja_dep")
232   ninja_escape_path("${build_ninja_dep}" escaped_build_ninja_dep)
233   shell_escape("${CMAKE_COMMAND}" escaped_CMAKE_COMMAND)
234   file(WRITE "${build_ninja_dep}" "fake dependency of top build.ninja file\n")
235   if(WIN32)
236     set(cmd_prefix "cmd.exe /C \"")
237     set(cmd_suffix "\"")
238   else()
239     set(cmd_prefix "")
240     set(cmd_suffix "")
241   endif()
242   set(fs_delay 3) # We assume the system as 1 sec timestamp resolution.
243   file(WRITE "${top_build_ninja}" "\
244 subninja ${escaped_ninja_output_path_prefix}/build.ninja
245 default ${escaped_ninja_output_path_prefix}/all
246
247 # Sleep for long enough before regenerating to make sure the timestamp of
248 # the top build.ninja will be strictly greater than the timestamp of the
249 # sub/build.ninja file.
250 rule RERUN
251   command = ${cmd_prefix}\"${escaped_CMAKE_COMMAND}\" -E sleep ${fs_delay} && \"${escaped_CMAKE_COMMAND}\" -E touch \"${escaped_top_build_ninja}\"${cmd_suffix}
252   description = Testing regeneration
253   generator = 1
254
255 build build.ninja: RERUN ${escaped_build_ninja_dep} || ${escaped_ninja_output_path_prefix}/build.ninja
256   pool = console
257 ")
258
259   # Run sub cmake project.
260   set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_OUTPUT_PATH_PREFIX=${ninja_output_path_prefix}")
261   set(RunCMake_TEST_BINARY_DIR "${top_build_dir}/${ninja_output_path_prefix}")
262   run_cmake(${test})
263
264   # Check there is no 'default' statement in Ninja file generated by CMake.
265   set(sub_build_ninja "${RunCMake_TEST_BINARY_DIR}/build.ninja")
266   file(READ "${sub_build_ninja}" sub_build_ninja_file)
267   if(sub_build_ninja_file MATCHES "\ndefault [^\n][^\n]*all\n")
268     message(FATAL_ERROR
269       "unexpected 'default' statement found in '${sub_build_ninja}'")
270   endif()
271
272   # Run ninja from the top build directory.
273   run_ninja("${top_build_dir}")
274
275   # Test regeneration rules run in order.
276   set(main_cmakelists "${RunCMake_SOURCE_DIR}/CMakeLists.txt")
277   sleep(${fs_delay})
278   file(TOUCH "${main_cmakelists}")
279   file(TOUCH "${build_ninja_dep}")
280   run_ninja("${top_build_dir}")
281   file(TIMESTAMP "${main_cmakelists}" mtime_main_cmakelists UTC)
282   file(TIMESTAMP "${sub_build_ninja}" mtime_sub_build_ninja UTC)
283   file(TIMESTAMP "${top_build_ninja}" mtime_top_build_ninja UTC)
284
285   # Check sub build.ninja is regenerated.
286   if(mtime_main_cmakelists STRGREATER mtime_sub_build_ninja)
287     message(FATAL_ERROR
288       "sub build.ninja not regenerated:
289   CMakeLists.txt  = ${mtime_main_cmakelists}
290   sub/build.ninja = ${mtime_sub_build_ninja}")
291   endif()
292
293   # Check top build.ninja is regenerated after sub build.ninja.
294   if(NOT mtime_top_build_ninja STRGREATER mtime_sub_build_ninja)
295     message(FATAL_ERROR
296       "top build.ninja not regenerated strictly after sub build.ninja:
297   sub/build.ninja = ${mtime_sub_build_ninja}
298   build.ninja     = ${mtime_top_build_ninja}")
299   endif()
300
301 endfunction(run_sub_cmake)
302
303 if("${ninja_version}" VERSION_LESS 1.6)
304   message(WARNING "Ninja is too old; skipping rest of test.")
305   return()
306 endif()
307
308 foreach(ninja_output_path_prefix "sub space" "sub")
309   run_sub_cmake(Executable "${ninja_output_path_prefix}")
310   run_sub_cmake(StaticLib  "${ninja_output_path_prefix}")
311   run_sub_cmake(SharedLib "${ninja_output_path_prefix}")
312   run_sub_cmake(TwoLibs "${ninja_output_path_prefix}")
313   run_sub_cmake(SubDirPrefix "${ninja_output_path_prefix}")
314   run_sub_cmake(CustomCommandWorkingDirectory "${ninja_output_path_prefix}")
315 endforeach(ninja_output_path_prefix)
316
317 function (run_PreventTargetAliasesDupBuildRule)
318   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PreventTargetAliasesDupBuildRule-build)
319   run_cmake(PreventTargetAliasesDupBuildRule)
320   run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
321 endfunction ()
322 run_PreventTargetAliasesDupBuildRule()
323
324 function (run_PreventConfigureFileDupBuildRule)
325   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PreventConfigureFileDupBuildRule-build)
326   run_cmake(PreventConfigureFileDupBuildRule)
327   run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
328 endfunction()
329 run_PreventConfigureFileDupBuildRule()
330
331 function (run_ChangeBuildType)
332   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ChangeBuildType-build)
333   set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=Debug")
334   run_cmake(ChangeBuildType)
335   unset(RunCMake_TEST_OPTIONS)
336   run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
337 endfunction()
338 run_ChangeBuildType()
339
340 function(run_QtAutoMocDeps)
341   set(QtX Qt${CMake_TEST_Qt_version})
342   if(CMake_TEST_${QtX}Core_Version VERSION_GREATER_EQUAL 5.15.0)
343     set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/QtAutoMocDeps-build)
344     run_cmake_with_options(QtAutoMocDeps
345       "-Dwith_qt_version=${CMake_TEST_Qt_version}"
346       "-D${QtX}_DIR=${${QtX}_DIR}"
347       "-D${QtX}Core_DIR=${${QtX}Core_DIR}"
348       "-D${QtX}Widgets_DIR=${${QtX}Widgets_DIR}"
349       "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
350     )
351     # Build the project.
352     run_ninja("${RunCMake_TEST_BINARY_DIR}")
353     # Touch just the library source file, which shouldn't cause a rerun of AUTOMOC
354     # for app_with_qt target.
355     file(TOUCH "${RunCMake_SOURCE_DIR}/simple_lib.cpp")
356     # Build and assert that AUTOMOC was not run for app_with_qt.
357     run_ninja("${RunCMake_TEST_BINARY_DIR}")
358     if(ninja_stdout MATCHES "Automatic MOC for target app_with_qt")
359       message(FATAL_ERROR
360         "AUTOMOC should not have executed for 'app_with_qt' target:\nstdout:\n${ninja_stdout}")
361     endif()
362     # Assert that the subdir executables were not rebuilt.
363     if(ninja_stdout MATCHES "Automatic MOC for target sub_exe_1")
364       message(FATAL_ERROR
365         "AUTOMOC should not have executed for 'sub_exe_1' target:\nstdout:\n${ninja_stdout}")
366     endif()
367     if(ninja_stdout MATCHES "Automatic MOC for target sub_exe_2")
368       message(FATAL_ERROR
369         "AUTOMOC should not have executed for 'sub_exe_2' target:\nstdout:\n${ninja_stdout}")
370     endif()
371     # Touch a header file to make sure an automoc dependency cycle is not introduced.
372     file(TOUCH "${RunCMake_SOURCE_DIR}/MyWindow.h")
373     run_ninja("${RunCMake_TEST_BINARY_DIR}")
374     # Need to run a second time to hit the dependency cycle.
375     run_ninja("${RunCMake_TEST_BINARY_DIR}")
376   endif()
377 endfunction()
378
379 function(run_QtAutoMocSkipPch)
380   set(QtX Qt${CMake_TEST_Qt_version})
381   if(CMake_TEST_${QtX}Core_Version VERSION_GREATER_EQUAL 5.15.0)
382     set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/QtAutoMocSkipPch-build)
383     run_cmake_with_options(QtAutoMocSkipPch
384       "-Dwith_qt_version=${CMake_TEST_Qt_version}"
385       "-D${QtX}_DIR=${${QtX}_DIR}"
386       "-D${QtX}Core_DIR=${${QtX}Core_DIR}"
387       "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
388     )
389     # Build the project.
390     run_ninja("${RunCMake_TEST_BINARY_DIR}")
391   endif()
392 endfunction()
393 if(CMake_TEST_Qt_version)
394   run_QtAutoMocDeps()
395   run_QtAutoMocSkipPch()
396 endif()