cmake --install: Check that install scripts exist before running

Previously a missing `cmake_install.cmake` was reported only as a
generic script processing error. Instead, report the missing script
path up front. This also avoids a partial installation when a
subdirectory's script is missing in a parallel install.
This commit is contained in:
Tyler Yankee committed 2026-11-04 10:51:25 -05:00
1 parent 3ed425fca5
commit 50c29eae35
10 files changed
+62 -1

No files matched your search

+7
View File
@@ -1032,6 +1032,13 @@ int do_install(int ac, char const* const* av)
}
auto doInstall = [&handler, &verbose, &jobs, &instrumentation]() -> int {
for (auto const& script : handler.GetScripts()) {
if (!cmSystemTools::FileExists(script.path, true)) {
cmSystemTools::Error(
cmStrCat("Install script does not exist:\n ", script.path));
return 1;
}
}
int ret_ = 0;
if (handler.IsParallel()) {
ret_ = handler.Install(jobs, instrumentation);
@@ -1 +1,3 @@
^CMake Error: Not a file:
^CMake Error: Install script does not exist:
[^
]*/dir-does-not-exist/cmake_install\.cmake$
@@ -116,3 +116,18 @@ function(reconfigure_parallel_test test)
unset(RunCMake-check-file)
endfunction()
reconfigure_parallel_test(out-of-date-json-reconfigure)
# A parallel install does not leave a partial installation behind after a
# missing install script is reported.
function(missing_script_test test)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
set(RunCMake_TEST_OPTIONS -DINSTALL_PARALLEL=ON -DCMAKE_INSTALL_PREFIX=install)
if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
endif()
run_cmake(install)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE ${RunCMake_TEST_BINARY_DIR}/subdir-1/cmake_install.cmake)
run_cmake_command(${test} ${CMAKE_COMMAND} --install . -j 4)
endfunction()
missing_script_test(parallel-missing-script)
@@ -0,0 +1,4 @@
if (EXISTS "${RunCMake_TEST_BINARY_DIR}/install")
set(RunCMake_TEST_FAILED
"files were installed despite a missing install script")
endif ()
@@ -0,0 +1,3 @@
^CMake Error: Install script does not exist:
[^
]*/parallel-missing-script-build/subdir-1/cmake_install\.cmake$
@@ -15,6 +15,7 @@ function(instrument test)
"INSTALL_PARALLEL"
"INSTALL_SEAM"
"INSTALL_INTERRUPT"
"INSTALL_MISSING_SCRIPT"
"TEST"
"CTEST_SEAM"
"CTEST_INTERRUPT"
@@ -288,6 +289,11 @@ function(instrument test)
if (ARGS_INSTALL)
run_cmake_command(${test}-install ${CMAKE_COMMAND} --install . --prefix install --config Debug)
endif()
if (ARGS_INSTALL_MISSING_SCRIPT)
file(REMOVE ${RunCMake_TEST_BINARY_DIR}/cmake_install.cmake)
run_cmake_command(${test}-install
${CMAKE_COMMAND} --install . --prefix install --config Debug)
endif()
if (ARGS_INSTALL_SEAM)
# Drive the cmakeInstall interrupt path deterministically via the test-only
# injection seam, with no OS signal, so it runs on every generator. First
@@ -704,6 +710,10 @@ instrument(interrupt-test BUILD CTEST_SEAM
CHECK_SCRIPT check-test-interrupted.cmake
)
instrument(install-missing-script INSTALL_MISSING_SCRIPT
CHECK_SCRIPT check-install-missing-script.cmake
)
# Test make/ninja hooks
if(RunCMake_GENERATOR STREQUAL "FASTBuild")
# FIXME(#27184): This does not work for FASTBuild.
@@ -0,0 +1,15 @@
include(${CMAKE_CURRENT_LIST_DIR}/json.cmake)
# The install failed before running any script, but the cmakeInstall snippet
# should still be written, recording the failure.
file(GLOB snippets LIST_DIRECTORIES false ${v1}/data/cmakeInstall-*.json)
list(LENGTH snippets num)
if (NOT num EQUAL 1)
add_error("Expected exactly one cmakeInstall snippet, found ${num}: ${snippets}")
else()
read_json("${snippets}" contents)
string(JSON result GET "${contents}" result)
if (result EQUAL 0)
add_error("Expected nonzero result in cmakeInstall snippet:\n${contents}")
endif()
endif()
@@ -0,0 +1,3 @@
^CMake Error: Install script does not exist:
[^
]*/install-missing-script/cmake_install\.cmake$