1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3
4 #include "cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h"
5
6 #include <sstream>
7
8 #include <cmsys/RegularExpression.hxx>
9
10 #include "cmRuntimeDependencyArchive.h"
11 #include "cmUVProcessChain.h"
12
13 cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::
cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(cmRuntimeDependencyArchive * archive)14 cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
15 cmRuntimeDependencyArchive* archive)
16 : cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(archive)
17 {
18 }
19
GetFileInfo(std::string const & file,std::vector<std::string> & libs,std::vector<std::string> & rpaths)20 bool cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::GetFileInfo(
21 std::string const& file, std::vector<std::string>& libs,
22 std::vector<std::string>& rpaths)
23 {
24 std::vector<std::string> command;
25 if (!this->Archive->GetGetRuntimeDependenciesCommand("otool", command)) {
26 this->SetError("Could not find otool");
27 return false;
28 }
29 command.emplace_back("-l");
30 command.emplace_back(file);
31
32 cmUVProcessChainBuilder builder;
33 builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
34 .AddCommand(command);
35
36 auto process = builder.Start();
37 if (!process.Valid()) {
38 std::ostringstream e;
39 e << "Failed to start otool process for:\n " << file;
40 this->SetError(e.str());
41 return false;
42 }
43
44 std::string line;
45 static const cmsys::RegularExpression rpathRegex("^ *cmd LC_RPATH$");
46 static const cmsys::RegularExpression loadDylibRegex(
47 "^ *cmd LC_LOAD(_WEAK)?_DYLIB$");
48 static const cmsys::RegularExpression pathRegex(
49 "^ *path (.*) \\(offset [0-9]+\\)$");
50 static const cmsys::RegularExpression nameRegex(
51 "^ *name (.*) \\(offset [0-9]+\\)$");
52 while (std::getline(*process.OutputStream(), line)) {
53 cmsys::RegularExpressionMatch cmdMatch;
54 if (rpathRegex.find(line.c_str(), cmdMatch)) {
55 if (!std::getline(*process.OutputStream(), line) ||
56 !std::getline(*process.OutputStream(), line)) {
57 this->SetError("Invalid output from otool");
58 return false;
59 }
60
61 cmsys::RegularExpressionMatch pathMatch;
62 if (pathRegex.find(line.c_str(), pathMatch)) {
63 rpaths.push_back(pathMatch.match(1));
64 } else {
65 this->SetError("Invalid output from otool");
66 return false;
67 }
68 } else if (loadDylibRegex.find(line.c_str(), cmdMatch)) {
69 if (!std::getline(*process.OutputStream(), line) ||
70 !std::getline(*process.OutputStream(), line)) {
71 this->SetError("Invalid output from otool");
72 return false;
73 }
74
75 cmsys::RegularExpressionMatch nameMatch;
76 if (nameRegex.find(line.c_str(), nameMatch)) {
77 libs.push_back(nameMatch.match(1));
78 } else {
79 this->SetError("Invalid output from otool");
80 return false;
81 }
82 }
83 }
84
85 if (!process.Wait()) {
86 std::ostringstream e;
87 e << "Failed to wait on otool process for:\n " << file;
88 this->SetError(e.str());
89 return false;
90 }
91 auto status = process.GetStatus();
92 if (!status[0] || status[0]->ExitStatus != 0) {
93 std::ostringstream e;
94 e << "Failed to run otool on:\n " << file;
95 this->SetError(e.str());
96 return false;
97 }
98
99 return true;
100 }
101