/src/CMake/Source/cmInstallRuntimeDependencySetGenerator.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmInstallRuntimeDependencySetGenerator.h" |
4 | | |
5 | | #include <ostream> |
6 | | #include <string> |
7 | | #include <utility> |
8 | | #include <vector> |
9 | | |
10 | | #include "cmGeneratorExpression.h" |
11 | | #include "cmInstallGenerator.h" |
12 | | #include "cmInstallType.h" |
13 | | #include "cmListFileCache.h" |
14 | | #include "cmLocalGenerator.h" |
15 | | #include "cmMakefile.h" |
16 | | #include "cmMessageType.h" |
17 | | #include "cmScriptGenerator.h" |
18 | | #include "cmStringAlgorithms.h" |
19 | | #include "cmake.h" |
20 | | |
21 | | cmInstallRuntimeDependencySetGenerator::cmInstallRuntimeDependencySetGenerator( |
22 | | DependencyType type, cmInstallRuntimeDependencySet* dependencySet, |
23 | | std::vector<std::string> installRPaths, bool noInstallRPath, |
24 | | std::string installNameDir, bool noInstallName, char const* depsVar, |
25 | | char const* rpathPrefix, char const* tmpVarPrefix, std::string destination, |
26 | | std::vector<std::string> const& configurations, std::string component, |
27 | | std::string permissions, MessageLevel message, bool exclude_from_all, |
28 | | cmListFileBacktrace backtrace) |
29 | 0 | : cmInstallGenerator(std::move(destination), configurations, |
30 | 0 | std::move(component), message, exclude_from_all, false, |
31 | 0 | std::move(backtrace)) |
32 | 0 | , Type(type) |
33 | 0 | , DependencySet(dependencySet) |
34 | 0 | , InstallRPaths(std::move(installRPaths)) |
35 | 0 | , NoInstallRPath(noInstallRPath) |
36 | 0 | , InstallNameDir(std::move(installNameDir)) |
37 | 0 | , NoInstallName(noInstallName) |
38 | 0 | , Permissions(std::move(permissions)) |
39 | 0 | , DepsVar(depsVar) |
40 | 0 | , RPathPrefix(rpathPrefix) |
41 | 0 | , TmpVarPrefix(tmpVarPrefix) |
42 | 0 | { |
43 | 0 | this->ActionsPerConfig = true; |
44 | 0 | } |
45 | | |
46 | | bool cmInstallRuntimeDependencySetGenerator::Compute(cmLocalGenerator* lg) |
47 | 0 | { |
48 | 0 | this->LocalGenerator = lg; |
49 | 0 | return true; |
50 | 0 | } |
51 | | |
52 | | void cmInstallRuntimeDependencySetGenerator::GenerateScriptForConfig( |
53 | | std::ostream& os, std::string const& config, Indent indent) |
54 | 0 | { |
55 | 0 | if (!this->LocalGenerator->GetMakefile() |
56 | 0 | ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL") |
57 | 0 | .empty() && |
58 | 0 | !this->NoInstallName) { |
59 | 0 | std::string installNameDir = "@rpath/"; |
60 | 0 | if (!this->InstallNameDir.empty()) { |
61 | 0 | installNameDir = this->InstallNameDir; |
62 | 0 | cmGeneratorExpression::ReplaceInstallPrefix(installNameDir, |
63 | 0 | "${CMAKE_INSTALL_PREFIX}"); |
64 | 0 | installNameDir = cmGeneratorExpression::Evaluate( |
65 | 0 | installNameDir, this->LocalGenerator, config); |
66 | 0 | if (installNameDir.empty()) { |
67 | 0 | this->LocalGenerator->GetMakefile()->GetCMakeInstance()->IssueMessage( |
68 | 0 | MessageType::FATAL_ERROR, |
69 | 0 | "INSTALL_NAME_DIR argument must not evaluate to an " |
70 | 0 | "empty string", |
71 | 0 | this->Backtrace); |
72 | 0 | return; |
73 | 0 | } |
74 | 0 | if (installNameDir.back() != '/') { |
75 | 0 | installNameDir += '/'; |
76 | 0 | } |
77 | 0 | } |
78 | 0 | os << indent << "set(" << this->TmpVarPrefix << "_install_name_dir \"" |
79 | 0 | << installNameDir << "\")\n"; |
80 | 0 | } |
81 | | |
82 | 0 | os << indent << "foreach(" << this->TmpVarPrefix << "_dep IN LISTS " |
83 | 0 | << this->DepsVar << ")\n"; |
84 | |
|
85 | 0 | if (!this->LocalGenerator->GetMakefile() |
86 | 0 | ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL") |
87 | 0 | .empty()) { |
88 | 0 | std::vector<std::string> evaluatedRPaths; |
89 | 0 | for (auto const& rpath : this->InstallRPaths) { |
90 | 0 | std::string result = |
91 | 0 | cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config); |
92 | 0 | if (!result.empty()) { |
93 | 0 | evaluatedRPaths.push_back(std::move(result)); |
94 | 0 | } |
95 | 0 | } |
96 | |
|
97 | 0 | switch (this->Type) { |
98 | 0 | case DependencyType::Library: |
99 | 0 | this->GenerateAppleLibraryScript(os, config, evaluatedRPaths, |
100 | 0 | indent.Next()); |
101 | 0 | break; |
102 | 0 | case DependencyType::Framework: |
103 | 0 | this->GenerateAppleFrameworkScript(os, config, evaluatedRPaths, |
104 | 0 | indent.Next()); |
105 | 0 | break; |
106 | 0 | } |
107 | 0 | } else { |
108 | 0 | std::string depVar = cmStrCat(this->TmpVarPrefix, "_dep"); |
109 | |
|
110 | 0 | this->AddInstallRule( |
111 | 0 | os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, |
112 | 0 | false, this->Permissions.c_str(), nullptr, nullptr, |
113 | 0 | " FOLLOW_SYMLINK_CHAIN", indent.Next(), depVar.c_str()); |
114 | |
|
115 | 0 | if (this->LocalGenerator->GetMakefile()->GetSafeDefinition( |
116 | 0 | "CMAKE_SYSTEM_NAME") == "Linux" && |
117 | 0 | !this->NoInstallRPath) { |
118 | 0 | std::string evaluatedRPath; |
119 | 0 | for (auto const& rpath : this->InstallRPaths) { |
120 | 0 | std::string result = |
121 | 0 | cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config); |
122 | 0 | if (!result.empty()) { |
123 | 0 | if (evaluatedRPath.empty()) { |
124 | 0 | evaluatedRPath = std::move(result); |
125 | 0 | } else { |
126 | 0 | evaluatedRPath += ':'; |
127 | 0 | evaluatedRPath += result; |
128 | 0 | } |
129 | 0 | } |
130 | 0 | } |
131 | |
|
132 | 0 | os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix |
133 | 0 | << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n"; |
134 | 0 | if (evaluatedRPath.empty()) { |
135 | 0 | os << indent.Next() << "file(RPATH_REMOVE FILE \"" |
136 | 0 | << GetDestDirPath( |
137 | 0 | ConvertToAbsoluteDestination(this->GetDestination(config))) |
138 | 0 | << "/${" << this->TmpVarPrefix << "_dep_name}\")\n"; |
139 | 0 | } else { |
140 | 0 | os << indent.Next() << "file(RPATH_SET FILE \"" |
141 | 0 | << GetDestDirPath( |
142 | 0 | ConvertToAbsoluteDestination(this->GetDestination(config))) |
143 | 0 | << "/${" << this->TmpVarPrefix << "_dep_name}\" NEW_RPATH " |
144 | 0 | << cmScriptGenerator::Quote(evaluatedRPath) << ")\n"; |
145 | 0 | } |
146 | 0 | } |
147 | 0 | } |
148 | | |
149 | 0 | os << indent << "endforeach()\n"; |
150 | 0 | } |
151 | | |
152 | | void cmInstallRuntimeDependencySetGenerator::GenerateAppleLibraryScript( |
153 | | std::ostream& os, std::string const& config, |
154 | | std::vector<std::string> const& evaluatedRPaths, Indent indent) |
155 | 0 | { |
156 | 0 | os << indent << "if(NOT " << this->TmpVarPrefix |
157 | 0 | << "_dep MATCHES \"\\\\.framework/\")\n"; |
158 | |
|
159 | 0 | auto depName = cmStrCat(this->TmpVarPrefix, "_dep"); |
160 | 0 | this->AddInstallRule( |
161 | 0 | os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, false, |
162 | 0 | this->Permissions.c_str(), nullptr, nullptr, " FOLLOW_SYMLINK_CHAIN", |
163 | 0 | indent.Next(), depName.c_str()); |
164 | |
|
165 | 0 | os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix |
166 | 0 | << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n"; |
167 | 0 | auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_dep_name}"); |
168 | 0 | this->GenerateInstallNameFixup(os, config, evaluatedRPaths, |
169 | 0 | cmStrCat("${", this->TmpVarPrefix, "_dep}"), |
170 | 0 | depNameVar, indent.Next()); |
171 | |
|
172 | 0 | os << indent << "endif()\n"; |
173 | 0 | } |
174 | | |
175 | | void cmInstallRuntimeDependencySetGenerator::GenerateAppleFrameworkScript( |
176 | | std::ostream& os, std::string const& config, |
177 | | std::vector<std::string> const& evaluatedRPaths, Indent indent) |
178 | 0 | { |
179 | 0 | os << indent << "if(" << this->TmpVarPrefix |
180 | 0 | << "_dep MATCHES \"^(.*/)?([^/]*\\\\.framework)/(.*)$\")\n" |
181 | 0 | << indent.Next() << "set(" << this->TmpVarPrefix |
182 | 0 | << "_dir \"${CMAKE_MATCH_1}\")\n" |
183 | 0 | << indent.Next() << "set(" << this->TmpVarPrefix |
184 | 0 | << "_name \"${CMAKE_MATCH_2}\")\n" |
185 | 0 | << indent.Next() << "set(" << this->TmpVarPrefix |
186 | 0 | << "_file \"${CMAKE_MATCH_3}\")\n" |
187 | 0 | << indent.Next() << "set(" << this->TmpVarPrefix << "_path \"${" |
188 | 0 | << this->TmpVarPrefix << "_dir}${" << this->TmpVarPrefix << "_name}\")\n"; |
189 | |
|
190 | 0 | auto depName = cmStrCat(this->TmpVarPrefix, "_path"); |
191 | 0 | this->AddInstallRule( |
192 | 0 | os, this->GetDestination(config), cmInstallType_DIRECTORY, {}, false, |
193 | 0 | this->Permissions.c_str(), nullptr, nullptr, " USE_SOURCE_PERMISSIONS", |
194 | 0 | indent.Next(), depName.c_str()); |
195 | |
|
196 | 0 | auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_name}/${", |
197 | 0 | this->TmpVarPrefix, "_file}"); |
198 | 0 | this->GenerateInstallNameFixup(os, config, evaluatedRPaths, |
199 | 0 | cmStrCat("${", this->TmpVarPrefix, "_dep}"), |
200 | 0 | depNameVar, indent.Next()); |
201 | |
|
202 | 0 | os << indent << "endif()\n"; |
203 | 0 | } |
204 | | |
205 | | void cmInstallRuntimeDependencySetGenerator::GenerateInstallNameFixup( |
206 | | std::ostream& os, std::string const& config, |
207 | | std::vector<std::string> const& evaluatedRPaths, std::string const& filename, |
208 | | std::string const& depName, Indent indent) |
209 | 0 | { |
210 | 0 | if (!(this->NoInstallRPath && this->NoInstallName)) { |
211 | 0 | auto indent2 = indent; |
212 | 0 | if (evaluatedRPaths.empty() && this->NoInstallName) { |
213 | 0 | indent2 = indent2.Next(); |
214 | 0 | os << indent << "if(" << this->RPathPrefix << "_" << filename << ")\n"; |
215 | 0 | } |
216 | 0 | os << indent2 << "set(" << this->TmpVarPrefix << "_rpath_args)\n"; |
217 | 0 | if (!this->NoInstallRPath) { |
218 | 0 | os << indent2 << "foreach(" << this->TmpVarPrefix << "_rpath IN LISTS " |
219 | 0 | << this->RPathPrefix << '_' << filename << ")\n" |
220 | 0 | << indent2.Next() << "list(APPEND " << this->TmpVarPrefix |
221 | 0 | << "_rpath_args -delete_rpath \"${" << this->TmpVarPrefix |
222 | 0 | << "_rpath}\")\n" |
223 | 0 | << indent2 << "endforeach()\n"; |
224 | 0 | } |
225 | 0 | os << indent2 << "execute_process(COMMAND \"" |
226 | 0 | << this->LocalGenerator->GetMakefile()->GetSafeDefinition( |
227 | 0 | "CMAKE_INSTALL_NAME_TOOL") |
228 | 0 | << "\" ${" << this->TmpVarPrefix << "_rpath_args}\n"; |
229 | 0 | if (!this->NoInstallRPath) { |
230 | 0 | for (auto const& rpath : evaluatedRPaths) { |
231 | 0 | os << indent2 << " -add_rpath " << cmScriptGenerator::Quote(rpath) |
232 | 0 | << '\n'; |
233 | 0 | } |
234 | 0 | } |
235 | 0 | if (!this->NoInstallName) { |
236 | 0 | os << indent2 << " -id \"${" << this->TmpVarPrefix |
237 | 0 | << "_install_name_dir}" << depName << "\"\n"; |
238 | 0 | } |
239 | 0 | os << indent2 << " \"" |
240 | 0 | << GetDestDirPath( |
241 | 0 | ConvertToAbsoluteDestination(this->GetDestination(config))) |
242 | 0 | << "/" << depName << "\")\n"; |
243 | 0 | if (evaluatedRPaths.empty() && this->NoInstallName) { |
244 | 0 | os << indent << "endif()\n"; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | | |
249 | | void cmInstallRuntimeDependencySetGenerator::GenerateStripFixup( |
250 | | std::ostream& os, std::string const& config, std::string const& depName, |
251 | | Indent indent) |
252 | 0 | { |
253 | 0 | std::string strip = |
254 | 0 | this->LocalGenerator->GetMakefile()->GetSafeDefinition("CMAKE_STRIP"); |
255 | 0 | if (!strip.empty()) { |
256 | 0 | os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n" |
257 | 0 | << indent.Next() << "execute_process(COMMAND \"" << strip << "\" "; |
258 | 0 | if (this->LocalGenerator->GetMakefile()->IsOn("APPLE")) { |
259 | 0 | os << "-x "; |
260 | 0 | } |
261 | 0 | os << "\"" |
262 | 0 | << GetDestDirPath( |
263 | 0 | ConvertToAbsoluteDestination(this->GetDestination(config))) |
264 | 0 | << "/" << depName << "\")\n" |
265 | 0 | << indent << "endif()\n"; |
266 | 0 | } |
267 | 0 | } |
268 | | |
269 | | std::string cmInstallRuntimeDependencySetGenerator::GetDestination( |
270 | | std::string const& config) const |
271 | 0 | { |
272 | 0 | return cmGeneratorExpression::Evaluate(this->Destination, |
273 | 0 | this->LocalGenerator, config); |
274 | 0 | } |