cmake --install: Support multiple --components

Issue: #25178
This commit is contained in:
Robert Maynard
2026-03-09 13:47:58 -04:00
parent f059d95484
commit bd605ba9e6
10 changed files with 88 additions and 40 deletions
+7
View File
@@ -917,6 +917,13 @@ The options are:
Component-based install. Only install component ``<comp>``.
.. versionadded:: 4.4
Supports installing more than one component:
* ``--component <compA> <compB>``
* ``--component <compA> --component <compB>``
.. option:: --default-directory-permissions <permissions>
Default directory install permissions. Permissions in format ``<u=rwx,g=rx,o=rx>``.
@@ -0,0 +1,5 @@
cmake-install-multi-component
-----------------------------
* The :option:`cmake --install` command now supports installing
multiple components.
+43 -34
View File
@@ -33,24 +33,27 @@
using InstallScript = cmInstallScriptHandler::InstallScript;
using InstallScriptRunner = cmInstallScriptHandler::InstallScriptRunner;
cmInstallScriptHandler::cmInstallScriptHandler(std::string _binaryDir,
std::string _component,
std::string _config,
std::vector<std::string>& args)
: binaryDir(std::move(_binaryDir))
, component(std::move(_component))
cmInstallScriptHandler::cmInstallScriptHandler(
std::string _binaryDir, std::vector<std::string> _components,
std::string _config, std::vector<std::string>& args)
: components(std::move(_components))
, binaryDir(std::move(_binaryDir))
{
if (this->components.empty()) {
this->components.emplace_back(std::string{});
}
std::string const& file =
cmStrCat(this->binaryDir, "/CMakeFiles/InstallScripts.json");
this->parallel = false;
auto addScript = [this, &args](std::string script,
auto addScript = [this, &args](std::string script, std::string component,
std::string config) -> void {
this->scripts.push_back({ script, config, args });
if (!this->component.empty()) {
if (!component.empty()) {
this->scripts.back().command.insert(
this->scripts.back().command.end() - 1,
cmStrCat("-DCMAKE_INSTALL_COMPONENT=", this->component));
cmStrCat("-DCMAKE_INSTALL_COMPONENT=", component));
}
if (!config.empty()) {
this->scripts.back().command.insert(
@@ -86,15 +89,20 @@ cmInstallScriptHandler::cmInstallScriptHandler(std::string _binaryDir,
this->configs.push_back(_config);
}
for (auto const& script : value["InstallScripts"]) {
for (auto const& config : configs) {
addScript(script.asCString(), config);
for (auto const& component : components) {
for (auto const& config : configs) {
addScript(script.asCString(), component, config);
}
}
if (!this->parallel) {
break;
}
}
} else {
addScript(cmStrCat(this->binaryDir, "/cmake_install.cmake"), _config);
for (auto const& component : components) {
addScript(cmStrCat(this->binaryDir, "/cmake_install.cmake"), component,
_config);
}
}
}
@@ -161,30 +169,31 @@ int cmInstallScriptHandler::Install(unsigned int j,
// Write install manifest
std::string install_manifest;
if (this->component.empty()) {
install_manifest = "install_manifest.txt";
} else {
cmsys::RegularExpression regEntry;
if (regEntry.compile("^[a-zA-Z0-9_.+-]+$") &&
regEntry.find(this->component)) {
install_manifest =
cmStrCat("install_manifest_", this->component, ".txt");
for (auto const& component : this->components) {
if (component.empty()) {
install_manifest = "install_manifest.txt";
} else {
cmCryptoHash md5(cmCryptoHash::AlgoMD5);
md5.Initialize();
install_manifest =
cmStrCat("install_manifest_", md5.HashString(this->component), ".txt");
cmsys::RegularExpression regEntry;
if (regEntry.compile("^[a-zA-Z0-9_.+-]+$") && regEntry.find(component)) {
install_manifest = cmStrCat("install_manifest_", component, ".txt");
} else {
cmCryptoHash md5(cmCryptoHash::AlgoMD5);
md5.Initialize();
install_manifest =
cmStrCat("install_manifest_", md5.HashString(component), ".txt");
}
}
}
cmGeneratedFileStream fout(cmStrCat(this->binaryDir, '/', install_manifest));
fout.SetCopyIfDifferent(true);
for (auto const& dir : this->directories) {
auto local_manifest = cmStrCat(dir, "/install_local_manifest.txt");
if (cmSystemTools::FileExists(local_manifest)) {
cmsys::ifstream fin(local_manifest.c_str());
std::string line;
while (std::getline(fin, line)) {
fout << line << "\n";
cmGeneratedFileStream fout(
cmStrCat(this->binaryDir, '/', install_manifest));
fout.SetCopyIfDifferent(true);
for (auto const& dir : this->directories) {
auto local_manifest = cmStrCat(dir, "/install_local_manifest.txt");
if (cmSystemTools::FileExists(local_manifest)) {
cmsys::ifstream fin(local_manifest.c_str());
std::string line;
while (std::getline(fin, line)) {
fout << line << "\n";
}
}
}
}
+2 -2
View File
@@ -21,7 +21,7 @@ class cmInstallScriptHandler
{
public:
cmInstallScriptHandler() = default;
cmInstallScriptHandler(std::string, std::string, std::string,
cmInstallScriptHandler(std::string, std::vector<std::string>, std::string,
std::vector<std::string>&);
bool IsParallel();
int Install(unsigned int j, cmInstrumentation& instrumentation);
@@ -51,7 +51,7 @@ private:
std::vector<InstallScript> scripts;
std::vector<std::string> configs;
std::vector<std::string> directories;
std::vector<std::string> components;
std::string binaryDir;
std::string component;
bool parallel;
};
+16 -4
View File
@@ -801,7 +801,7 @@ int do_install(int ac, char const* const* av)
assert(1 < ac);
std::string config;
std::string component;
std::vector<std::string> components;
std::string defaultDirectoryPermissions;
std::string prefix;
std::string dir;
@@ -809,6 +809,17 @@ int do_install(int ac, char const* const* av)
bool strip = false;
bool verbose = cmSystemTools::HasEnv("VERBOSE");
auto componentLambda = [&components](std::string const& value) -> bool {
if (!value.empty()) {
cmList values{ value };
for (auto const& v : values) {
components.emplace_back(v);
}
return true;
}
return false;
};
auto jLambda = extract_job_number_lambda_builder(dir, jobs, "-j");
auto parallelLambda =
extract_job_number_lambda_builder(dir, jobs, "--parallel");
@@ -824,8 +835,8 @@ int do_install(int ac, char const* const* av)
std::vector<CommandArgument> arguments = {
CommandArgument{ "--config", CommandArgument::Values::One,
CommandArgument::setToValue(config) },
CommandArgument{ "--component", CommandArgument::Values::One,
CommandArgument::setToValue(component) },
CommandArgument{ "--component", CommandArgument::Values::OneOrMore,
componentLambda },
CommandArgument{
"--default-directory-permissions", CommandArgument::Values::One,
CommandArgument::setToValue(defaultDirectoryPermissions) },
@@ -876,6 +887,7 @@ int do_install(int ac, char const* const* av)
" <dir> = Project binary directory to install.\n"
" --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
" --component <comp> = Component-based install. Only install <comp>.\n"
" May be passed multiple components. t\n"
" --default-directory-permissions <permission> \n"
" Default install permission. Use default permission <permission>.\n"
" -j <jobs> --parallel <jobs>\n"
@@ -915,7 +927,7 @@ int do_install(int ac, char const* const* av)
args.emplace_back("-P");
cmInstrumentation instrumentation(dir);
auto handler = cmInstallScriptHandler(dir, component, config, args);
auto handler = cmInstallScriptHandler(dir, components, config, args);
int ret = 0;
if (!jobs && handler.IsParallel()) {
jobs = 1;
@@ -147,6 +147,15 @@ run_cmake_command(install-unknown-command-long
run_cmake_command(install-options-to-vars
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
--strip --prefix /var/test --config sample --component pack)
run_cmake_command(install-no-component-value
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
--component)
run_cmake_command(install-multi-component-1
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
--component comp1 comp2)
run_cmake_command(install-multi-component-2
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
--component comp1 --component comp2)
run_cmake_command(install-default-dir-permissions-all
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-permissions-install-options-to-vars
--default-directory-permissions u=rwx,g=rx,o=rx)
@@ -0,0 +1,2 @@
CMAKE_INSTALL_COMPONENT is comp1
CMAKE_INSTALL_COMPONENT is comp2
@@ -0,0 +1,2 @@
CMAKE_INSTALL_COMPONENT is comp1
CMAKE_INSTALL_COMPONENT is comp2
@@ -0,0 +1 @@
1
@@ -0,0 +1 @@
^CMake Error: Invalid value used with --component