Imported Upstream version 3.19.4
[platform/upstream/cmake.git] / Source / cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
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::
14   cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
15     cmRuntimeDependencyArchive* archive)
16   : cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(archive)
17 {
18 }
19
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 }