|
|
|
include(RunCMake)
|
|
|
|
|
|
|
|
set(RunCMake_GENERATOR "Ninja")
|
|
|
|
set(RunCMake_GENERATOR_IS_MULTI_CONFIG 0)
|
|
|
|
|
|
|
|
# Detect ninja version so we know what tests can be supported.
|
|
|
|
execute_process(
|
|
|
|
COMMAND "${RunCMake_MAKE_PROGRAM}" --version
|
|
|
|
OUTPUT_VARIABLE ninja_out
|
|
|
|
ERROR_VARIABLE ninja_out
|
|
|
|
RESULT_VARIABLE ninja_res
|
|
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
|
|
)
|
|
|
|
if(ninja_res EQUAL 0 AND "x${ninja_out}" MATCHES "^x[0-9]+\\.[0-9]+")
|
|
|
|
set(ninja_version "${ninja_out}")
|
|
|
|
message(STATUS "ninja version: ${ninja_version}")
|
|
|
|
else()
|
|
|
|
message(FATAL_ERROR "'ninja --version' reported:\n${ninja_out}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Sanitize NINJA_STATUS since we expect default behavior.
|
|
|
|
unset(ENV{NINJA_STATUS})
|
|
|
|
|
|
|
|
if(CMAKE_HOST_WIN32)
|
|
|
|
run_cmake(SelectCompilerWindows)
|
|
|
|
else()
|
|
|
|
run_cmake(SelectCompilerUNIX)
|
|
|
|
endif()
|
|
|
|
|
|
|
|
function(run_NinjaToolMissing)
|
|
|
|
set(RunCMake_MAKE_PROGRAM ninja-tool-missing)
|
|
|
|
run_cmake(NinjaToolMissing)
|
|
|
|
endfunction()
|
|
|
|
run_NinjaToolMissing()
|
|
|
|
|
|
|
|
function(run_NoWorkToDo)
|
|
|
|
run_cmake(NoWorkToDo)
|
|
|
|
set(RunCMake_TEST_NO_CLEAN 1)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/NoWorkToDo-build)
|
|
|
|
set(RunCMake_TEST_OUTPUT_MERGE 1)
|
|
|
|
run_cmake_command(NoWorkToDo-build ${CMAKE_COMMAND} --build .)
|
|
|
|
run_cmake_command(NoWorkToDo-nowork ${CMAKE_COMMAND} --build . -- -d explain)
|
|
|
|
endfunction()
|
|
|
|
run_NoWorkToDo()
|
|
|
|
|
|
|
|
function(run_VerboseBuild)
|
|
|
|
run_cmake(VerboseBuild)
|
|
|
|
set(RunCMake_TEST_NO_CLEAN 1)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VerboseBuild-build)
|
|
|
|
set(RunCMake_TEST_OUTPUT_MERGE 1)
|
|
|
|
run_cmake_command(VerboseBuild-build ${CMAKE_COMMAND} --build . -v --clean-first)
|
|
|
|
run_cmake_command(VerboseBuild-nowork ${CMAKE_COMMAND} --build . --verbose)
|
|
|
|
endfunction()
|
|
|
|
run_VerboseBuild()
|
|
|
|
|
|
|
|
function(run_CMP0058 case)
|
|
|
|
# Use a single build tree for a few tests without cleaning.
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0058-${case}-build)
|
|
|
|
set(RunCMake_TEST_NO_CLEAN 1)
|
|
|
|
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
run_cmake(CMP0058-${case})
|
|
|
|
run_cmake_command(CMP0058-${case}-build ${CMAKE_COMMAND} --build .)
|
|
|
|
endfunction()
|
|
|
|
|
|
|
|
run_CMP0058(OLD-no)
|
|
|
|
run_CMP0058(OLD-by)
|
|
|
|
run_CMP0058(WARN-no)
|
|
|
|
run_CMP0058(WARN-by)
|
|
|
|
run_CMP0058(NEW-no)
|
|
|
|
run_CMP0058(NEW-by)
|
|
|
|
|
|
|
|
run_cmake_with_options(CustomCommandDepfile -DCMAKE_BUILD_TYPE=Debug)
|
|
|
|
run_cmake(CustomCommandJobPool)
|
|
|
|
run_cmake(JobPoolUsesTerminal)
|
|
|
|
|
|
|
|
run_cmake(RspFileC)
|
|
|
|
run_cmake(RspFileCXX)
|
|
|
|
if(TEST_Fortran)
|
|
|
|
run_cmake(RspFileFortran)
|
|
|
|
endif()
|
|
|
|
|
|
|
|
function(run_CommandConcat)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommandConcat-build)
|
|
|
|
set(RunCMake_TEST_NO_CLEAN 1)
|
|
|
|
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
run_cmake(CommandConcat)
|
|
|
|
run_cmake_command(CommandConcat-build ${CMAKE_COMMAND} --build .)
|
|
|
|
endfunction()
|
|
|
|
run_CommandConcat()
|
|
|
|
|
|
|
|
function(run_SubDir)
|
|
|
|
# Use a single build tree for a few tests without cleaning.
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build)
|
|
|
|
set(RunCMake_TEST_NO_CLEAN 1)
|
|
|
|
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
run_cmake(SubDir)
|
|
|
|
if(WIN32)
|
|
|
|
set(SubDir_all [[SubDir\all]])
|
|
|
|
set(SubDir_test [[SubDir\test]])
|
|
|
|
set(SubDir_install [[SubDir\install]])
|
|
|
|
set(SubDirBinary_test [[SubDirBinary\test]])
|
|
|
|
set(SubDirBinary_all [[SubDirBinary\all]])
|
|
|
|
set(SubDirBinary_install [[SubDirBinary\install]])
|
|
|
|
else()
|
|
|
|
set(SubDir_all [[SubDir/all]])
|
|
|
|
set(SubDir_test [[SubDir/test]])
|
|
|
|
set(SubDir_install [[SubDir/install]])
|
|
|
|
set(SubDirBinary_all [[SubDirBinary/all]])
|
|
|
|
set(SubDirBinary_test [[SubDirBinary/test]])
|
|
|
|
set(SubDirBinary_install [[SubDirBinary/install]])
|
|
|
|
endif()
|
|
|
|
run_cmake_command(SubDir-build ${CMAKE_COMMAND} --build . --target ${SubDir_all})
|
|
|
|
run_cmake_command(SubDir-test ${CMAKE_COMMAND} --build . --target ${SubDir_test})
|
|
|
|
run_cmake_command(SubDir-install ${CMAKE_COMMAND} --build . --target ${SubDir_install})
|
|
|
|
run_cmake_command(SubDirBinary-build ${CMAKE_COMMAND} --build . --target ${SubDirBinary_all})
|
|
|
|
run_cmake_command(SubDirBinary-test ${CMAKE_COMMAND} --build . --target ${SubDirBinary_test})
|
|
|
|
run_cmake_command(SubDirBinary-install ${CMAKE_COMMAND} --build . --target ${SubDirBinary_install})
|
|
|
|
endfunction()
|
|
|
|
run_SubDir()
|
|
|
|
|
|
|
|
function(run_ninja dir)
|
|
|
|
execute_process(
|
|
|
|
COMMAND "${RunCMake_MAKE_PROGRAM}" ${ARGN}
|
|
|
|
WORKING_DIRECTORY "${dir}"
|
|
|
|
OUTPUT_VARIABLE ninja_stdout
|
|
|
|
ERROR_VARIABLE ninja_stderr
|
|
|
|
RESULT_VARIABLE ninja_result
|
|
|
|
)
|
|
|
|
if(NOT ninja_result EQUAL 0)
|
|
|
|
message(STATUS "
|
|
|
|
============ beginning of ninja's stdout ============
|
|
|
|
${ninja_stdout}
|
|
|
|
=============== end of ninja's stdout ===============
|
|
|
|
")
|
|
|
|
message(STATUS "
|
|
|
|
============ beginning of ninja's stderr ============
|
|
|
|
${ninja_stderr}
|
|
|
|
=============== end of ninja's stderr ===============
|
|
|
|
")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"top ninja build failed exited with status ${ninja_result}")
|
|
|
|
endif()
|
|
|
|
set(ninja_stdout "${ninja_stdout}" PARENT_SCOPE)
|
|
|
|
endfunction(run_ninja)
|
|
|
|
|
|
|
|
function (run_LooseObjectDepends)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LooseObjectDepends-build)
|
|
|
|
run_cmake(LooseObjectDepends)
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}" "CMakeFiles/top.dir/top.c${CMAKE_C_OUTPUT_EXTENSION}")
|
|
|
|
if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}dep${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"The `dep` library was created when requesting an object file to be "
|
|
|
|
"built; this should no longer be necessary.")
|
|
|
|
endif ()
|
|
|
|
if (EXISTS "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/dep.dir/dep.c${CMAKE_C_OUTPUT_EXTENSION}")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"The `dep.c` object file was created when requesting an object file to "
|
|
|
|
"be built; this should no longer be necessary.")
|
|
|
|
endif ()
|
|
|
|
endfunction ()
|
|
|
|
run_LooseObjectDepends()
|
|
|
|
|
|
|
|
function (run_AssumedSources)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AssumedSources-build)
|
|
|
|
run_cmake(AssumedSources)
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}" "${RunCMake_TEST_BINARY_DIR}/target.c")
|
|
|
|
if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/target.c")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"Dependencies for an assumed source did not hook up properly for 'target.c'.")
|
|
|
|
endif ()
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}" "${RunCMake_TEST_BINARY_DIR}/target-no-depends.c")
|
|
|
|
if (EXISTS "${RunCMake_TEST_BINARY_DIR}/target-no-depends.c")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"Dependencies for an assumed source were magically hooked up for 'target-no-depends.c'.")
|
|
|
|
endif ()
|
|
|
|
endfunction ()
|
|
|
|
run_AssumedSources()
|
|
|
|
|
|
|
|
function(sleep delay)
|
|
|
|
execute_process(
|
|
|
|
COMMAND ${CMAKE_COMMAND} -E sleep ${delay}
|
|
|
|
RESULT_VARIABLE result
|
|
|
|
)
|
|
|
|
if(NOT result EQUAL 0)
|
|
|
|
message(FATAL_ERROR "failed to sleep for ${delay} second.")
|
|
|
|
endif()
|
|
|
|
endfunction(sleep)
|
|
|
|
|
|
|
|
macro(ninja_escape_path path out)
|
|
|
|
string(REPLACE "\$ " "\$\$" "${out}" "${path}")
|
|
|
|
string(REPLACE " " "\$ " "${out}" "${${out}}")
|
|
|
|
string(REPLACE ":" "\$:" "${out}" "${${out}}")
|
|
|
|
endmacro(ninja_escape_path)
|
|
|
|
|
|
|
|
macro(shell_escape string out)
|
|
|
|
string(REPLACE "\"" "\\\"" "${out}" "${string}")
|
|
|
|
endmacro(shell_escape)
|
|
|
|
|
|
|
|
function(run_sub_cmake test ninja_output_path_prefix)
|
|
|
|
set(top_build_dir "${RunCMake_BINARY_DIR}/${test}-build/")
|
|
|
|
file(REMOVE_RECURSE "${top_build_dir}")
|
|
|
|
file(MAKE_DIRECTORY "${top_build_dir}")
|
|
|
|
|
|
|
|
ninja_escape_path("${ninja_output_path_prefix}"
|
|
|
|
escaped_ninja_output_path_prefix)
|
|
|
|
|
|
|
|
# Generate top build ninja file.
|
|
|
|
set(top_build_ninja "${top_build_dir}/build.ninja")
|
|
|
|
shell_escape("${top_build_ninja}" escaped_top_build_ninja)
|
|
|
|
set(build_ninja_dep "${top_build_dir}/build_ninja_dep")
|
|
|
|
ninja_escape_path("${build_ninja_dep}" escaped_build_ninja_dep)
|
|
|
|
shell_escape("${CMAKE_COMMAND}" escaped_CMAKE_COMMAND)
|
|
|
|
file(WRITE "${build_ninja_dep}" "fake dependency of top build.ninja file\n")
|
|
|
|
if(WIN32)
|
|
|
|
set(cmd_prefix "cmd.exe /C \"")
|
|
|
|
set(cmd_suffix "\"")
|
|
|
|
else()
|
|
|
|
set(cmd_prefix "")
|
|
|
|
set(cmd_suffix "")
|
|
|
|
endif()
|
|
|
|
set(fs_delay 3) # We assume the system as 1 sec timestamp resolution.
|
|
|
|
file(WRITE "${top_build_ninja}" "\
|
|
|
|
subninja ${escaped_ninja_output_path_prefix}/build.ninja
|
|
|
|
default ${escaped_ninja_output_path_prefix}/all
|
|
|
|
|
|
|
|
# Sleep for long enough before regenerating to make sure the timestamp of
|
|
|
|
# the top build.ninja will be strictly greater than the timestamp of the
|
|
|
|
# sub/build.ninja file.
|
|
|
|
rule RERUN
|
|
|
|
command = ${cmd_prefix}\"${escaped_CMAKE_COMMAND}\" -E sleep ${fs_delay} && \"${escaped_CMAKE_COMMAND}\" -E touch \"${escaped_top_build_ninja}\"${cmd_suffix}
|
|
|
|
description = Testing regeneration
|
|
|
|
generator = 1
|
|
|
|
|
|
|
|
build build.ninja: RERUN ${escaped_build_ninja_dep} || ${escaped_ninja_output_path_prefix}/build.ninja
|
|
|
|
pool = console
|
|
|
|
")
|
|
|
|
|
|
|
|
# Run sub cmake project.
|
|
|
|
set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_OUTPUT_PATH_PREFIX=${ninja_output_path_prefix}")
|
|
|
|
set(RunCMake_TEST_BINARY_DIR "${top_build_dir}/${ninja_output_path_prefix}")
|
|
|
|
run_cmake(${test})
|
|
|
|
|
|
|
|
# Check there is no 'default' statement in Ninja file generated by CMake.
|
|
|
|
set(sub_build_ninja "${RunCMake_TEST_BINARY_DIR}/build.ninja")
|
|
|
|
file(READ "${sub_build_ninja}" sub_build_ninja_file)
|
|
|
|
if(sub_build_ninja_file MATCHES "\ndefault [^\n][^\n]*all\n")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"unexpected 'default' statement found in '${sub_build_ninja}'")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Run ninja from the top build directory.
|
|
|
|
run_ninja("${top_build_dir}")
|
|
|
|
|
|
|
|
# Test regeneration rules run in order.
|
|
|
|
set(main_cmakelists "${RunCMake_SOURCE_DIR}/CMakeLists.txt")
|
|
|
|
sleep(${fs_delay})
|
|
|
|
file(TOUCH "${main_cmakelists}")
|
|
|
|
file(TOUCH "${build_ninja_dep}")
|
|
|
|
run_ninja("${top_build_dir}")
|
|
|
|
file(TIMESTAMP "${main_cmakelists}" mtime_main_cmakelists UTC)
|
|
|
|
file(TIMESTAMP "${sub_build_ninja}" mtime_sub_build_ninja UTC)
|
|
|
|
file(TIMESTAMP "${top_build_ninja}" mtime_top_build_ninja UTC)
|
|
|
|
|
|
|
|
# Check sub build.ninja is regenerated.
|
|
|
|
if(mtime_main_cmakelists STRGREATER mtime_sub_build_ninja)
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"sub build.ninja not regenerated:
|
|
|
|
CMakeLists.txt = ${mtime_main_cmakelists}
|
|
|
|
sub/build.ninja = ${mtime_sub_build_ninja}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Check top build.ninja is regenerated after sub build.ninja.
|
|
|
|
if(NOT mtime_top_build_ninja STRGREATER mtime_sub_build_ninja)
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"top build.ninja not regenerated strictly after sub build.ninja:
|
|
|
|
sub/build.ninja = ${mtime_sub_build_ninja}
|
|
|
|
build.ninja = ${mtime_top_build_ninja}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
endfunction(run_sub_cmake)
|
|
|
|
|
|
|
|
if("${ninja_version}" VERSION_LESS 1.6)
|
|
|
|
message(WARNING "Ninja is too old; skipping rest of test.")
|
|
|
|
return()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
foreach(ninja_output_path_prefix "sub space" "sub")
|
|
|
|
run_sub_cmake(Executable "${ninja_output_path_prefix}")
|
|
|
|
run_sub_cmake(StaticLib "${ninja_output_path_prefix}")
|
|
|
|
run_sub_cmake(SharedLib "${ninja_output_path_prefix}")
|
|
|
|
run_sub_cmake(TwoLibs "${ninja_output_path_prefix}")
|
|
|
|
run_sub_cmake(SubDirPrefix "${ninja_output_path_prefix}")
|
|
|
|
run_sub_cmake(CustomCommandWorkingDirectory "${ninja_output_path_prefix}")
|
|
|
|
endforeach(ninja_output_path_prefix)
|
|
|
|
|
|
|
|
function (run_PreventTargetAliasesDupBuildRule)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PreventTargetAliasesDupBuildRule-build)
|
|
|
|
run_cmake(PreventTargetAliasesDupBuildRule)
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
|
|
|
|
endfunction ()
|
|
|
|
run_PreventTargetAliasesDupBuildRule()
|
|
|
|
|
|
|
|
function (run_PreventConfigureFileDupBuildRule)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PreventConfigureFileDupBuildRule-build)
|
|
|
|
run_cmake(PreventConfigureFileDupBuildRule)
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
|
|
|
|
endfunction()
|
|
|
|
run_PreventConfigureFileDupBuildRule()
|
|
|
|
|
|
|
|
function (run_ChangeBuildType)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ChangeBuildType-build)
|
|
|
|
set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=Debug")
|
|
|
|
run_cmake(ChangeBuildType)
|
|
|
|
unset(RunCMake_TEST_OPTIONS)
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
|
|
|
|
endfunction()
|
|
|
|
run_ChangeBuildType()
|
|
|
|
|
|
|
|
function(run_Qt5AutoMocDeps)
|
|
|
|
if(CMake_TEST_Qt5 AND CMAKE_TEST_Qt5Core_Version VERSION_GREATER_EQUAL 5.15.0)
|
|
|
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Qt5AutoMocDeps-build)
|
|
|
|
set(RunCMake_TEST_OPTIONS "-DQt5Core_DIR=${Qt5Core_DIR}" "-DQt5Widgets_DIR=${Qt5Widgets_DIR}")
|
|
|
|
run_cmake(Qt5AutoMocDeps)
|
|
|
|
unset(RunCMake_TEST_OPTIONS)
|
|
|
|
# Build the project.
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
# Touch just the library source file, which shouldn't cause a rerun of AUTOMOC
|
|
|
|
# for app_with_qt target.
|
|
|
|
file(TOUCH "${RunCMake_SOURCE_DIR}/simple_lib.cpp")
|
|
|
|
# Build and assert that AUTOMOC was not run for app_with_qt.
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
if(ninja_stdout MATCHES "Automatic MOC for target app_with_qt")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"AUTOMOC should not have executed for 'app_with_qt' target:\nstdout:\n${ninja_stdout}")
|
|
|
|
endif()
|
|
|
|
# Assert that the subdir executables were not rebuilt.
|
|
|
|
if(ninja_stdout MATCHES "Automatic MOC for target sub_exe_1")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"AUTOMOC should not have executed for 'sub_exe_1' target:\nstdout:\n${ninja_stdout}")
|
|
|
|
endif()
|
|
|
|
if(ninja_stdout MATCHES "Automatic MOC for target sub_exe_2")
|
|
|
|
message(FATAL_ERROR
|
|
|
|
"AUTOMOC should not have executed for 'sub_exe_2' target:\nstdout:\n${ninja_stdout}")
|
|
|
|
endif()
|
|
|
|
# Touch a header file to make sure an automoc dependency cycle is not introduced.
|
|
|
|
file(TOUCH "${RunCMake_SOURCE_DIR}/MyWindow.h")
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
# Need to run a second time to hit the dependency cycle.
|
|
|
|
run_ninja("${RunCMake_TEST_BINARY_DIR}")
|
|
|
|
endif()
|
|
|
|
endfunction()
|
|
|
|
run_Qt5AutoMocDeps()
|