/src/CMake/Source/cmInstallGenerator.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 "cmInstallGenerator.h" |
4 | | |
5 | | #include <sstream> |
6 | | #include <utility> |
7 | | |
8 | | #include <cm/string_view> |
9 | | |
10 | | #include "cmDiagnostics.h" |
11 | | #include "cmLocalGenerator.h" |
12 | | #include "cmMakefile.h" |
13 | | #include "cmStringAlgorithms.h" |
14 | | #include "cmSystemTools.h" |
15 | | |
16 | | cmInstallGenerator::cmInstallGenerator( |
17 | | std::string destination, std::vector<std::string> const& configurations, |
18 | | std::string component, MessageLevel message, bool excludeFromAll, |
19 | | bool allComponents, cmDiagnosticContext context) |
20 | 0 | : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations) |
21 | 0 | , Destination(std::move(destination)) |
22 | 0 | , Component(std::move(component)) |
23 | 0 | , Message(message) |
24 | 0 | , ExcludeFromAll(excludeFromAll) |
25 | 0 | , AllComponents(allComponents) |
26 | 0 | , Context{ std::move(context) } |
27 | 0 | { |
28 | 0 | } |
29 | | |
30 | 0 | cmInstallGenerator::~cmInstallGenerator() = default; |
31 | | |
32 | | bool cmInstallGenerator::HaveInstall() |
33 | 0 | { |
34 | 0 | return true; |
35 | 0 | } |
36 | | |
37 | | void cmInstallGenerator::CheckCMP0082(bool& haveSubdirectoryInstall, |
38 | | bool& haveInstallAfterSubdirectory) |
39 | 0 | { |
40 | 0 | if (haveSubdirectoryInstall) { |
41 | 0 | haveInstallAfterSubdirectory = true; |
42 | 0 | } |
43 | 0 | } |
44 | | |
45 | | void cmInstallGenerator::AddInstallRule( |
46 | | std::ostream& os, std::string const& dest, cmInstallType type, |
47 | | std::vector<std::string> const& files, bool optional /* = false */, |
48 | | char const* permissionsFile /* = nullptr */, |
49 | | char const* permissionsDir /* = nullptr */, |
50 | | char const* rename /* = nullptr */, char const* literalArgs /* = nullptr */, |
51 | | Indent indent, char const* filesVar /* = nullptr */) |
52 | 0 | { |
53 | | // Use the FILE command to install the file. |
54 | 0 | std::string stype; |
55 | 0 | switch (type) { |
56 | 0 | case cmInstallType_DIRECTORY: |
57 | 0 | stype = "DIRECTORY"; |
58 | 0 | break; |
59 | 0 | case cmInstallType_PROGRAMS: |
60 | 0 | stype = "PROGRAM"; |
61 | 0 | break; |
62 | 0 | case cmInstallType_EXECUTABLE: |
63 | 0 | stype = "EXECUTABLE"; |
64 | 0 | break; |
65 | 0 | case cmInstallType_STATIC_LIBRARY: |
66 | 0 | stype = "STATIC_LIBRARY"; |
67 | 0 | break; |
68 | 0 | case cmInstallType_SHARED_LIBRARY: |
69 | 0 | stype = "SHARED_LIBRARY"; |
70 | 0 | break; |
71 | 0 | case cmInstallType_MODULE_LIBRARY: |
72 | 0 | stype = "MODULE"; |
73 | 0 | break; |
74 | 0 | case cmInstallType_FILES: |
75 | 0 | stype = "FILE"; |
76 | 0 | break; |
77 | 0 | } |
78 | 0 | if (cmSystemTools::FileIsFullPath(dest)) { |
79 | 0 | if (!files.empty()) { |
80 | 0 | os << indent << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"; |
81 | 0 | os << indent << " \""; |
82 | 0 | bool firstIteration = true; |
83 | 0 | for (std::string const& file : files) { |
84 | 0 | if (!firstIteration) { |
85 | 0 | os << ";"; |
86 | 0 | } |
87 | 0 | os << dest << "/"; |
88 | 0 | if (rename && *rename) { |
89 | 0 | os << rename; |
90 | 0 | } else { |
91 | 0 | os << cmSystemTools::GetFilenameNameView(file); |
92 | 0 | } |
93 | 0 | firstIteration = false; |
94 | 0 | } |
95 | 0 | os << "\")\n"; |
96 | 0 | } |
97 | 0 | if (filesVar) { |
98 | 0 | os << indent << "foreach(_cmake_abs_file IN LISTS " << filesVar << ")\n"; |
99 | 0 | os << indent.Next() |
100 | 0 | << "get_filename_component(_cmake_abs_file_name " |
101 | 0 | "\"${_cmake_abs_file}\" NAME)\n"; |
102 | 0 | os << indent.Next() << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES \"" |
103 | 0 | << dest << "/${_cmake_abs_file_name}\")\n"; |
104 | 0 | os << indent << "endforeach()\n"; |
105 | 0 | os << indent << "unset(_cmake_abs_file_name)\n"; |
106 | 0 | os << indent << "unset(_cmake_abs_file)\n"; |
107 | 0 | } |
108 | 0 | os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; |
109 | 0 | os << indent.Next() |
110 | 0 | << "message(WARNING \"ABSOLUTE path INSTALL " |
111 | 0 | "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"; |
112 | 0 | os << indent << "endif()\n"; |
113 | |
|
114 | 0 | os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; |
115 | 0 | os << indent.Next() |
116 | 0 | << "message(FATAL_ERROR \"ABSOLUTE path INSTALL " |
117 | 0 | "DESTINATION forbidden (by caller): " |
118 | 0 | "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"; |
119 | 0 | os << indent << "endif()\n"; |
120 | 0 | } |
121 | 0 | std::string absDest = ConvertToAbsoluteDestination(dest); |
122 | 0 | os << indent << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " |
123 | 0 | << stype; |
124 | 0 | if (optional) { |
125 | 0 | os << " OPTIONAL"; |
126 | 0 | } |
127 | 0 | switch (this->Message) { |
128 | 0 | case MessageDefault: |
129 | 0 | break; |
130 | 0 | case MessageAlways: |
131 | 0 | os << " MESSAGE_ALWAYS"; |
132 | 0 | break; |
133 | 0 | case MessageLazy: |
134 | 0 | os << " MESSAGE_LAZY"; |
135 | 0 | break; |
136 | 0 | case MessageNever: |
137 | 0 | os << " MESSAGE_NEVER"; |
138 | 0 | break; |
139 | 0 | } |
140 | 0 | if (permissionsFile && *permissionsFile) { |
141 | 0 | os << " PERMISSIONS" << permissionsFile; |
142 | 0 | } |
143 | 0 | if (permissionsDir && *permissionsDir) { |
144 | 0 | os << " DIR_PERMISSIONS" << permissionsDir; |
145 | 0 | } |
146 | 0 | if (rename && *rename) { |
147 | 0 | os << " RENAME \"" << rename << "\""; |
148 | 0 | } |
149 | 0 | os << " FILES"; |
150 | 0 | if (files.size() == 1) { |
151 | 0 | os << " \"" << files[0] << "\""; |
152 | 0 | } else { |
153 | 0 | for (std::string const& f : files) { |
154 | 0 | os << "\n" << indent << " \"" << f << "\""; |
155 | 0 | } |
156 | 0 | if (filesVar) { |
157 | 0 | os << " ${" << filesVar << "}"; |
158 | 0 | } |
159 | 0 | os << "\n" << indent << " "; |
160 | 0 | if (!(literalArgs && *literalArgs)) { |
161 | 0 | os << " "; |
162 | 0 | } |
163 | 0 | } |
164 | 0 | if (literalArgs && *literalArgs) { |
165 | 0 | os << literalArgs; |
166 | 0 | } |
167 | 0 | os << ")\n"; |
168 | 0 | } |
169 | | |
170 | | std::string cmInstallGenerator::CreateComponentTest( |
171 | | std::string const& component, bool excludeFromAll, bool allComponents) |
172 | 0 | { |
173 | 0 | if (allComponents) { |
174 | 0 | if (excludeFromAll) { |
175 | 0 | return "CMAKE_INSTALL_COMPONENT"; |
176 | 0 | } |
177 | 0 | return {}; |
178 | 0 | } |
179 | | |
180 | 0 | std::string result = "CMAKE_INSTALL_COMPONENT STREQUAL \""; |
181 | 0 | result += component; |
182 | 0 | result += "\""; |
183 | 0 | if (!excludeFromAll) { |
184 | 0 | result += " OR NOT CMAKE_INSTALL_COMPONENT"; |
185 | 0 | } |
186 | |
|
187 | 0 | return result; |
188 | 0 | } |
189 | | |
190 | | void cmInstallGenerator::GenerateScript(std::ostream& os) |
191 | 0 | { |
192 | | // Track indentation. |
193 | 0 | Indent indent; |
194 | |
|
195 | 0 | std::string componentTest = this->CreateComponentTest( |
196 | 0 | this->Component, this->ExcludeFromAll, this->AllComponents); |
197 | | |
198 | | // Begin this block of installation. |
199 | 0 | if (!componentTest.empty()) { |
200 | 0 | os << indent << "if(" << componentTest << ")\n"; |
201 | 0 | } |
202 | | |
203 | | // Generate the script possibly with per-configuration code. |
204 | 0 | this->GenerateScriptConfigs(os, |
205 | 0 | this->AllComponents ? indent : indent.Next()); |
206 | | |
207 | | // End this block of installation. |
208 | 0 | if (!componentTest.empty()) { |
209 | 0 | os << indent << "endif()\n\n"; |
210 | 0 | } |
211 | 0 | } |
212 | | |
213 | | bool cmInstallGenerator::InstallsForConfig(std::string const& config) |
214 | 0 | { |
215 | 0 | return this->GeneratesForConfig(config); |
216 | 0 | } |
217 | | |
218 | | std::string cmInstallGenerator::ConvertToAbsoluteDestination( |
219 | | std::string const& dest) |
220 | 0 | { |
221 | 0 | if (dest == ".") { |
222 | 0 | return "${CMAKE_INSTALL_PREFIX}"; |
223 | 0 | } |
224 | | |
225 | 0 | std::string result; |
226 | 0 | if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) { |
227 | 0 | result = "${CMAKE_INSTALL_PREFIX}/"; |
228 | 0 | } |
229 | 0 | result += dest; |
230 | 0 | return result; |
231 | 0 | } |
232 | | |
233 | | void cmInstallGenerator::CheckAbsoluteDestination(std::string const& dest, |
234 | | cmLocalGenerator* lg) const |
235 | 0 | { |
236 | 0 | if (!cmSystemTools::FileIsFullPath(dest)) { |
237 | 0 | return; |
238 | 0 | } |
239 | 0 | lg->IssueDiagnostic( |
240 | 0 | cmDiagnostics::CMD_INSTALL_ABSOLUTE_DESTINATION, |
241 | 0 | cmStrCat("INSTALL command given absolute DESTINATION path:\n ", dest), |
242 | 0 | this->Context); |
243 | 0 | } |
244 | | |
245 | | cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel( |
246 | | cmMakefile* mf, bool never) |
247 | 0 | { |
248 | 0 | if (never) { |
249 | 0 | return MessageNever; |
250 | 0 | } |
251 | 0 | std::string m = mf->GetSafeDefinition("CMAKE_INSTALL_MESSAGE"); |
252 | 0 | if (m == "ALWAYS") { |
253 | 0 | return MessageAlways; |
254 | 0 | } |
255 | 0 | if (m == "LAZY") { |
256 | 0 | return MessageLazy; |
257 | 0 | } |
258 | 0 | if (m == "NEVER") { |
259 | 0 | return MessageNever; |
260 | 0 | } |
261 | 0 | return MessageDefault; |
262 | 0 | } |
263 | | |
264 | | cmDiagnosticContext cmInstallGenerator::CaptureContext(cmMakefile const& mf) |
265 | 0 | { |
266 | 0 | cmDiagnosticContext context{ mf.GetBacktrace() }; |
267 | 0 | context.RecordDiagnostic(cmDiagnostics::CMD_INSTALL_ABSOLUTE_DESTINATION, |
268 | 0 | mf.GetStateSnapshot()); |
269 | 0 | return context; |
270 | 0 | } |
271 | | |
272 | | std::string cmInstallGenerator::GetDestDirPath(std::string const& file) |
273 | 0 | { |
274 | | // Construct the path of the file on disk after installation on |
275 | | // which tweaks may be performed. |
276 | 0 | std::string toDestDirPath = "$ENV{DESTDIR}"; |
277 | 0 | if (file[0] != '/' && file[0] != '$') { |
278 | 0 | toDestDirPath += "/"; |
279 | 0 | } |
280 | 0 | toDestDirPath += file; |
281 | 0 | return toDestDirPath; |
282 | 0 | } |
283 | | |
284 | | void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent, |
285 | | std::string const& config, |
286 | | std::string const& file, |
287 | | TweakMethod const& tweak) |
288 | 0 | { |
289 | 0 | std::ostringstream tw; |
290 | 0 | tweak(tw, indent.Next(), config, file); |
291 | 0 | std::string tws = tw.str(); |
292 | 0 | if (!tws.empty()) { |
293 | 0 | os << indent << "if(EXISTS \"" << file << "\" AND\n" |
294 | 0 | << indent << " NOT IS_SYMLINK \"" << file << "\")\n"; |
295 | 0 | os << tws; |
296 | 0 | os << indent << "endif()\n"; |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | | void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent, |
301 | | std::string const& config, |
302 | | std::string const& dir, |
303 | | std::vector<std::string> const& files, |
304 | | TweakMethod const& tweak) |
305 | 0 | { |
306 | 0 | if (files.size() == 1) { |
307 | | // Tweak a single file. |
308 | 0 | AddTweak(os, indent, config, GetDestDirPath(cmStrCat(dir, files[0])), |
309 | 0 | tweak); |
310 | 0 | } else { |
311 | | // Generate a foreach loop to tweak multiple files. |
312 | 0 | std::ostringstream tw; |
313 | 0 | AddTweak(tw, indent.Next(), config, "${file}", tweak); |
314 | 0 | std::string tws = tw.str(); |
315 | 0 | if (!tws.empty()) { |
316 | 0 | Indent indent2 = indent.Next().Next(); |
317 | 0 | os << indent << "foreach(file\n"; |
318 | 0 | for (std::string const& f : files) { |
319 | 0 | os << indent2 << "\"" << GetDestDirPath(cmStrCat(dir, f)) << "\"\n"; |
320 | 0 | } |
321 | 0 | os << indent2 << ")\n"; |
322 | 0 | os << tws; |
323 | 0 | os << indent << "endforeach()\n"; |
324 | 0 | } |
325 | 0 | } |
326 | 0 | } |