1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include "cmBinUtilsLinuxELFLinker.h"
9 #include <cm/string_view>
11 #include <cmsys/RegularExpression.hxx>
13 #include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
15 #include "cmLDConfigLDConfigTool.h"
16 #include "cmMakefile.h"
17 #include "cmMessageType.h"
18 #include "cmRuntimeDependencyArchive.h"
19 #include "cmStringAlgorithms.h"
20 #include "cmSystemTools.h"
22 static std::string ReplaceOrigin(const std::string& rpath,
23 const std::string& origin)
25 static const cmsys::RegularExpression originRegex(
26 "(\\$ORIGIN)([^a-zA-Z0-9_]|$)");
27 static const cmsys::RegularExpression originCurlyRegex("\\${ORIGIN}");
29 cmsys::RegularExpressionMatch match;
30 if (originRegex.find(rpath.c_str(), match)) {
31 cm::string_view pathv(rpath);
32 auto begin = pathv.substr(0, match.start(1));
33 auto end = pathv.substr(match.end(1));
34 return cmStrCat(begin, origin, end);
36 if (originCurlyRegex.find(rpath.c_str(), match)) {
37 cm::string_view pathv(rpath);
38 auto begin = pathv.substr(0, match.start());
39 auto end = pathv.substr(match.end());
40 return cmStrCat(begin, origin, end);
45 cmBinUtilsLinuxELFLinker::cmBinUtilsLinuxELFLinker(
46 cmRuntimeDependencyArchive* archive)
47 : cmBinUtilsLinker(archive)
51 bool cmBinUtilsLinuxELFLinker::Prepare()
53 std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
57 if (tool == "objdump") {
59 cm::make_unique<cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool>(
63 e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
64 this->SetError(e.str());
68 std::string ldConfigTool =
69 this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_TOOL");
70 if (ldConfigTool.empty()) {
71 ldConfigTool = "ldconfig";
73 if (ldConfigTool == "ldconfig") {
75 cm::make_unique<cmLDConfigLDConfigTool>(this->Archive);
78 e << "Invalid value for CMAKE_LDCONFIG_TOOL: " << ldConfigTool;
79 this->SetError(e.str());
86 bool cmBinUtilsLinuxELFLinker::ScanDependencies(
87 std::string const& file, cmStateEnums::TargetType /* unused */)
89 std::vector<std::string> parentRpaths;
91 cmELF elf(file.c_str());
95 if (elf.GetMachine() != 0) {
96 if (this->Machine != 0) {
97 if (elf.GetMachine() != this->Machine) {
98 this->SetError("All files must have the same architecture.");
102 this->Machine = elf.GetMachine();
106 return this->ScanDependencies(file, parentRpaths);
109 bool cmBinUtilsLinuxELFLinker::ScanDependencies(
110 std::string const& file, std::vector<std::string> const& parentRpaths)
112 std::string origin = cmSystemTools::GetFilenamePath(file);
113 std::vector<std::string> needed;
114 std::vector<std::string> rpaths;
115 std::vector<std::string> runpaths;
116 if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
119 for (auto& runpath : runpaths) {
120 runpath = ReplaceOrigin(runpath, origin);
122 for (auto& rpath : rpaths) {
123 rpath = ReplaceOrigin(rpath, origin);
126 std::vector<std::string> searchPaths;
127 if (!runpaths.empty()) {
128 searchPaths = runpaths;
130 searchPaths = rpaths;
131 searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
135 std::vector<std::string> ldConfigPaths;
136 if (!this->LDConfigTool->GetLDConfigPaths(ldConfigPaths)) {
139 searchPaths.insert(searchPaths.end(), ldConfigPaths.begin(),
140 ldConfigPaths.end());
142 for (auto const& dep : needed) {
143 if (!this->Archive->IsPreExcluded(dep)) {
145 bool resolved = false;
146 if (dep.find('/') != std::string::npos) {
147 this->SetError("Paths to dependencies are not supported");
150 if (!this->ResolveDependency(dep, searchPaths, path, resolved)) {
154 if (!this->Archive->IsPostExcluded(path)) {
156 this->Archive->AddResolvedPath(dep, path, unique);
157 if (unique && !this->ScanDependencies(path, rpaths)) {
162 this->Archive->AddUnresolvedPath(dep);
171 bool FileHasArchitecture(const char* filename, std::uint16_t machine)
177 return machine == 0 || machine == elf.GetMachine();
181 bool cmBinUtilsLinuxELFLinker::ResolveDependency(
182 std::string const& name, std::vector<std::string> const& searchPaths,
183 std::string& path, bool& resolved)
185 for (auto const& searchPath : searchPaths) {
186 path = cmStrCat(searchPath, '/', name);
187 if (cmSystemTools::PathExists(path) &&
188 FileHasArchitecture(path.c_str(), this->Machine)) {
194 for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
195 path = cmStrCat(searchPath, '/', name);
196 if (cmSystemTools::PathExists(path) &&
197 FileHasArchitecture(path.c_str(), this->Machine)) {
198 std::ostringstream warning;
199 warning << "Dependency " << name << " found in search directory:\n "
201 << "\nSee file(GET_RUNTIME_DEPENDENCIES) documentation for "
202 << "more information.";
203 this->Archive->GetMakefile()->IssueMessage(MessageType::WARNING,