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