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