Ninja: Add option for parallel install
Adds the global property ``INSTALL_PARALLEL`` to enable a parallel install target for Ninja. Fixes: #25459
This commit is contained in:
parent
daeb8fffa2
commit
0e5250e63c
@ -24,6 +24,13 @@ Builtin Targets
|
||||
The ``CMAKE_STRIP`` variable will contain the platform's ``strip`` utility, which
|
||||
removes symbols information from generated binaries.
|
||||
|
||||
``install/parallel``
|
||||
|
||||
.. versionadded:: 3.30
|
||||
|
||||
Created only if the :prop_gbl:`INSTALL_PARALLEL` global property is ``ON``.
|
||||
Runs the install step for each subdirectory independently and in parallel.
|
||||
|
||||
For each subdirectory ``sub/dir`` of the project, additional targets
|
||||
are generated:
|
||||
|
||||
|
@ -39,6 +39,7 @@ Properties of Global Scope
|
||||
/prop_gbl/GENERATOR_IS_MULTI_CONFIG
|
||||
/prop_gbl/GLOBAL_DEPENDS_DEBUG_MODE
|
||||
/prop_gbl/GLOBAL_DEPENDS_NO_CYCLES
|
||||
/prop_gbl/INSTALL_PARALLEL
|
||||
/prop_gbl/IN_TRY_COMPILE
|
||||
/prop_gbl/JOB_POOLS
|
||||
/prop_gbl/PACKAGES_FOUND
|
||||
|
23
Help/prop_gbl/INSTALL_PARALLEL.rst
Normal file
23
Help/prop_gbl/INSTALL_PARALLEL.rst
Normal file
@ -0,0 +1,23 @@
|
||||
INSTALL_PARALLEL
|
||||
----------------
|
||||
|
||||
.. versionadded:: 3.30
|
||||
|
||||
Enables parallel installation option for the Ninja generator.
|
||||
|
||||
When this property is ``ON``, ``install/local`` targets have the
|
||||
console pool disabled, allowing them to run concurrently.
|
||||
|
||||
This property also provides the target ``install/parallel``, which has an
|
||||
explicit dependency on the ``install/local`` target for each subdirectory,
|
||||
recursing down the project.
|
||||
|
||||
Setting this property has no affect on the behavior of ``cmake --install``.
|
||||
The install must be invoked by building the ``install/parallel`` target
|
||||
directly.
|
||||
|
||||
Calls to :command:`install(CODE)` or :command:`install(SCRIPT)` might depend
|
||||
on actions performed by an earlier :command:`install` command in a different
|
||||
directory such as files installed or variable settings. If the project has
|
||||
such order-dependent installation logic, parallel installation should be
|
||||
not be enabled, in order to prevent possible race conditions.
|
@ -3048,7 +3048,9 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
|
||||
if (const char* install_local = this->GetInstallLocalTargetName()) {
|
||||
gti.Name = install_local;
|
||||
gti.Message = "Installing only the local directory...";
|
||||
gti.UsesTerminal = true;
|
||||
gti.UsesTerminal =
|
||||
!this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
|
||||
"INSTALL_PARALLEL");
|
||||
gti.CommandLines.clear();
|
||||
|
||||
cmCustomCommandLine localCmdLine = singleLine;
|
||||
|
@ -1835,6 +1835,21 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
|
||||
if (!this->DefaultFileConfig.empty()) {
|
||||
this->WriteTargetDefault(*this->GetDefaultFileStream());
|
||||
}
|
||||
|
||||
if (this->InstallTargetEnabled &&
|
||||
this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
|
||||
"INSTALL_PARALLEL") &&
|
||||
!this->Makefiles[0]->IsOn("CMAKE_SKIP_INSTALL_RULES")) {
|
||||
cmNinjaBuild build("phony");
|
||||
build.Comment = "Install every subdirectory in parallel";
|
||||
build.Outputs.emplace_back(this->GetInstallParallelTargetName());
|
||||
for (auto const& mf : this->Makefiles) {
|
||||
build.ExplicitDeps.emplace_back(
|
||||
this->ConvertToNinjaPath(cmStrCat(mf->GetCurrentBinaryDirectory(), "/",
|
||||
this->GetInstallLocalTargetName())));
|
||||
}
|
||||
WriteBuild(os, build);
|
||||
}
|
||||
}
|
||||
|
||||
void cmGlobalNinjaGenerator::WriteTargetDefault(std::ostream& os)
|
||||
|
@ -218,6 +218,10 @@ public:
|
||||
{
|
||||
return "install/strip";
|
||||
}
|
||||
const char* GetInstallParallelTargetName() const
|
||||
{
|
||||
return "install/parallel";
|
||||
}
|
||||
const char* GetTestTargetName() const override { return "test"; }
|
||||
const char* GetPackageTargetName() const override { return "package"; }
|
||||
const char* GetPackageSourceTargetName() const override
|
||||
|
@ -723,10 +723,12 @@ void cmLocalGenerator::GenerateInstallRules()
|
||||
" set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
|
||||
"endif()\n"
|
||||
"\n"
|
||||
"string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n"
|
||||
"if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n"
|
||||
" string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n"
|
||||
" \"${CMAKE_INSTALL_MANIFEST_FILES}\")\n"
|
||||
"file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n"
|
||||
" \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n";
|
||||
" file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n"
|
||||
" \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n"
|
||||
"endif()\n";
|
||||
/* clang-format on */
|
||||
}
|
||||
}
|
||||
|
@ -250,6 +250,7 @@ if(CMAKE_GENERATOR MATCHES "Ninja")
|
||||
add_RunCMake_test(NinjaPrivateDeps
|
||||
-DCMAKE_C_OUTPUT_EXTENSION=${CMAKE_C_OUTPUT_EXTENSION}
|
||||
-DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig})
|
||||
add_RunCMake_test(InstallParallel)
|
||||
endif()
|
||||
add_RunCMake_test(CTest)
|
||||
|
||||
|
3
Tests/RunCMake/InstallParallel/CMakeLists.txt
Normal file
3
Tests/RunCMake/InstallParallel/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.29)
|
||||
project(${RunCMake_TEST} NONE)
|
||||
include(${RunCMake_TEST}.cmake)
|
17
Tests/RunCMake/InstallParallel/RunCMakeTest.cmake
Normal file
17
Tests/RunCMake/InstallParallel/RunCMakeTest.cmake
Normal file
@ -0,0 +1,17 @@
|
||||
include(RunCMake)
|
||||
|
||||
function(install_test test parallel install_target check_script)
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-install)
|
||||
set(RunCMake_TEST_OPTIONS -DINSTALL_PARALLEL=${parallel})
|
||||
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)
|
||||
run_cmake_command(${test}-install ${CMAKE_COMMAND} --build . --config Debug -t ${install_target})
|
||||
set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY ${RunCMake_SOURCE_DIR})
|
||||
run_cmake_command(verify-parallel ${CMAKE_COMMAND} -P ${check_script} ${RunCMake_TEST_BINARY_DIR}/.ninja_log)
|
||||
endfunction()
|
||||
|
||||
install_test(parallel 1 install/parallel check-parallel.cmake)
|
||||
install_test(no-parallel 0 install check-single.cmake)
|
15
Tests/RunCMake/InstallParallel/check-parallel.cmake
Normal file
15
Tests/RunCMake/InstallParallel/check-parallel.cmake
Normal file
@ -0,0 +1,15 @@
|
||||
include(read-ninja-install.cmake)
|
||||
|
||||
foreach(line ${lines})
|
||||
string(REPLACE "\t" ";" line ${line})
|
||||
list(GET line 0 start)
|
||||
list(GET line 1 end)
|
||||
list(APPEND start_times ${start})
|
||||
list(APPEND end_times ${end})
|
||||
endforeach()
|
||||
list(GET start_times 1 start_2)
|
||||
list(GET end_times 0 end_1)
|
||||
|
||||
if (NOT start_2 LESS end_1)
|
||||
message(FATAL_ERROR "Install is not parallel")
|
||||
endif()
|
5
Tests/RunCMake/InstallParallel/check-single.cmake
Normal file
5
Tests/RunCMake/InstallParallel/check-single.cmake
Normal file
@ -0,0 +1,5 @@
|
||||
include(read-ninja-install.cmake)
|
||||
list(LENGTH lines len)
|
||||
if (NOT ${len} STREQUAL "1")
|
||||
message(FATAL_ERROR "Expected single installation call")
|
||||
endif()
|
6
Tests/RunCMake/InstallParallel/install.cmake
Normal file
6
Tests/RunCMake/InstallParallel/install.cmake
Normal file
@ -0,0 +1,6 @@
|
||||
install(CODE "message(installing:${CMAKE_CURRENT_SOURCE_DIR})")
|
||||
if (INSTALL_PARALLEL)
|
||||
set_property(GLOBAL PROPERTY INSTALL_PARALLEL ON)
|
||||
endif()
|
||||
add_subdirectory(subdir-1)
|
||||
add_subdirectory(subdir-2)
|
@ -0,0 +1,5 @@
|
||||
installing:.*
|
||||
installing:.*
|
||||
installing:.*
|
||||
installing:.*
|
||||
installing:.*
|
15
Tests/RunCMake/InstallParallel/parallel-install-stdout.txt
Normal file
15
Tests/RunCMake/InstallParallel/parallel-install-stdout.txt
Normal file
@ -0,0 +1,15 @@
|
||||
\[1\/5\] Installing only the local directory...
|
||||
\-\- Install configuration: \"Debug\"
|
||||
installing:.*
|
||||
\[2\/5\] Installing only the local directory...
|
||||
\-\- Install configuration: \"Debug\"
|
||||
installing:.*
|
||||
\[3\/5\] Installing only the local directory...
|
||||
\-\- Install configuration: \"Debug\"
|
||||
installing:.*
|
||||
\[4\/5\] Installing only the local directory...
|
||||
\-\- Install configuration: \"Debug\"
|
||||
installing:.*
|
||||
\[5\/5\] Installing only the local directory...
|
||||
\-\- Install configuration: \"Debug\"
|
||||
installing:.*
|
4
Tests/RunCMake/InstallParallel/read-ninja-install.cmake
Normal file
4
Tests/RunCMake/InstallParallel/read-ninja-install.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
set(ninja_log ${CMAKE_ARGV3})
|
||||
file(STRINGS ${ninja_log} lines)
|
||||
list(POP_FRONT lines)
|
||||
list(FILTER lines INCLUDE REGEX ".*install.*util")
|
3
Tests/RunCMake/InstallParallel/subdir-1/CMakeLists.txt
Normal file
3
Tests/RunCMake/InstallParallel/subdir-1/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
install(CODE "message(installing:${CMAKE_CURRENT_SOURCE_DIR})")
|
||||
add_subdirectory(subdir-3)
|
||||
add_subdirectory(subdir-4)
|
@ -0,0 +1 @@
|
||||
install(CODE "message(installing:${CMAKE_CURRENT_SOURCE_DIR})")
|
@ -0,0 +1 @@
|
||||
install(CODE "message(installing:${CMAKE_CURRENT_SOURCE_DIR})")
|
1
Tests/RunCMake/InstallParallel/subdir-2/CMakeLists.txt
Normal file
1
Tests/RunCMake/InstallParallel/subdir-2/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
install(CODE "message(installing:${CMAKE_CURRENT_SOURCE_DIR})")
|
Loading…
Reference in New Issue
Block a user