diff options
author | Seth R Johnson <johnsonsr@ornl.gov> | 2021-09-30 19:36:18 (GMT) |
---|---|---|
committer | Seth R Johnson <johnsonsr@ornl.gov> | 2021-09-30 19:36:35 (GMT) |
commit | 8f7e98ef09085011e92b3dfeb8aaf60f31bc9270 (patch) | |
tree | 28bad367e0db1246901350b4d09ff8e9828be1ed /Source/cmInstallTargetGenerator.cxx | |
parent | 89d134c61d4cc78bfb9585c80144ce2acae14cfa (diff) | |
download | CMake-8f7e98ef09085011e92b3dfeb8aaf60f31bc9270.zip CMake-8f7e98ef09085011e92b3dfeb8aaf60f31bc9270.tar.gz CMake-8f7e98ef09085011e92b3dfeb8aaf60f31bc9270.tar.bz2 |
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.
Diffstat (limited to 'Source/cmInstallTargetGenerator.cxx')
-rw-r--r-- | Source/cmInstallTargetGenerator.cxx | 65 |
1 files changed, 43 insertions, 22 deletions
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 2f974c4..ae11afc 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -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,33 +682,52 @@ 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); + 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(); + } + } - if (runpaths.find(runpath) == runpaths.end()) { - os << indent << "execute_process(COMMAND " << installNameTool - << "\n"; - os << indent << " -add_rpath \"" << runpath << "\"\n"; - os << indent << " \"" << toDestDirPath << "\")\n"; + // 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 { |