/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 | | #if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L |
9 | | # include <string_view> // To fix IWYU warning |
10 | | #endif |
11 | | |
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 exclude_from_all, |
19 | | bool all_components, cmListFileBacktrace backtrace) |
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(exclude_from_all) |
25 | 0 | , AllComponents(all_components) |
26 | 0 | , Backtrace(std::move(backtrace)) |
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* permissions_file /* = nullptr */, |
49 | | char const* permissions_dir /* = nullptr */, |
50 | | char const* rename /* = nullptr */, char const* literal_args /* = nullptr */, |
51 | | Indent indent, char const* files_var /* = 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 (files_var) { |
98 | 0 | os << indent << "foreach(_cmake_abs_file IN LISTS " << files_var |
99 | 0 | << ")\n"; |
100 | 0 | os << indent.Next() |
101 | 0 | << "get_filename_component(_cmake_abs_file_name " |
102 | 0 | "\"${_cmake_abs_file}\" NAME)\n"; |
103 | 0 | os << indent.Next() << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES \"" |
104 | 0 | << dest << "/${_cmake_abs_file_name}\")\n"; |
105 | 0 | os << indent << "endforeach()\n"; |
106 | 0 | os << indent << "unset(_cmake_abs_file_name)\n"; |
107 | 0 | os << indent << "unset(_cmake_abs_file)\n"; |
108 | 0 | } |
109 | 0 | os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; |
110 | 0 | os << indent.Next() |
111 | 0 | << "message(WARNING \"ABSOLUTE path INSTALL " |
112 | 0 | "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"; |
113 | 0 | os << indent << "endif()\n"; |
114 | |
|
115 | 0 | os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"; |
116 | 0 | os << indent.Next() |
117 | 0 | << "message(FATAL_ERROR \"ABSOLUTE path INSTALL " |
118 | 0 | "DESTINATION forbidden (by caller): " |
119 | 0 | "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"; |
120 | 0 | os << indent << "endif()\n"; |
121 | 0 | } |
122 | 0 | std::string absDest = ConvertToAbsoluteDestination(dest); |
123 | 0 | os << indent << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " |
124 | 0 | << stype; |
125 | 0 | if (optional) { |
126 | 0 | os << " OPTIONAL"; |
127 | 0 | } |
128 | 0 | switch (this->Message) { |
129 | 0 | case MessageDefault: |
130 | 0 | break; |
131 | 0 | case MessageAlways: |
132 | 0 | os << " MESSAGE_ALWAYS"; |
133 | 0 | break; |
134 | 0 | case MessageLazy: |
135 | 0 | os << " MESSAGE_LAZY"; |
136 | 0 | break; |
137 | 0 | case MessageNever: |
138 | 0 | os << " MESSAGE_NEVER"; |
139 | 0 | break; |
140 | 0 | } |
141 | 0 | if (permissions_file && *permissions_file) { |
142 | 0 | os << " PERMISSIONS" << permissions_file; |
143 | 0 | } |
144 | 0 | if (permissions_dir && *permissions_dir) { |
145 | 0 | os << " DIR_PERMISSIONS" << permissions_dir; |
146 | 0 | } |
147 | 0 | if (rename && *rename) { |
148 | 0 | os << " RENAME \"" << rename << "\""; |
149 | 0 | } |
150 | 0 | os << " FILES"; |
151 | 0 | if (files.size() == 1) { |
152 | 0 | os << " \"" << files[0] << "\""; |
153 | 0 | } else { |
154 | 0 | for (std::string const& f : files) { |
155 | 0 | os << "\n" << indent << " \"" << f << "\""; |
156 | 0 | } |
157 | 0 | if (files_var) { |
158 | 0 | os << " ${" << files_var << "}"; |
159 | 0 | } |
160 | 0 | os << "\n" << indent << " "; |
161 | 0 | if (!(literal_args && *literal_args)) { |
162 | 0 | os << " "; |
163 | 0 | } |
164 | 0 | } |
165 | 0 | if (literal_args && *literal_args) { |
166 | 0 | os << literal_args; |
167 | 0 | } |
168 | 0 | os << ")\n"; |
169 | 0 | } |
170 | | |
171 | | std::string cmInstallGenerator::CreateComponentTest( |
172 | | std::string const& component, bool exclude_from_all, bool all_components) |
173 | 0 | { |
174 | 0 | if (all_components) { |
175 | 0 | if (exclude_from_all) { |
176 | 0 | return "CMAKE_INSTALL_COMPONENT"; |
177 | 0 | } |
178 | 0 | return {}; |
179 | 0 | } |
180 | | |
181 | 0 | std::string result = "CMAKE_INSTALL_COMPONENT STREQUAL \""; |
182 | 0 | result += component; |
183 | 0 | result += "\""; |
184 | 0 | if (!exclude_from_all) { |
185 | 0 | result += " OR NOT CMAKE_INSTALL_COMPONENT"; |
186 | 0 | } |
187 | |
|
188 | 0 | return result; |
189 | 0 | } |
190 | | |
191 | | void cmInstallGenerator::GenerateScript(std::ostream& os) |
192 | 0 | { |
193 | | // Track indentation. |
194 | 0 | Indent indent; |
195 | |
|
196 | 0 | std::string component_test = this->CreateComponentTest( |
197 | 0 | this->Component, this->ExcludeFromAll, this->AllComponents); |
198 | | |
199 | | // Begin this block of installation. |
200 | 0 | if (!component_test.empty()) { |
201 | 0 | os << indent << "if(" << component_test << ")\n"; |
202 | 0 | } |
203 | | |
204 | | // Generate the script possibly with per-configuration code. |
205 | 0 | this->GenerateScriptConfigs(os, |
206 | 0 | this->AllComponents ? indent : indent.Next()); |
207 | | |
208 | | // End this block of installation. |
209 | 0 | if (!component_test.empty()) { |
210 | 0 | os << indent << "endif()\n\n"; |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | bool cmInstallGenerator::InstallsForConfig(std::string const& config) |
215 | 0 | { |
216 | 0 | return this->GeneratesForConfig(config); |
217 | 0 | } |
218 | | |
219 | | std::string cmInstallGenerator::ConvertToAbsoluteDestination( |
220 | | std::string const& dest) |
221 | 0 | { |
222 | 0 | std::string result; |
223 | 0 | if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) { |
224 | 0 | result = "${CMAKE_INSTALL_PREFIX}/"; |
225 | 0 | } |
226 | 0 | result += dest; |
227 | 0 | return result; |
228 | 0 | } |
229 | | |
230 | | cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel( |
231 | | cmMakefile* mf, bool never) |
232 | 0 | { |
233 | 0 | if (never) { |
234 | 0 | return MessageNever; |
235 | 0 | } |
236 | 0 | std::string m = mf->GetSafeDefinition("CMAKE_INSTALL_MESSAGE"); |
237 | 0 | if (m == "ALWAYS") { |
238 | 0 | return MessageAlways; |
239 | 0 | } |
240 | 0 | if (m == "LAZY") { |
241 | 0 | return MessageLazy; |
242 | 0 | } |
243 | 0 | if (m == "NEVER") { |
244 | 0 | return MessageNever; |
245 | 0 | } |
246 | 0 | return MessageDefault; |
247 | 0 | } |
248 | | |
249 | | std::string cmInstallGenerator::GetDestDirPath(std::string const& file) |
250 | 0 | { |
251 | | // Construct the path of the file on disk after installation on |
252 | | // which tweaks may be performed. |
253 | 0 | std::string toDestDirPath = "$ENV{DESTDIR}"; |
254 | 0 | if (file[0] != '/' && file[0] != '$') { |
255 | 0 | toDestDirPath += "/"; |
256 | 0 | } |
257 | 0 | toDestDirPath += file; |
258 | 0 | return toDestDirPath; |
259 | 0 | } |
260 | | |
261 | | void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent, |
262 | | std::string const& config, |
263 | | std::string const& file, |
264 | | TweakMethod const& tweak) |
265 | 0 | { |
266 | 0 | std::ostringstream tw; |
267 | 0 | tweak(tw, indent.Next(), config, file); |
268 | 0 | std::string tws = tw.str(); |
269 | 0 | if (!tws.empty()) { |
270 | 0 | os << indent << "if(EXISTS \"" << file << "\" AND\n" |
271 | 0 | << indent << " NOT IS_SYMLINK \"" << file << "\")\n"; |
272 | 0 | os << tws; |
273 | 0 | os << indent << "endif()\n"; |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | | void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent, |
278 | | std::string const& config, |
279 | | std::string const& dir, |
280 | | std::vector<std::string> const& files, |
281 | | TweakMethod const& tweak) |
282 | 0 | { |
283 | 0 | if (files.size() == 1) { |
284 | | // Tweak a single file. |
285 | 0 | AddTweak(os, indent, config, GetDestDirPath(cmStrCat(dir, files[0])), |
286 | 0 | tweak); |
287 | 0 | } else { |
288 | | // Generate a foreach loop to tweak multiple files. |
289 | 0 | std::ostringstream tw; |
290 | 0 | AddTweak(tw, indent.Next(), config, "${file}", tweak); |
291 | 0 | std::string tws = tw.str(); |
292 | 0 | if (!tws.empty()) { |
293 | 0 | Indent indent2 = indent.Next().Next(); |
294 | 0 | os << indent << "foreach(file\n"; |
295 | 0 | for (std::string const& f : files) { |
296 | 0 | os << indent2 << "\"" << GetDestDirPath(cmStrCat(dir, f)) << "\"\n"; |
297 | 0 | } |
298 | 0 | os << indent2 << ")\n"; |
299 | 0 | os << tws; |
300 | 0 | os << indent << "endforeach()\n"; |
301 | 0 | } |
302 | 0 | } |
303 | 0 | } |