/src/CMake/Source/cmQtAutoGenGlobalInitializer.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 "cmQtAutoGenGlobalInitializer.h" |
4 | | |
5 | | #include <set> |
6 | | #include <utility> |
7 | | |
8 | | #include <cm/memory> |
9 | | |
10 | | #include "cmCustomCommand.h" |
11 | | #include "cmDuration.h" |
12 | | #include "cmGeneratorTarget.h" |
13 | | #include "cmLocalGenerator.h" |
14 | | #include "cmMakefile.h" |
15 | | #include "cmMessageType.h" |
16 | | #include "cmProcessOutput.h" |
17 | | #include "cmQtAutoGen.h" |
18 | | #include "cmQtAutoGenInitializer.h" |
19 | | #include "cmState.h" |
20 | | #include "cmStateTypes.h" |
21 | | #include "cmStringAlgorithms.h" |
22 | | #include "cmSystemTools.h" |
23 | | #include "cmTarget.h" |
24 | | #include "cmValue.h" |
25 | | |
26 | | cmQtAutoGenGlobalInitializer::Keywords::Keywords() |
27 | 0 | : AUTOMOC("AUTOMOC") |
28 | 0 | , AUTOUIC("AUTOUIC") |
29 | 0 | , AUTORCC("AUTORCC") |
30 | 0 | , AUTOMOC_EXECUTABLE("AUTOMOC_EXECUTABLE") |
31 | 0 | , AUTOUIC_EXECUTABLE("AUTOUIC_EXECUTABLE") |
32 | 0 | , AUTORCC_EXECUTABLE("AUTORCC_EXECUTABLE") |
33 | 0 | , SKIP_AUTOGEN("SKIP_AUTOGEN") |
34 | 0 | , SKIP_AUTOMOC("SKIP_AUTOMOC") |
35 | 0 | , SKIP_AUTOUIC("SKIP_AUTOUIC") |
36 | 0 | , SKIP_AUTORCC("SKIP_AUTORCC") |
37 | 0 | , AUTOUIC_OPTIONS("AUTOUIC_OPTIONS") |
38 | 0 | , AUTORCC_OPTIONS("AUTORCC_OPTIONS") |
39 | 0 | , qrc("qrc") |
40 | 0 | , ui("ui") |
41 | 0 | { |
42 | 0 | } |
43 | | |
44 | | cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( |
45 | | std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators) |
46 | 0 | { |
47 | 0 | for (auto const& localGen : localGenerators) { |
48 | | // Detect global autogen and autorcc target names |
49 | 0 | bool globalAutoGenTarget = false; |
50 | 0 | bool globalAutoRccTarget = false; |
51 | 0 | { |
52 | 0 | cmMakefile const* makefile = localGen->GetMakefile(); |
53 | | // Detect global autogen target name |
54 | 0 | if (makefile->IsOn("CMAKE_GLOBAL_AUTOGEN_TARGET")) { |
55 | 0 | std::string targetName = |
56 | 0 | makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME"); |
57 | 0 | if (targetName.empty()) { |
58 | 0 | targetName = "autogen"; |
59 | 0 | } |
60 | 0 | this->GlobalAutoGenTargets_.emplace(localGen.get(), |
61 | 0 | std::move(targetName)); |
62 | 0 | globalAutoGenTarget = true; |
63 | 0 | } |
64 | | |
65 | | // Detect global autorcc target name |
66 | 0 | if (makefile->IsOn("CMAKE_GLOBAL_AUTORCC_TARGET")) { |
67 | 0 | std::string targetName = |
68 | 0 | makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME"); |
69 | 0 | if (targetName.empty()) { |
70 | 0 | targetName = "autorcc"; |
71 | 0 | } |
72 | 0 | this->GlobalAutoRccTargets_.emplace(localGen.get(), |
73 | 0 | std::move(targetName)); |
74 | 0 | globalAutoRccTarget = true; |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | // Find targets that require AUTOMOC/UIC/RCC processing |
79 | 0 | for (auto const& target : localGen->GetGeneratorTargets()) { |
80 | | // Process only certain target types |
81 | 0 | switch (target->GetType()) { |
82 | 0 | case cmStateEnums::EXECUTABLE: |
83 | 0 | case cmStateEnums::STATIC_LIBRARY: |
84 | 0 | case cmStateEnums::SHARED_LIBRARY: |
85 | 0 | case cmStateEnums::MODULE_LIBRARY: |
86 | 0 | case cmStateEnums::OBJECT_LIBRARY: |
87 | | // Process target |
88 | 0 | break; |
89 | 0 | default: |
90 | | // Don't process target |
91 | 0 | continue; |
92 | 0 | } |
93 | 0 | if (target->IsImported()) { |
94 | | // Don't process target |
95 | 0 | continue; |
96 | 0 | } |
97 | 0 | std::set<std::string> const& languages = |
98 | 0 | target->GetAllConfigCompileLanguages(); |
99 | | // cmGeneratorTarget::GetAllConfigCompileLanguages caches the target's |
100 | | // sources. Clear it so that OBJECT library targets that are AUTOGEN |
101 | | // initialized after this target get their added mocs_compilation.cpp |
102 | | // source acknowledged by this target. |
103 | 0 | target->ClearSourcesCache(); |
104 | 0 | if (languages.count("CSharp")) { |
105 | | // Don't process target if it's a CSharp target |
106 | 0 | continue; |
107 | 0 | } |
108 | | |
109 | 0 | bool const moc = target->GetPropertyAsBool(this->kw().AUTOMOC); |
110 | 0 | bool const uic = target->GetPropertyAsBool(this->kw().AUTOUIC); |
111 | 0 | bool const rcc = target->GetPropertyAsBool(this->kw().AUTORCC); |
112 | 0 | if (moc || uic || rcc) { |
113 | 0 | std::string const& mocExec = |
114 | 0 | target->GetSafeProperty(this->kw().AUTOMOC_EXECUTABLE); |
115 | 0 | std::string const& uicExec = |
116 | 0 | target->GetSafeProperty(this->kw().AUTOUIC_EXECUTABLE); |
117 | 0 | std::string const& rccExec = |
118 | 0 | target->GetSafeProperty(this->kw().AUTORCC_EXECUTABLE); |
119 | | |
120 | | // We support Qt4, Qt5 and Qt6 |
121 | 0 | auto const qtVersion = |
122 | 0 | cmQtAutoGenInitializer::GetQtVersion(target.get(), mocExec); |
123 | 0 | bool const validQt = (qtVersion.first.Major == 4) || |
124 | 0 | (qtVersion.first.Major == 5) || (qtVersion.first.Major == 6); |
125 | |
|
126 | 0 | bool const mocAvailable = (validQt || !mocExec.empty()); |
127 | 0 | bool const uicAvailable = (validQt || !uicExec.empty()); |
128 | 0 | bool const rccAvailable = (validQt || !rccExec.empty()); |
129 | 0 | bool const mocIsValid = (moc && mocAvailable); |
130 | 0 | bool const uicIsValid = (uic && uicAvailable); |
131 | 0 | bool const rccIsValid = (rcc && rccAvailable); |
132 | | // Disabled AUTOMOC/UIC/RCC warning |
133 | 0 | bool const mocDisabled = (moc && !mocAvailable); |
134 | 0 | bool const uicDisabled = (uic && !uicAvailable); |
135 | 0 | bool const rccDisabled = (rcc && !rccAvailable); |
136 | 0 | if (mocDisabled || uicDisabled || rccDisabled) { |
137 | 0 | cmAlphaNum version = (qtVersion.second == 0) |
138 | 0 | ? cmAlphaNum("<QTVERSION>") |
139 | 0 | : cmAlphaNum(qtVersion.second); |
140 | 0 | cmAlphaNum component = uicDisabled ? "Widgets" : "Core"; |
141 | |
|
142 | 0 | std::string const msg = cmStrCat( |
143 | 0 | "AUTOGEN: No valid Qt version found for target ", |
144 | 0 | target->GetName(), ". ", |
145 | 0 | cmQtAutoGen::Tools(mocDisabled, uicDisabled, rccDisabled), |
146 | 0 | " disabled. Consider adding:\n find_package(Qt", version, |
147 | 0 | " COMPONENTS ", component, ")\nto your CMakeLists.txt file."); |
148 | 0 | target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg); |
149 | 0 | } |
150 | 0 | if (mocIsValid || uicIsValid || rccIsValid) { |
151 | | // Create autogen target initializer |
152 | 0 | this->Initializers_.emplace_back( |
153 | 0 | cm::make_unique<cmQtAutoGenInitializer>( |
154 | 0 | this, target.get(), qtVersion.first, mocIsValid, uicIsValid, |
155 | 0 | rccIsValid, globalAutoGenTarget, globalAutoRccTarget)); |
156 | 0 | } |
157 | 0 | } |
158 | 0 | } |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | 0 | cmQtAutoGenGlobalInitializer::~cmQtAutoGenGlobalInitializer() = default; |
163 | | |
164 | | void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget( |
165 | | cmLocalGenerator* localGen, std::string const& name, |
166 | | std::string const& comment) |
167 | 0 | { |
168 | | // Test if the target already exists |
169 | 0 | if (!localGen->FindGeneratorTargetToUse(name)) { |
170 | 0 | cmMakefile const* makefile = localGen->GetMakefile(); |
171 | | |
172 | | // Create utility target |
173 | 0 | auto cc = cm::make_unique<cmCustomCommand>(); |
174 | 0 | cc->SetWorkingDirectory(makefile->GetHomeOutputDirectory().c_str()); |
175 | 0 | cc->SetEscapeOldStyle(false); |
176 | 0 | cc->SetComment(comment.c_str()); |
177 | 0 | cmTarget* target = localGen->AddUtilityCommand(name, true, std::move(cc)); |
178 | 0 | localGen->AddGeneratorTarget( |
179 | 0 | cm::make_unique<cmGeneratorTarget>(target, localGen)); |
180 | | |
181 | | // Set FOLDER property in the target |
182 | 0 | { |
183 | 0 | cmValue folder = |
184 | 0 | makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); |
185 | 0 | if (folder) { |
186 | 0 | target->SetProperty("FOLDER", folder); |
187 | 0 | } |
188 | 0 | } |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | | void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen( |
193 | | cmLocalGenerator* localGen, std::string const& targetName) |
194 | 0 | { |
195 | 0 | auto const it = this->GlobalAutoGenTargets_.find(localGen); |
196 | 0 | if (it != this->GlobalAutoGenTargets_.end()) { |
197 | 0 | cmGeneratorTarget const* target = |
198 | 0 | localGen->FindGeneratorTargetToUse(it->second); |
199 | 0 | if (target) { |
200 | 0 | target->Target->AddUtility(targetName, false, localGen->GetMakefile()); |
201 | 0 | } |
202 | 0 | } |
203 | 0 | } |
204 | | |
205 | | void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc( |
206 | | cmLocalGenerator* localGen, std::string const& targetName) |
207 | 0 | { |
208 | 0 | auto const it = this->GlobalAutoRccTargets_.find(localGen); |
209 | 0 | if (it != this->GlobalAutoRccTargets_.end()) { |
210 | 0 | cmGeneratorTarget const* target = |
211 | 0 | localGen->FindGeneratorTargetToUse(it->second); |
212 | 0 | if (target) { |
213 | 0 | target->Target->AddUtility(targetName, false, localGen->GetMakefile()); |
214 | 0 | } |
215 | 0 | } |
216 | 0 | } |
217 | | |
218 | | cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> |
219 | | cmQtAutoGenGlobalInitializer::GetCompilerFeatures( |
220 | | std::string const& generator, cmQtAutoGen::ConfigString const& executable, |
221 | | std::string& error, bool const isMultiConfig, bool const UseBetterGraph) |
222 | 0 | { |
223 | 0 | cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> res; |
224 | 0 | if (isMultiConfig && UseBetterGraph) { |
225 | 0 | for (auto const& config : executable.Config) { |
226 | 0 | auto const exe = config.second; |
227 | | // Check if we have cached features |
228 | 0 | { |
229 | 0 | auto it = this->CompilerFeatures_.Config[config.first].find(exe); |
230 | 0 | if (it != this->CompilerFeatures_.Config[config.first].end()) { |
231 | 0 | res.Config[config.first] = it->second; |
232 | 0 | continue; |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | // Check if the executable exists |
237 | 0 | if (!cmSystemTools::FileExists(exe, true)) { |
238 | 0 | error = cmStrCat("The \"", generator, "\" executable ", |
239 | 0 | cmQtAutoGen::Quoted(exe), " does not exist."); |
240 | 0 | res.Config[config.first] = {}; |
241 | 0 | continue; |
242 | 0 | } |
243 | | |
244 | | // Test the executable |
245 | 0 | std::string stdOut; |
246 | 0 | { |
247 | 0 | std::string stdErr; |
248 | 0 | std::vector<std::string> command; |
249 | 0 | command.emplace_back(exe); |
250 | 0 | command.emplace_back("-h"); |
251 | 0 | int retVal = 0; |
252 | 0 | bool const runResult = cmSystemTools::RunSingleCommand( |
253 | 0 | command, &stdOut, &stdErr, &retVal, nullptr, |
254 | 0 | cmSystemTools::OUTPUT_NONE, cmDuration::zero(), |
255 | 0 | cmProcessOutput::Auto); |
256 | 0 | if (!runResult) { |
257 | 0 | error = cmStrCat("Test run of \"", generator, "\" executable ", |
258 | 0 | cmQtAutoGen::Quoted(exe), " failed.\n", |
259 | 0 | cmQtAutoGen::QuotedCommand(command), '\n', stdOut, |
260 | 0 | '\n', stdErr); |
261 | 0 | res.Config[config.first] = {}; |
262 | 0 | continue; |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | | // Create valid handle |
267 | 0 | res.Config[config.first] = |
268 | 0 | std::make_shared<cmQtAutoGen::CompilerFeatures>(); |
269 | 0 | res.Config[config.first]->HelpOutput = std::move(stdOut); |
270 | | |
271 | | // Register compiler features |
272 | 0 | this->CompilerFeatures_.Config[config.first].emplace( |
273 | 0 | exe, res.Config[config.first]); |
274 | 0 | } |
275 | 0 | return res; |
276 | 0 | } |
277 | | |
278 | | // Check if we have cached features |
279 | 0 | { |
280 | 0 | auto const it = this->CompilerFeatures_.Default.find(executable.Default); |
281 | 0 | if (it != this->CompilerFeatures_.Default.end()) { |
282 | 0 | res.Default = it->second; |
283 | 0 | return res; |
284 | 0 | } |
285 | 0 | } |
286 | | |
287 | | // Check if the executable exists |
288 | 0 | if (!cmSystemTools::FileExists(executable.Default, true)) { |
289 | 0 | error = |
290 | 0 | cmStrCat("The \"", generator, "\" executable ", |
291 | 0 | cmQtAutoGen::Quoted(executable.Default), " does not exist."); |
292 | 0 | return cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>(); |
293 | 0 | } |
294 | | |
295 | | // Test the executable |
296 | 0 | std::string stdOut; |
297 | 0 | { |
298 | 0 | std::string stdErr; |
299 | 0 | std::vector<std::string> command; |
300 | 0 | command.emplace_back(executable.Default); |
301 | 0 | command.emplace_back("-h"); |
302 | 0 | int retVal = 0; |
303 | 0 | bool const runResult = cmSystemTools::RunSingleCommand( |
304 | 0 | command, &stdOut, &stdErr, &retVal, nullptr, cmSystemTools::OUTPUT_NONE, |
305 | 0 | cmDuration::zero(), cmProcessOutput::Auto); |
306 | 0 | if (!runResult) { |
307 | 0 | error = cmStrCat("Test run of \"", generator, "\" executable ", |
308 | 0 | cmQtAutoGen::Quoted(executable.Default), " failed.\n", |
309 | 0 | cmQtAutoGen::QuotedCommand(command), '\n', stdOut, '\n', |
310 | 0 | stdErr); |
311 | 0 | return cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>(); |
312 | 0 | } |
313 | 0 | } |
314 | | |
315 | 0 | res.Default = std::make_shared<cmQtAutoGen::CompilerFeatures>(); |
316 | 0 | res.Default->HelpOutput = std::move(stdOut); |
317 | | |
318 | | // Register compiler features |
319 | 0 | this->CompilerFeatures_.Default.emplace(executable.Default, res.Default); |
320 | |
|
321 | 0 | return res; |
322 | 0 | } |
323 | | |
324 | | bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets() |
325 | 0 | { |
326 | | // Initialize global autogen targets |
327 | 0 | { |
328 | 0 | std::string const comment = "Global AUTOGEN target"; |
329 | 0 | for (auto const& pair : this->GlobalAutoGenTargets_) { |
330 | 0 | this->GetOrCreateGlobalTarget(pair.first, pair.second, comment); |
331 | 0 | } |
332 | 0 | } |
333 | | // Initialize global autorcc targets |
334 | 0 | { |
335 | 0 | std::string const comment = "Global AUTORCC target"; |
336 | 0 | for (auto const& pair : this->GlobalAutoRccTargets_) { |
337 | 0 | this->GetOrCreateGlobalTarget(pair.first, pair.second, comment); |
338 | 0 | } |
339 | 0 | } |
340 | | // Initialize per target autogen targets |
341 | 0 | for (auto& initializer : this->Initializers_) { |
342 | 0 | if (!initializer->InitCustomTargets()) { |
343 | 0 | return false; |
344 | 0 | } |
345 | 0 | } |
346 | 0 | return true; |
347 | 0 | } |
348 | | |
349 | | bool cmQtAutoGenGlobalInitializer::SetupCustomTargets() |
350 | 0 | { |
351 | 0 | for (auto& initializer : this->Initializers_) { |
352 | 0 | if (!initializer->SetupCustomTargets()) { |
353 | 0 | return false; |
354 | 0 | } |
355 | 0 | } |
356 | 0 | return true; |
357 | 0 | } |