mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 21:59:54 -06:00
cmInstallTargetGenerator: optimize rpath adjustments
With builds that have many internal library directories or many external libraries, rpaths can be quite large. The cost of calling install_name_tool thousands of times can add up to minutes on a build, especially if virus scanning software is there to help you out. With this change, instead of deleting and then re-adding an rpath, we ignore it. Likewise we batch all the rpath adjustment calls into a single command. Before, installing SCALE (some libraries have 70+ build-time RPATHs that get deleted, plus up to a dozen external RPATHs from upstream dependencies that should remain in the binary) would take almost 9 minutes on my laptop, and after this change the installation takes only 30 second.
This commit is contained in:
@@ -2,11 +2,13 @@
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmInstallTargetGenerator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "cmComputeLinkInformation.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
@@ -680,34 +682,53 @@ void cmInstallTargetGenerator::AddChrpathPatchRule(
|
||||
" this limitation.";
|
||||
mf->IssueMessage(MessageType::WARNING, msg.str());
|
||||
} else {
|
||||
// Note: These paths are kept unique to avoid
|
||||
// install_name_tool corruption.
|
||||
std::set<std::string> runpaths;
|
||||
for (std::string const& i : oldRuntimeDirs) {
|
||||
std::string runpath =
|
||||
mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
|
||||
|
||||
if (runpaths.find(runpath) == runpaths.end()) {
|
||||
runpaths.insert(runpath);
|
||||
os << indent << "execute_process(COMMAND " << installNameTool
|
||||
<< "\n";
|
||||
os << indent << " -delete_rpath \"" << runpath << "\"\n";
|
||||
os << indent << " \"" << toDestDirPath << "\")\n";
|
||||
// To be consistent with older versions, runpath changes must be ordered,
|
||||
// deleted first, then added, *and* the same path must only appear once.
|
||||
std::map<std::string, std::string> runpath_change;
|
||||
std::vector<std::string> ordered;
|
||||
for (std::string const& dir : oldRuntimeDirs) {
|
||||
// Normalize path and add to map of changes to make
|
||||
auto iter_inserted = runpath_change.insert(
|
||||
{ mf->GetGlobalGenerator()->ExpandCFGIntDir(dir, config),
|
||||
"delete" });
|
||||
if (iter_inserted.second) {
|
||||
// Add path to ordered list of changes
|
||||
ordered.push_back(iter_inserted.first->first);
|
||||
}
|
||||
}
|
||||
|
||||
runpaths.clear();
|
||||
for (std::string const& i : newRuntimeDirs) {
|
||||
std::string runpath =
|
||||
mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
|
||||
|
||||
if (runpaths.find(runpath) == runpaths.end()) {
|
||||
os << indent << "execute_process(COMMAND " << installNameTool
|
||||
<< "\n";
|
||||
os << indent << " -add_rpath \"" << runpath << "\"\n";
|
||||
os << indent << " \"" << toDestDirPath << "\")\n";
|
||||
for (std::string const& dir : newRuntimeDirs) {
|
||||
// Normalize path and add to map of changes to make
|
||||
auto iter_inserted = runpath_change.insert(
|
||||
{ mf->GetGlobalGenerator()->ExpandCFGIntDir(dir, config), "add" });
|
||||
if (iter_inserted.second) {
|
||||
// Add path to ordered list of changes
|
||||
ordered.push_back(iter_inserted.first->first);
|
||||
} else if (iter_inserted.first->second != "add") {
|
||||
// Rpath was requested to be deleted and then later re-added. Drop it
|
||||
// from the list by marking as an empty value.
|
||||
iter_inserted.first->second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove rpaths that are unchanged (value was set to empty)
|
||||
ordered.erase(
|
||||
std::remove_if(ordered.begin(), ordered.end(),
|
||||
[&runpath_change](const std::string& runpath) {
|
||||
return runpath_change.find(runpath)->second.empty();
|
||||
}),
|
||||
ordered.end());
|
||||
|
||||
if (!ordered.empty()) {
|
||||
os << indent << "execute_process(COMMAND " << installNameTool << "\n";
|
||||
for (std::string const& runpath : ordered) {
|
||||
// Either 'add_rpath' or 'delete_rpath' since we've removed empty
|
||||
// entries
|
||||
os << indent << " -" << runpath_change.find(runpath)->second
|
||||
<< "_rpath \"" << runpath << "\"\n";
|
||||
}
|
||||
os << indent << " \"" << toDestDirPath << "\")\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Construct the original rpath string to be replaced.
|
||||
|
||||
Reference in New Issue
Block a user