/src/CMake/Source/cmLocalGenerator.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 "cmLocalGenerator.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <array> |
7 | | #include <cassert> |
8 | | #include <cstdio> |
9 | | #include <cstdlib> |
10 | | #include <initializer_list> |
11 | | #include <iterator> |
12 | | #include <queue> |
13 | | #include <sstream> |
14 | | #include <unordered_set> |
15 | | #include <utility> |
16 | | #include <vector> |
17 | | |
18 | | #include <cm/memory> |
19 | | #include <cm/optional> |
20 | | #include <cm/string_view> |
21 | | #include <cmext/algorithm> |
22 | | #include <cmext/string_view> |
23 | | |
24 | | #include "cmsys/RegularExpression.hxx" |
25 | | #include "cmsys/String.h" |
26 | | |
27 | | #include "cmAlgorithms.h" |
28 | | #include "cmCMakePath.h" |
29 | | #include "cmComputeLinkInformation.h" |
30 | | #include "cmCryptoHash.h" |
31 | | #include "cmCustomCommand.h" |
32 | | #include "cmCustomCommandGenerator.h" |
33 | | #include "cmCustomCommandLines.h" |
34 | | #include "cmCustomCommandTypes.h" |
35 | | #include "cmGeneratedFileStream.h" |
36 | | #include "cmGeneratorExpression.h" |
37 | | #include "cmGeneratorExpressionEvaluationFile.h" |
38 | | #include "cmGeneratorTarget.h" |
39 | | #include "cmGlobalGenerator.h" |
40 | | #include "cmInstallGenerator.h" |
41 | | #include "cmInstallScriptGenerator.h" |
42 | | #include "cmInstallTargetGenerator.h" |
43 | | #include "cmLinkLineComputer.h" |
44 | | #include "cmLinkLineDeviceComputer.h" |
45 | | #include "cmList.h" |
46 | | #include "cmMakefile.h" |
47 | | #include "cmMessageType.h" |
48 | | #include "cmObjectLocation.h" |
49 | | #include "cmRange.h" |
50 | | #include "cmRulePlaceholderExpander.h" |
51 | | #include "cmScriptGenerator.h" |
52 | | #include "cmSourceFile.h" |
53 | | #include "cmSourceFileLocation.h" |
54 | | #include "cmSourceFileLocationKind.h" |
55 | | #include "cmSourceGroup.h" |
56 | | #include "cmStandardLevelResolver.h" |
57 | | #include "cmState.h" |
58 | | #include "cmStateDirectory.h" |
59 | | #include "cmStateTypes.h" |
60 | | #include "cmStringAlgorithms.h" |
61 | | #include "cmSystemTools.h" |
62 | | #include "cmTarget.h" |
63 | | #include "cmTestGenerator.h" |
64 | | #include "cmValue.h" |
65 | | #include "cmake.h" |
66 | | |
67 | | #if defined(__HAIKU__) |
68 | | # include <FindDirectory.h> |
69 | | # include <StorageDefs.h> |
70 | | #endif |
71 | | |
72 | | namespace { |
73 | | // List of variables that are replaced when |
74 | | // rules are expanded. These variables are |
75 | | // replaced in the form <var> with GetSafeDefinition(var). |
76 | | // ${LANG} is replaced in the variable first with all enabled |
77 | | // languages. |
78 | | auto ruleReplaceVars = { |
79 | | "CMAKE_${LANG}_COMPILER", |
80 | | "CMAKE_SHARED_MODULE_${LANG}_FLAGS", |
81 | | "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS", |
82 | | "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG", |
83 | | "CMAKE_${LANG}_ARCHIVE", |
84 | | "CMAKE_AR", |
85 | | "CMAKE_SOURCE_DIR", |
86 | | "CMAKE_BINARY_DIR", |
87 | | "CMAKE_CURRENT_SOURCE_DIR", |
88 | | "CMAKE_CURRENT_BINARY_DIR", |
89 | | "CMAKE_RANLIB", |
90 | | "CMAKE_MT", |
91 | | "CMAKE_TAPI", |
92 | | "CMAKE_CUDA_HOST_COMPILER", |
93 | | "CMAKE_CUDA_HOST_LINK_LAUNCHER", |
94 | | "CMAKE_HIP_HOST_COMPILER", |
95 | | "CMAKE_HIP_HOST_LINK_LAUNCHER", |
96 | | "CMAKE_CL_SHOWINCLUDES_PREFIX", |
97 | | }; |
98 | | |
99 | | // Variables whose placeholders now map to an empty string. |
100 | | // Our platform modules no longer use these, but third-party code might. |
101 | | auto ruleReplaceEmptyVars = { |
102 | | "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS", |
103 | | "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS", |
104 | | "CMAKE_${LANG}_LINK_FLAGS", |
105 | | }; |
106 | | } |
107 | | |
108 | | cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile) |
109 | 0 | : cmOutputConverter(makefile->GetStateSnapshot()) |
110 | 0 | , DirectoryBacktrace(makefile->GetBacktrace()) |
111 | 0 | { |
112 | 0 | this->GlobalGenerator = gg; |
113 | |
|
114 | 0 | this->Makefile = makefile; |
115 | |
|
116 | 0 | this->AliasTargets = makefile->GetAliasTargets(); |
117 | |
|
118 | 0 | this->EmitUniversalBinaryFlags = true; |
119 | |
|
120 | 0 | this->ComputeObjectMaxPath(); |
121 | | |
122 | | // Canonicalize entries of the CPATH environment variable the same |
123 | | // way detection of CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES does. |
124 | 0 | { |
125 | 0 | std::vector<std::string> cpath; |
126 | 0 | cmSystemTools::GetPath(cpath, "CPATH"); |
127 | 0 | for (std::string const& cp : cpath) { |
128 | 0 | if (cmSystemTools::FileIsFullPath(cp)) { |
129 | 0 | this->EnvCPATH.emplace_back(cmSystemTools::CollapseFullPath(cp)); |
130 | 0 | } |
131 | 0 | } |
132 | 0 | } |
133 | |
|
134 | 0 | std::vector<std::string> enabledLanguages = |
135 | 0 | this->GetState()->GetEnabledLanguages(); |
136 | |
|
137 | 0 | if (cmValue sysrootCompile = |
138 | 0 | this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) { |
139 | 0 | this->CompilerSysroot = *sysrootCompile; |
140 | 0 | } else { |
141 | 0 | this->CompilerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT"); |
142 | 0 | } |
143 | |
|
144 | 0 | if (cmValue sysrootLink = |
145 | 0 | this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) { |
146 | 0 | this->LinkerSysroot = *sysrootLink; |
147 | 0 | } else { |
148 | 0 | this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT"); |
149 | 0 | } |
150 | | |
151 | | // OSX SYSROOT can be required by some tools, like tapi |
152 | 0 | { |
153 | 0 | cmValue osxSysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT"); |
154 | 0 | this->VariableMappings["CMAKE_OSX_SYSROOT"] = |
155 | 0 | osxSysroot.IsEmpty() ? "/" : this->EscapeForShell(*osxSysroot, true); |
156 | 0 | } |
157 | |
|
158 | 0 | if (cmValue appleArchSysroots = |
159 | 0 | this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) { |
160 | 0 | std::string const& appleArchs = |
161 | 0 | this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES"); |
162 | 0 | cmList archs(appleArchs); |
163 | 0 | cmList sysroots{ appleArchSysroots, cmList::EmptyElements::Yes }; |
164 | 0 | if (archs.size() == sysroots.size()) { |
165 | 0 | for (cmList::size_type i = 0; i < archs.size(); ++i) { |
166 | 0 | this->AppleArchSysroots[archs[i]] = sysroots[i]; |
167 | 0 | } |
168 | 0 | } else { |
169 | 0 | std::string const e = |
170 | 0 | cmStrCat("CMAKE_APPLE_ARCH_SYSROOTS:\n ", *appleArchSysroots, |
171 | 0 | "\n" |
172 | 0 | "is not the same length as CMAKE_OSX_ARCHITECTURES:\n ", |
173 | 0 | appleArchs); |
174 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, e); |
175 | 0 | } |
176 | 0 | } |
177 | |
|
178 | 0 | for (std::string const& lang : enabledLanguages) { |
179 | 0 | if (lang == "NONE") { |
180 | 0 | continue; |
181 | 0 | } |
182 | 0 | this->Compilers["CMAKE_" + lang + "_COMPILER"] = lang; |
183 | |
|
184 | 0 | this->VariableMappings["CMAKE_" + lang + "_COMPILER"] = |
185 | 0 | this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER"); |
186 | |
|
187 | 0 | std::string const& compilerArg1 = "CMAKE_" + lang + "_COMPILER_ARG1"; |
188 | 0 | std::string const& compilerTarget = "CMAKE_" + lang + "_COMPILER_TARGET"; |
189 | 0 | std::string const& compilerOptionTarget = |
190 | 0 | "CMAKE_" + lang + "_COMPILE_OPTIONS_TARGET"; |
191 | 0 | std::string const& compilerExternalToolchain = |
192 | 0 | "CMAKE_" + lang + "_COMPILER_EXTERNAL_TOOLCHAIN"; |
193 | 0 | std::string const& compilerOptionExternalToolchain = |
194 | 0 | "CMAKE_" + lang + "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN"; |
195 | 0 | std::string const& compilerOptionSysroot = |
196 | 0 | "CMAKE_" + lang + "_COMPILE_OPTIONS_SYSROOT"; |
197 | |
|
198 | 0 | this->VariableMappings[compilerArg1] = |
199 | 0 | this->Makefile->GetSafeDefinition(compilerArg1); |
200 | 0 | this->VariableMappings[compilerTarget] = |
201 | 0 | this->Makefile->GetSafeDefinition(compilerTarget); |
202 | 0 | this->VariableMappings[compilerOptionTarget] = |
203 | 0 | this->Makefile->GetSafeDefinition(compilerOptionTarget); |
204 | 0 | this->VariableMappings[compilerExternalToolchain] = |
205 | 0 | this->Makefile->GetSafeDefinition(compilerExternalToolchain); |
206 | 0 | this->VariableMappings[compilerOptionExternalToolchain] = |
207 | 0 | this->Makefile->GetSafeDefinition(compilerOptionExternalToolchain); |
208 | 0 | this->VariableMappings[compilerOptionSysroot] = |
209 | 0 | this->Makefile->GetSafeDefinition(compilerOptionSysroot); |
210 | |
|
211 | 0 | for (std::string replaceVar : ruleReplaceVars) { |
212 | 0 | if (replaceVar.find("${LANG}") != std::string::npos) { |
213 | 0 | cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang); |
214 | 0 | } |
215 | |
|
216 | 0 | this->VariableMappings[replaceVar] = |
217 | 0 | this->Makefile->GetSafeDefinition(replaceVar); |
218 | 0 | } |
219 | |
|
220 | 0 | for (std::string replaceVar : ruleReplaceEmptyVars) { |
221 | 0 | if (replaceVar.find("${LANG}") != std::string::npos) { |
222 | 0 | cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang); |
223 | 0 | } |
224 | |
|
225 | 0 | this->VariableMappings[replaceVar] = std::string(); |
226 | 0 | } |
227 | 0 | } |
228 | 0 | } |
229 | | |
230 | | std::unique_ptr<cmRulePlaceholderExpander> |
231 | | cmLocalGenerator::CreateRulePlaceholderExpander(cmBuildStep buildStep) const |
232 | 0 | { |
233 | 0 | return cm::make_unique<cmRulePlaceholderExpander>( |
234 | 0 | buildStep, this->Compilers, this->VariableMappings, this->CompilerSysroot, |
235 | 0 | this->LinkerSysroot, |
236 | 0 | this->GetState()->UseWatcomWMake() || this->GetState()->UseBorlandMake() |
237 | 0 | ? cmRulePlaceholderExpander::UseShortPaths::Yes |
238 | 0 | : cmRulePlaceholderExpander::UseShortPaths::No); |
239 | 0 | } |
240 | | |
241 | 0 | cmLocalGenerator::~cmLocalGenerator() = default; |
242 | | |
243 | | void cmLocalGenerator::IssueMessage(MessageType type, std::string const& text, |
244 | | cmListFileBacktrace const& bt) const |
245 | 0 | { |
246 | 0 | this->GetMakefile()->IssueMessage(type, text, bt); |
247 | 0 | } |
248 | | |
249 | | void cmLocalGenerator::IssueDiagnostic(cmDiagnosticCategory category, |
250 | | std::string const& text, |
251 | | cmListFileBacktrace const& bt) const |
252 | 0 | { |
253 | 0 | this->GetMakefile()->IssueDiagnostic(category, text, bt); |
254 | 0 | } |
255 | | |
256 | | void cmLocalGenerator::ComputeObjectMaxPath() |
257 | 0 | { |
258 | | // Choose a maximum object file name length. |
259 | | #if defined(_WIN32) || defined(__CYGWIN__) |
260 | | this->ObjectPathMax = 250; |
261 | | #else |
262 | 0 | this->ObjectPathMax = 1000; |
263 | 0 | #endif |
264 | 0 | cmValue plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX"); |
265 | 0 | if (cmNonempty(plen)) { |
266 | 0 | unsigned int pmax; |
267 | 0 | if (sscanf(plen->c_str(), "%u", &pmax) == 1) { |
268 | 0 | if (pmax >= 128) { |
269 | 0 | this->ObjectPathMax = pmax; |
270 | 0 | } else { |
271 | 0 | std::ostringstream w; |
272 | 0 | w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax |
273 | 0 | << ", which is less than the minimum of 128. " |
274 | 0 | "The value will be ignored."; |
275 | 0 | this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str()); |
276 | 0 | } |
277 | 0 | } else { |
278 | 0 | std::ostringstream w; |
279 | 0 | w << "CMAKE_OBJECT_PATH_MAX is set to \"" << *plen |
280 | 0 | << "\", which fails to parse as a positive integer. " |
281 | 0 | "The value will be ignored."; |
282 | 0 | this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str()); |
283 | 0 | } |
284 | 0 | } |
285 | 0 | this->ObjectMaxPathViolations.clear(); |
286 | 0 | } |
287 | | |
288 | | static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs, |
289 | | std::string const& config, |
290 | | std::string const& lang, |
291 | | cmGeneratorTarget const* target) |
292 | 0 | { |
293 | 0 | if (!target) { |
294 | 0 | return; |
295 | 0 | } |
296 | | |
297 | 0 | std::stable_sort( |
298 | 0 | includeDirs.begin(), includeDirs.end(), |
299 | 0 | [&target, &config, &lang](std::string const& a, std::string const& b) { |
300 | 0 | return !target->IsSystemIncludeDirectory(a, config, lang) && |
301 | 0 | target->IsSystemIncludeDirectory(b, config, lang); |
302 | 0 | }); |
303 | 0 | } |
304 | | |
305 | | static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs, |
306 | | std::string const& config, |
307 | | std::string const& lang, |
308 | | cmGeneratorTarget const* target) |
309 | 0 | { |
310 | 0 | if (!target) { |
311 | 0 | return; |
312 | 0 | } |
313 | | |
314 | 0 | std::stable_sort(includeDirs.begin(), includeDirs.end(), |
315 | 0 | [target, &config, &lang](BT<std::string> const& a, |
316 | 0 | BT<std::string> const& b) { |
317 | 0 | return !target->IsSystemIncludeDirectory(a.Value, config, |
318 | 0 | lang) && |
319 | 0 | target->IsSystemIncludeDirectory(b.Value, config, lang); |
320 | 0 | }); |
321 | 0 | } |
322 | | |
323 | | void cmLocalGenerator::TraceDependencies() const |
324 | 0 | { |
325 | | // Generate the rule files for each target. |
326 | 0 | auto const& targets = this->GetGeneratorTargets(); |
327 | 0 | for (auto const& target : targets) { |
328 | 0 | if (!target->IsInBuildSystem()) { |
329 | 0 | continue; |
330 | 0 | } |
331 | 0 | target->TraceDependencies(); |
332 | 0 | } |
333 | 0 | } |
334 | | |
335 | | #ifndef CMAKE_BOOTSTRAP |
336 | | void cmLocalGenerator::ResolveSourceGroupGenex() |
337 | 0 | { |
338 | 0 | this->Makefile->ResolveSourceGroupGenex(this); |
339 | 0 | } |
340 | | #endif |
341 | | |
342 | | void cmLocalGenerator::GenerateTestFiles() |
343 | 0 | { |
344 | 0 | if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) { |
345 | 0 | return; |
346 | 0 | } |
347 | | |
348 | | // Compute the set of configurations. |
349 | 0 | std::vector<std::string> configurationTypes = |
350 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig); |
351 | 0 | std::string config = this->Makefile->GetDefaultConfiguration(); |
352 | |
|
353 | 0 | std::string file = |
354 | 0 | cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentBinary(), |
355 | 0 | "/CTestTestfile.cmake"); |
356 | 0 | this->GlobalGenerator->AddTestFile(file); |
357 | |
|
358 | 0 | cmGeneratedFileStream fout(file); |
359 | |
|
360 | 0 | fout << "# CMake generated Testfile for \n" |
361 | 0 | "# Source directory: " |
362 | 0 | << this->StateSnapshot.GetDirectory().GetCurrentSource() |
363 | 0 | << "\n" |
364 | 0 | "# Build directory: " |
365 | 0 | << this->StateSnapshot.GetDirectory().GetCurrentBinary() |
366 | 0 | << "\n" |
367 | 0 | "# \n" |
368 | 0 | "# This file includes the relevant testing commands " |
369 | 0 | "required for \n" |
370 | 0 | "# testing this directory and lists subdirectories to " |
371 | 0 | "be tested as well.\n"; |
372 | |
|
373 | 0 | std::string resourceSpecFile = |
374 | 0 | this->Makefile->GetSafeDefinition("CTEST_RESOURCE_SPEC_FILE"); |
375 | 0 | if (!resourceSpecFile.empty()) { |
376 | 0 | fout << "set(CTEST_RESOURCE_SPEC_FILE \"" << resourceSpecFile << "\")\n"; |
377 | 0 | } |
378 | |
|
379 | 0 | cmValue testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE"); |
380 | 0 | if (testIncludeFile) { |
381 | 0 | fout << "include(\"" << *testIncludeFile << "\")\n"; |
382 | 0 | } |
383 | |
|
384 | 0 | cmValue testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES"); |
385 | 0 | if (testIncludeFiles) { |
386 | 0 | cmList includesList{ *testIncludeFiles }; |
387 | 0 | for (std::string const& i : includesList) { |
388 | 0 | fout << "include(\"" << i << "\")\n"; |
389 | 0 | } |
390 | 0 | } |
391 | | |
392 | | // Ask each test generator to write its code. |
393 | 0 | for (auto const& tester : this->Makefile->GetTestGenerators()) { |
394 | 0 | tester->Compute(this); |
395 | 0 | tester->Generate(fout, config, configurationTypes); |
396 | 0 | } |
397 | 0 | using vec_t = std::vector<cmStateSnapshot>; |
398 | 0 | vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren(); |
399 | 0 | for (cmStateSnapshot const& i : children) { |
400 | | // TODO: Use add_subdirectory instead? |
401 | 0 | std::string outP = i.GetDirectory().GetCurrentBinary(); |
402 | 0 | outP = this->MaybeRelativeToCurBinDir(outP); |
403 | 0 | fout << "subdirs(" << cmScriptGenerator::Quote(outP) << ")\n"; |
404 | 0 | } |
405 | | |
406 | | // Add directory labels property |
407 | 0 | cmValue directoryLabels = |
408 | 0 | this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS"); |
409 | 0 | cmValue labels = this->Makefile->GetProperty("LABELS"); |
410 | |
|
411 | 0 | if (labels || directoryLabels) { |
412 | 0 | fout << "set_directory_properties(PROPERTIES LABELS "; |
413 | 0 | if (labels) { |
414 | 0 | fout << cmScriptGenerator::Quote(*labels); |
415 | 0 | } |
416 | 0 | if (labels && directoryLabels) { |
417 | 0 | fout << ";"; |
418 | 0 | } |
419 | 0 | if (directoryLabels) { |
420 | 0 | fout << cmScriptGenerator::Quote(*directoryLabels); |
421 | 0 | } |
422 | 0 | fout << ")\n"; |
423 | 0 | } |
424 | 0 | } |
425 | | |
426 | | void cmLocalGenerator::CreateEvaluationFileOutputs() |
427 | 0 | { |
428 | 0 | std::vector<std::string> const& configs = |
429 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
430 | 0 | for (std::string const& c : configs) { |
431 | 0 | this->CreateEvaluationFileOutputs(c); |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | | void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config) |
436 | 0 | { |
437 | 0 | for (auto const& geef : this->Makefile->GetEvaluationFiles()) { |
438 | 0 | geef->CreateOutputFile(this, config); |
439 | 0 | } |
440 | 0 | } |
441 | | |
442 | | void cmLocalGenerator::ProcessEvaluationFiles( |
443 | | std::vector<std::string>& generatedFiles) |
444 | 0 | { |
445 | 0 | for (auto const& geef : this->Makefile->GetEvaluationFiles()) { |
446 | 0 | geef->Generate(this); |
447 | 0 | if (cmSystemTools::GetFatalErrorOccurred()) { |
448 | 0 | return; |
449 | 0 | } |
450 | 0 | std::vector<std::string> files = geef->GetFiles(); |
451 | 0 | std::sort(files.begin(), files.end()); |
452 | |
|
453 | 0 | std::vector<std::string> intersection; |
454 | 0 | std::set_intersection(files.begin(), files.end(), generatedFiles.begin(), |
455 | 0 | generatedFiles.end(), |
456 | 0 | std::back_inserter(intersection)); |
457 | 0 | if (!intersection.empty()) { |
458 | 0 | cmSystemTools::Error("Files to be generated by multiple different " |
459 | 0 | "commands: " + |
460 | 0 | cmWrap('"', intersection, '"', " ")); |
461 | 0 | return; |
462 | 0 | } |
463 | | |
464 | 0 | cm::append(generatedFiles, files); |
465 | 0 | std::inplace_merge(generatedFiles.begin(), |
466 | 0 | generatedFiles.end() - files.size(), |
467 | 0 | generatedFiles.end()); |
468 | 0 | } |
469 | 0 | } |
470 | | |
471 | | void cmLocalGenerator::GenerateInstallRules() |
472 | 0 | { |
473 | | // Compute the install prefix. |
474 | 0 | cmValue installPrefix = |
475 | 0 | this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX"); |
476 | 0 | std::string prefix = *installPrefix; |
477 | |
|
478 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
479 | | if (!installPrefix) { |
480 | | if (!cmSystemTools::GetEnv("SystemDrive", prefix)) { |
481 | | prefix = "C:"; |
482 | | } |
483 | | cmValue project_name = this->Makefile->GetDefinition("PROJECT_NAME"); |
484 | | if (cmNonempty(project_name)) { |
485 | | prefix += "/Program Files/"; |
486 | | prefix += *project_name; |
487 | | } else { |
488 | | prefix += "/InstalledCMakeProject"; |
489 | | } |
490 | | } |
491 | | #elif defined(__HAIKU__) |
492 | | char dir[B_PATH_NAME_LENGTH]; |
493 | | if (!installPrefix) { |
494 | | if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) == |
495 | | B_OK) { |
496 | | prefix = dir; |
497 | | } else { |
498 | | prefix = "/boot/system"; |
499 | | } |
500 | | } |
501 | | #else |
502 | 0 | if (!installPrefix) { |
503 | 0 | prefix = "/usr/local"; |
504 | 0 | } |
505 | 0 | #endif |
506 | 0 | if (cmValue stagingPrefix = |
507 | 0 | this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) { |
508 | 0 | prefix = *stagingPrefix; |
509 | 0 | } |
510 | | |
511 | | // Compute the set of configurations. |
512 | 0 | std::vector<std::string> configurationTypes = |
513 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig); |
514 | 0 | std::string config = this->Makefile->GetDefaultConfiguration(); |
515 | | |
516 | | // Choose a default install configuration. |
517 | 0 | std::string default_config = config; |
518 | 0 | char const* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO", |
519 | 0 | "DEBUG", nullptr }; |
520 | 0 | for (char const** c = default_order; *c && default_config.empty(); ++c) { |
521 | 0 | for (std::string const& configurationType : configurationTypes) { |
522 | 0 | if (cmSystemTools::UpperCase(configurationType) == *c) { |
523 | 0 | default_config = configurationType; |
524 | 0 | } |
525 | 0 | } |
526 | 0 | } |
527 | 0 | if (default_config.empty() && !configurationTypes.empty()) { |
528 | 0 | default_config = configurationTypes[0]; |
529 | 0 | } |
530 | | |
531 | | // Create the install script file. |
532 | 0 | std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary(); |
533 | 0 | std::string homedir = this->GetState()->GetBinaryDirectory(); |
534 | 0 | int toplevel_install = 0; |
535 | 0 | if (file == homedir) { |
536 | 0 | toplevel_install = 1; |
537 | 0 | } |
538 | 0 | file += "/cmake_install.cmake"; |
539 | 0 | this->GetGlobalGenerator()->AddInstallScript(file); |
540 | 0 | cmGeneratedFileStream fout(file); |
541 | | |
542 | | // Write the header. |
543 | | /* clang-format off */ |
544 | 0 | fout << "# Install script for directory: " |
545 | 0 | << this->StateSnapshot.GetDirectory().GetCurrentSource() |
546 | 0 | << "\n\n" |
547 | 0 | "# Set the install prefix\n" |
548 | 0 | "if(NOT DEFINED CMAKE_INSTALL_PREFIX)\n" |
549 | 0 | " set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")\n" |
550 | 0 | "endif()\n" |
551 | 0 | << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )" |
552 | 0 | << "\"${CMAKE_INSTALL_PREFIX}\")\n\n"; |
553 | | /* clang-format on */ |
554 | | |
555 | | // Write support code for generating per-configuration install rules. |
556 | | /* clang-format off */ |
557 | 0 | fout << |
558 | 0 | "# Set the install configuration name.\n" |
559 | 0 | "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n" |
560 | 0 | " if(BUILD_TYPE)\n" |
561 | 0 | " string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n" |
562 | 0 | " CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n" |
563 | 0 | " else()\n" |
564 | 0 | " set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n" |
565 | 0 | " endif()\n" |
566 | 0 | " message(STATUS \"Install configuration: " |
567 | 0 | "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n" |
568 | 0 | "endif()\n" |
569 | 0 | "\n"; |
570 | | /* clang-format on */ |
571 | | |
572 | | // Write support code for dealing with component-specific installs. |
573 | | /* clang-format off */ |
574 | 0 | fout << |
575 | 0 | "# Set the component getting installed.\n" |
576 | 0 | "if(NOT CMAKE_INSTALL_COMPONENT)\n" |
577 | 0 | " if(COMPONENT)\n" |
578 | 0 | " message(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n" |
579 | 0 | " set(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n" |
580 | 0 | " else()\n" |
581 | 0 | " set(CMAKE_INSTALL_COMPONENT)\n" |
582 | 0 | " endif()\n" |
583 | 0 | "endif()\n" |
584 | 0 | "\n"; |
585 | | /* clang-format on */ |
586 | | |
587 | | // Copy user-specified install options to the install code. |
588 | 0 | if (cmValue so_no_exe = |
589 | 0 | this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) { |
590 | | /* clang-format off */ |
591 | 0 | fout << |
592 | 0 | "# Install shared libraries without execute permission?\n" |
593 | 0 | "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n" |
594 | 0 | " set(CMAKE_INSTALL_SO_NO_EXE \"" << *so_no_exe << "\")\n" |
595 | 0 | "endif()\n" |
596 | 0 | "\n"; |
597 | | /* clang-format on */ |
598 | 0 | } |
599 | | |
600 | | // Copy cmake cross compile state to install code. |
601 | 0 | if (cmValue crosscompiling = |
602 | 0 | this->Makefile->GetDefinition("CMAKE_CROSSCOMPILING")) { |
603 | | /* clang-format off */ |
604 | 0 | fout << |
605 | 0 | "# Is this installation the result of a crosscompile?\n" |
606 | 0 | "if(NOT DEFINED CMAKE_CROSSCOMPILING)\n" |
607 | 0 | " set(CMAKE_CROSSCOMPILING \"" << *crosscompiling << "\")\n" |
608 | 0 | "endif()\n" |
609 | 0 | "\n"; |
610 | | /* clang-format on */ |
611 | 0 | } |
612 | | |
613 | | // Write default directory permissions. |
614 | 0 | if (cmValue defaultDirPermissions = this->Makefile->GetDefinition( |
615 | 0 | "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS")) { |
616 | | /* clang-format off */ |
617 | 0 | fout << |
618 | 0 | "# Set default install directory permissions.\n" |
619 | 0 | "if(NOT DEFINED CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS)\n" |
620 | 0 | " set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS \"" |
621 | 0 | << *defaultDirPermissions << "\")\n" |
622 | 0 | "endif()\n" |
623 | 0 | "\n"; |
624 | | /* clang-format on */ |
625 | 0 | } |
626 | | |
627 | | // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM so that |
628 | | // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)` |
629 | | // has same platform variable as when running cmake |
630 | 0 | if (cmValue platform = this->Makefile->GetDefinition( |
631 | 0 | "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM")) { |
632 | | /* clang-format off */ |
633 | 0 | fout << |
634 | 0 | "# Set OS and executable format for runtime-dependencies.\n" |
635 | 0 | "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM)\n" |
636 | 0 | " set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM \"" |
637 | 0 | << *platform << "\")\n" |
638 | 0 | "endif()\n" |
639 | 0 | "\n"; |
640 | | /* clang-format on */ |
641 | 0 | } |
642 | | |
643 | | // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL so that |
644 | | // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)` |
645 | | // has same tool selected as when running cmake |
646 | 0 | if (cmValue command = |
647 | 0 | this->Makefile->GetDefinition("CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL")) { |
648 | | /* clang-format off */ |
649 | 0 | fout << |
650 | 0 | "# Set tool for dependency-resolution of runtime-dependencies.\n" |
651 | 0 | "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL)\n" |
652 | 0 | " set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL \"" |
653 | 0 | << *command << "\")\n" |
654 | 0 | "endif()\n" |
655 | 0 | "\n"; |
656 | | /* clang-format on */ |
657 | 0 | } |
658 | | |
659 | | // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND so that |
660 | | // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)` |
661 | | // has same path to the tool as when running cmake |
662 | 0 | if (cmValue command = this->Makefile->GetDefinition( |
663 | 0 | "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND")) { |
664 | | /* clang-format off */ |
665 | 0 | fout << |
666 | 0 | "# Set path to tool for dependency-resolution of runtime-dependencies.\n" |
667 | 0 | "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND)\n" |
668 | 0 | " set(CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND \"" |
669 | 0 | << *command << "\")\n" |
670 | 0 | "endif()\n" |
671 | 0 | "\n"; |
672 | | /* clang-format on */ |
673 | 0 | } |
674 | | |
675 | | // Write out CMAKE_OBJDUMP so that installed code that uses |
676 | | // `file(GET_RUNTIME_DEPENDENCIES)` and hasn't specified |
677 | | // CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND has consistent |
678 | | // logic to fallback to CMAKE_OBJDUMP when `objdump` is |
679 | | // not on the path |
680 | 0 | if (cmValue command = this->Makefile->GetDefinition("CMAKE_OBJDUMP")) { |
681 | | /* clang-format off */ |
682 | 0 | fout << |
683 | 0 | "# Set path to fallback-tool for dependency-resolution.\n" |
684 | 0 | "if(NOT DEFINED CMAKE_OBJDUMP)\n" |
685 | 0 | " set(CMAKE_OBJDUMP \"" |
686 | 0 | << *command << "\")\n" |
687 | 0 | "endif()\n" |
688 | 0 | "\n"; |
689 | | /* clang-format on */ |
690 | 0 | } |
691 | |
|
692 | 0 | this->AddGeneratorSpecificInstallSetup(fout); |
693 | | |
694 | | // Ask each install generator to write its code. |
695 | 0 | cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082); |
696 | 0 | auto const& installers = this->Makefile->GetInstallGenerators(); |
697 | 0 | bool haveSubdirectoryInstall = false; |
698 | 0 | bool haveInstallAfterSubdirectory = false; |
699 | 0 | if (status == cmPolicies::WARN) { |
700 | 0 | for (auto const& installer : installers) { |
701 | 0 | installer->CheckCMP0082(haveSubdirectoryInstall, |
702 | 0 | haveInstallAfterSubdirectory); |
703 | 0 | installer->Generate(fout, config, configurationTypes); |
704 | 0 | } |
705 | 0 | } else { |
706 | 0 | for (auto const& installer : installers) { |
707 | 0 | installer->Generate(fout, config, configurationTypes); |
708 | 0 | } |
709 | 0 | } |
710 | | |
711 | | // Write rules from old-style specification stored in targets. |
712 | 0 | this->GenerateTargetInstallRules(fout, config, configurationTypes); |
713 | | |
714 | | // Include install scripts from subdirectories. |
715 | 0 | switch (status) { |
716 | 0 | case cmPolicies::WARN: |
717 | 0 | if (haveInstallAfterSubdirectory && |
718 | 0 | this->Makefile->PolicyOptionalWarningEnabled( |
719 | 0 | "CMAKE_POLICY_WARNING_CMP0082")) { |
720 | 0 | std::ostringstream e; |
721 | 0 | e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0082) << "\n"; |
722 | 0 | this->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, e.str()); |
723 | 0 | } |
724 | 0 | CM_FALLTHROUGH; |
725 | 0 | case cmPolicies::OLD: { |
726 | 0 | std::vector<cmStateSnapshot> children = |
727 | 0 | this->Makefile->GetStateSnapshot().GetChildren(); |
728 | 0 | if (!children.empty()) { |
729 | 0 | fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n"; |
730 | 0 | fout << " # Include the install script for each subdirectory.\n"; |
731 | 0 | for (cmStateSnapshot const& c : children) { |
732 | 0 | if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) { |
733 | 0 | std::string odir = c.GetDirectory().GetCurrentBinary(); |
734 | 0 | cmSystemTools::ConvertToUnixSlashes(odir); |
735 | 0 | fout << " include(\"" << odir << "/cmake_install.cmake\")\n"; |
736 | 0 | } |
737 | 0 | } |
738 | 0 | fout << "\n"; |
739 | 0 | fout << "endif()\n\n"; |
740 | 0 | } |
741 | 0 | } break; |
742 | | |
743 | 0 | case cmPolicies::NEW: |
744 | | // NEW behavior is handled in |
745 | | // cmInstallSubdirectoryGenerator::GenerateScript() |
746 | 0 | break; |
747 | 0 | } |
748 | | |
749 | | /* clang-format off */ |
750 | | |
751 | 0 | fout << |
752 | 0 | "string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n" |
753 | 0 | " \"${CMAKE_INSTALL_MANIFEST_FILES}\")\n" |
754 | 0 | "if(CMAKE_INSTALL_LOCAL_ONLY)\n" |
755 | 0 | " file(WRITE \"" << |
756 | 0 | this->StateSnapshot.GetDirectory().GetCurrentBinary() << |
757 | 0 | "/install_local_manifest.txt\"\n" |
758 | 0 | " \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n" |
759 | 0 | "endif()\n"; |
760 | |
|
761 | 0 | if (toplevel_install) { |
762 | 0 | fout << |
763 | 0 | "if(CMAKE_INSTALL_COMPONENT)\n" |
764 | 0 | " if(CMAKE_INSTALL_COMPONENT MATCHES \"^[a-zA-Z0-9_.+-]+$\")\n" |
765 | 0 | " set(CMAKE_INSTALL_MANIFEST \"install_manifest_" |
766 | 0 | "${CMAKE_INSTALL_COMPONENT}.txt\")\n" |
767 | 0 | " else()\n" |
768 | 0 | " string(MD5 CMAKE_INST_COMP_HASH \"${CMAKE_INSTALL_COMPONENT}\")\n" |
769 | 0 | " set(CMAKE_INSTALL_MANIFEST \"install_manifest_" |
770 | 0 | "${CMAKE_INST_COMP_HASH}.txt\")\n" |
771 | 0 | " unset(CMAKE_INST_COMP_HASH)\n" |
772 | 0 | " endif()\n" |
773 | 0 | "else()\n" |
774 | 0 | " set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n" |
775 | 0 | "endif()\n" |
776 | 0 | "\n" |
777 | 0 | "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n" |
778 | 0 | " file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n" |
779 | 0 | " \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n" |
780 | 0 | "endif()\n"; |
781 | 0 | } |
782 | | /* clang-format on */ |
783 | 0 | } |
784 | | |
785 | | void cmLocalGenerator::AddGeneratorTarget( |
786 | | std::unique_ptr<cmGeneratorTarget> gt) |
787 | 0 | { |
788 | 0 | cmGeneratorTarget* gt_ptr = gt.get(); |
789 | |
|
790 | 0 | this->GeneratorTargets.push_back(std::move(gt)); |
791 | 0 | this->GeneratorTargetSearchIndex.emplace(gt_ptr->GetName(), gt_ptr); |
792 | 0 | this->GlobalGenerator->IndexGeneratorTarget(gt_ptr); |
793 | 0 | } |
794 | | |
795 | | void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt) |
796 | 0 | { |
797 | 0 | this->ImportedGeneratorTargets.emplace(gt->GetName(), gt); |
798 | 0 | this->GlobalGenerator->IndexGeneratorTarget(gt); |
799 | 0 | } |
800 | | |
801 | | void cmLocalGenerator::AddOwnedImportedGeneratorTarget( |
802 | | std::unique_ptr<cmGeneratorTarget> gt) |
803 | 0 | { |
804 | 0 | this->OwnedImportedGeneratorTargets.push_back(std::move(gt)); |
805 | 0 | } |
806 | | |
807 | | cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget( |
808 | | std::string const& name) const |
809 | 0 | { |
810 | 0 | auto ti = this->GeneratorTargetSearchIndex.find(name); |
811 | 0 | if (ti != this->GeneratorTargetSearchIndex.end()) { |
812 | 0 | return ti->second; |
813 | 0 | } |
814 | 0 | return nullptr; |
815 | 0 | } |
816 | | |
817 | | void cmLocalGenerator::ComputeTargetManifest() |
818 | 0 | { |
819 | | // Collect the set of configuration types. |
820 | 0 | std::vector<std::string> configNames = |
821 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
822 | | |
823 | | // Add our targets to the manifest for each configuration. |
824 | 0 | auto const& targets = this->GetGeneratorTargets(); |
825 | 0 | for (auto const& target : targets) { |
826 | 0 | if (!target->IsInBuildSystem()) { |
827 | 0 | continue; |
828 | 0 | } |
829 | 0 | for (std::string const& c : configNames) { |
830 | 0 | target->ComputeTargetManifest(c); |
831 | 0 | } |
832 | 0 | } |
833 | 0 | } |
834 | | |
835 | | bool cmLocalGenerator::ComputeTargetCompileFeatures() |
836 | 0 | { |
837 | | // Collect the set of configuration types. |
838 | 0 | std::vector<std::string> configNames = |
839 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
840 | |
|
841 | 0 | using LanguagePair = std::pair<std::string, std::string>; |
842 | 0 | std::vector<LanguagePair> pairedLanguages{ |
843 | 0 | { "OBJC", "C" }, { "OBJCXX", "CXX" }, { "CUDA", "CXX" }, { "HIP", "CXX" } |
844 | 0 | }; |
845 | 0 | std::set<LanguagePair> inferredEnabledLanguages; |
846 | 0 | for (auto const& lang : pairedLanguages) { |
847 | 0 | if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) { |
848 | 0 | inferredEnabledLanguages.insert(lang); |
849 | 0 | } |
850 | 0 | } |
851 | | |
852 | | // Process compile features of all targets. |
853 | 0 | auto const& targets = this->GetGeneratorTargets(); |
854 | 0 | for (auto const& target : targets) { |
855 | 0 | for (std::string const& c : configNames) { |
856 | 0 | if (!target->ComputeCompileFeatures(c)) { |
857 | 0 | return false; |
858 | 0 | } |
859 | 0 | } |
860 | | |
861 | | // Now that C/C++ _STANDARD values have been computed |
862 | | // set the values to ObjC/ObjCXX _STANDARD variables |
863 | 0 | if (target->CanCompileSources()) { |
864 | 0 | for (std::string const& c : configNames) { |
865 | 0 | target->ComputeCompileFeatures(c, inferredEnabledLanguages); |
866 | 0 | } |
867 | 0 | } |
868 | 0 | } |
869 | | |
870 | 0 | return true; |
871 | 0 | } |
872 | | |
873 | | bool cmLocalGenerator::IsRootMakefile() const |
874 | 0 | { |
875 | 0 | return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid(); |
876 | 0 | } |
877 | | |
878 | | cmState* cmLocalGenerator::GetState() const |
879 | 0 | { |
880 | 0 | return this->GlobalGenerator->GetCMakeInstance()->GetState(); |
881 | 0 | } |
882 | | |
883 | | cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const |
884 | 0 | { |
885 | 0 | return this->Makefile->GetStateSnapshot(); |
886 | 0 | } |
887 | | |
888 | | std::string cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target, |
889 | | std::string const& prop, |
890 | | std::string const& config) |
891 | 0 | { |
892 | 0 | cmValue value = this->Makefile->GetProperty(prop); |
893 | 0 | if (target) { |
894 | 0 | value = target->GetProperty(prop); |
895 | 0 | } |
896 | 0 | if (value) { |
897 | 0 | return cmGeneratorExpression::Evaluate(*value, this, config, target); |
898 | 0 | } |
899 | 0 | return ""; |
900 | 0 | } |
901 | | |
902 | | std::string cmLocalGenerator::ConvertToIncludeReference( |
903 | | std::string const& path, OutputFormat format) |
904 | 0 | { |
905 | 0 | return this->ConvertToOutputForExisting(path, format); |
906 | 0 | } |
907 | | |
908 | | std::string cmLocalGenerator::GetIncludeFlags( |
909 | | std::vector<std::string> const& includeDirs, cmGeneratorTarget* target, |
910 | | std::string const& lang, std::string const& config, bool forResponseFile) |
911 | 0 | { |
912 | 0 | if (lang.empty()) { |
913 | 0 | return ""; |
914 | 0 | } |
915 | | |
916 | 0 | std::vector<std::string> includes = includeDirs; |
917 | 0 | MoveSystemIncludesToEnd(includes, config, lang, target); |
918 | |
|
919 | 0 | OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL; |
920 | 0 | std::ostringstream includeFlags; |
921 | |
|
922 | 0 | std::string const& includeFlag = |
923 | 0 | this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang)); |
924 | 0 | bool quotePaths = false; |
925 | 0 | if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) { |
926 | 0 | quotePaths = true; |
927 | 0 | } |
928 | 0 | std::string sep = " "; |
929 | 0 | bool repeatFlag = true; |
930 | | // should the include flag be repeated like ie. -IA -IB |
931 | 0 | if (cmValue incSep = this->Makefile->GetDefinition( |
932 | 0 | cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang))) { |
933 | | // if there is a separator then the flag is not repeated but is only |
934 | | // given once i.e. -classpath a:b:c |
935 | 0 | sep = *incSep; |
936 | 0 | repeatFlag = false; |
937 | 0 | } |
938 | | |
939 | | // Support special system include flag if it is available and the |
940 | | // normal flag is repeated for each directory. |
941 | 0 | cmValue sysIncludeFlag = nullptr; |
942 | 0 | cmValue sysIncludeFlagWarning = nullptr; |
943 | 0 | if (repeatFlag) { |
944 | 0 | sysIncludeFlag = this->Makefile->GetDefinition( |
945 | 0 | cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang)); |
946 | 0 | sysIncludeFlagWarning = this->Makefile->GetDefinition( |
947 | 0 | cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang, "_WARNING")); |
948 | 0 | } |
949 | |
|
950 | 0 | cmValue fwSearchFlag = this->Makefile->GetDefinition( |
951 | 0 | cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG")); |
952 | 0 | cmValue sysFwSearchFlag = this->Makefile->GetDefinition( |
953 | 0 | cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG")); |
954 | |
|
955 | 0 | bool flagUsed = false; |
956 | 0 | bool sysIncludeFlagUsed = false; |
957 | 0 | std::set<std::string> emitted; |
958 | | #ifdef __APPLE__ |
959 | | emitted.insert("/System/Library/Frameworks"); |
960 | | #endif |
961 | 0 | for (std::string const& i : includes) { |
962 | 0 | if (cmNonempty(fwSearchFlag) && this->Makefile->IsOn("APPLE") && |
963 | 0 | cmSystemTools::IsPathToFramework(i)) { |
964 | 0 | std::string const frameworkDir = cmSystemTools::GetFilenamePath(i); |
965 | 0 | if (emitted.insert(frameworkDir).second) { |
966 | 0 | if (sysFwSearchFlag && target && |
967 | 0 | target->IsSystemIncludeDirectory(frameworkDir, config, lang)) { |
968 | 0 | includeFlags << *sysFwSearchFlag; |
969 | 0 | } else { |
970 | 0 | includeFlags << *fwSearchFlag; |
971 | 0 | } |
972 | 0 | includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat) |
973 | 0 | << " "; |
974 | 0 | } |
975 | 0 | continue; |
976 | 0 | } |
977 | | |
978 | 0 | if (!flagUsed || repeatFlag) { |
979 | 0 | if (sysIncludeFlag && target && |
980 | 0 | target->IsSystemIncludeDirectory(i, config, lang)) { |
981 | 0 | includeFlags << *sysIncludeFlag; |
982 | 0 | sysIncludeFlagUsed = true; |
983 | 0 | } else { |
984 | 0 | includeFlags << includeFlag; |
985 | 0 | } |
986 | 0 | flagUsed = true; |
987 | 0 | } |
988 | 0 | std::string includePath = this->ConvertToIncludeReference(i, shellFormat); |
989 | 0 | if (quotePaths && !includePath.empty() && includePath.front() != '\"') { |
990 | 0 | includeFlags << "\""; |
991 | 0 | } |
992 | 0 | includeFlags << includePath; |
993 | 0 | if (quotePaths && !includePath.empty() && includePath.front() != '\"') { |
994 | 0 | includeFlags << "\""; |
995 | 0 | } |
996 | 0 | includeFlags << sep; |
997 | 0 | } |
998 | 0 | if (sysIncludeFlagUsed && sysIncludeFlagWarning) { |
999 | 0 | includeFlags << *sysIncludeFlagWarning; |
1000 | 0 | } |
1001 | 0 | std::string flags = includeFlags.str(); |
1002 | | // remove trailing separators |
1003 | 0 | if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) { |
1004 | 0 | flags.back() = ' '; |
1005 | 0 | } |
1006 | 0 | return cmTrimWhitespace(flags); |
1007 | 0 | } |
1008 | | |
1009 | | void cmLocalGenerator::AddCompileOptions(std::string& flags, |
1010 | | cmGeneratorTarget* target, |
1011 | | std::string const& lang, |
1012 | | std::string const& config) |
1013 | 0 | { |
1014 | 0 | std::vector<BT<std::string>> tmpFlags; |
1015 | 0 | this->AddCompileOptions(tmpFlags, target, lang, config); |
1016 | 0 | this->AppendFlags(flags, tmpFlags); |
1017 | 0 | } |
1018 | | |
1019 | | void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, |
1020 | | cmGeneratorTarget* target, |
1021 | | std::string const& lang, |
1022 | | std::string const& config) |
1023 | 0 | { |
1024 | 0 | std::string langFlagRegexVar = cmStrCat("CMAKE_", lang, "_FLAG_REGEX"); |
1025 | |
|
1026 | 0 | if (cmValue langFlagRegexStr = |
1027 | 0 | this->Makefile->GetDefinition(langFlagRegexVar)) { |
1028 | | // Filter flags acceptable to this language. |
1029 | 0 | if (cmValue targetFlags = target->GetProperty("COMPILE_FLAGS")) { |
1030 | 0 | std::vector<std::string> opts; |
1031 | 0 | cmSystemTools::ParseWindowsCommandLine(targetFlags->c_str(), opts); |
1032 | | // Re-escape these flags since COMPILE_FLAGS were already parsed |
1033 | | // as a command line above. |
1034 | 0 | std::string compileOpts; |
1035 | 0 | this->AppendCompileOptions(compileOpts, opts, langFlagRegexStr->c_str()); |
1036 | 0 | if (!compileOpts.empty()) { |
1037 | 0 | flags.emplace_back(std::move(compileOpts)); |
1038 | 0 | } |
1039 | 0 | } |
1040 | 0 | std::vector<BT<std::string>> targetCompileOpts = |
1041 | 0 | target->GetCompileOptions(config, lang); |
1042 | | // COMPILE_OPTIONS are escaped. |
1043 | 0 | this->AppendCompileOptions(flags, targetCompileOpts, |
1044 | 0 | langFlagRegexStr->c_str()); |
1045 | 0 | } else { |
1046 | | // Use all flags. |
1047 | 0 | if (cmValue targetFlags = target->GetProperty("COMPILE_FLAGS")) { |
1048 | | // COMPILE_FLAGS are not escaped for historical reasons. |
1049 | 0 | std::string compileFlags; |
1050 | 0 | this->AppendFlags(compileFlags, *targetFlags); |
1051 | 0 | if (!compileFlags.empty()) { |
1052 | 0 | flags.emplace_back(std::move(compileFlags)); |
1053 | 0 | } |
1054 | 0 | } |
1055 | 0 | std::vector<BT<std::string>> targetCompileOpts = |
1056 | 0 | target->GetCompileOptions(config, lang); |
1057 | | // COMPILE_OPTIONS are escaped. |
1058 | 0 | this->AppendCompileOptions(flags, targetCompileOpts); |
1059 | 0 | } |
1060 | |
|
1061 | 0 | cmStandardLevelResolver standardResolver(this->Makefile); |
1062 | 0 | for (auto const& it : target->GetMaxLanguageStandards()) { |
1063 | 0 | cmValue standard = target->GetLanguageStandard(it.first, config); |
1064 | 0 | if (!standard) { |
1065 | 0 | continue; |
1066 | 0 | } |
1067 | 0 | if (standardResolver.IsLaterStandard(it.first, *standard, it.second)) { |
1068 | 0 | std::ostringstream e; |
1069 | 0 | e << "The COMPILE_FEATURES property of target \"" << target->GetName() |
1070 | 0 | << "\" was evaluated when computing the link " |
1071 | 0 | "implementation, and the \"" |
1072 | 0 | << it.first << "_STANDARD\" was \"" << it.second |
1073 | 0 | << "\" for that computation. Computing the " |
1074 | 0 | "COMPILE_FEATURES based on the link implementation resulted in a " |
1075 | 0 | "higher \"" |
1076 | 0 | << it.first << "_STANDARD\" \"" << *standard |
1077 | 0 | << "\". " |
1078 | 0 | "This is not permitted. The COMPILE_FEATURES may not both depend " |
1079 | 0 | "on " |
1080 | 0 | "and be depended on by the link implementation.\n"; |
1081 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
1082 | 0 | return; |
1083 | 0 | } |
1084 | 0 | } |
1085 | | |
1086 | | // Add Warning as errors flags |
1087 | 0 | if (!this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) { |
1088 | 0 | cmValue const wError = target->GetProperty("COMPILE_WARNING_AS_ERROR"); |
1089 | 0 | cmValue const wErrorOpts = this->Makefile->GetDefinition( |
1090 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_WARNING_AS_ERROR")); |
1091 | 0 | if (wError.IsOn() && wErrorOpts.IsSet()) { |
1092 | 0 | std::string wErrorFlags; |
1093 | 0 | this->AppendCompileOptions(wErrorFlags, *wErrorOpts); |
1094 | 0 | if (!wErrorFlags.empty()) { |
1095 | 0 | flags.emplace_back(std::move(wErrorFlags)); |
1096 | 0 | } |
1097 | 0 | } |
1098 | 0 | } |
1099 | | |
1100 | | // Add compile flag for the MSVC compiler only. |
1101 | 0 | cmMakefile* mf = this->GetMakefile(); |
1102 | 0 | if (cmValue jmc = |
1103 | 0 | mf->GetDefinition("CMAKE_" + lang + "_COMPILE_OPTIONS_JMC")) { |
1104 | | |
1105 | | // Handle Just My Code debugging flags, /JMC. |
1106 | | // If the target is a Managed C++ one, /JMC is not compatible. |
1107 | 0 | if (target->GetManagedType(config) != |
1108 | 0 | cmGeneratorTarget::ManagedType::Managed) { |
1109 | | // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set |
1110 | | // to ON |
1111 | 0 | if (cmValue jmcExprGen = |
1112 | 0 | target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) { |
1113 | 0 | std::string isJMCEnabled = |
1114 | 0 | cmGeneratorExpression::Evaluate(*jmcExprGen, this, config); |
1115 | 0 | if (cmIsOn(isJMCEnabled)) { |
1116 | 0 | cmList optList{ *jmc }; |
1117 | 0 | std::string jmcFlags; |
1118 | 0 | this->AppendCompileOptions(jmcFlags, optList); |
1119 | 0 | if (!jmcFlags.empty()) { |
1120 | 0 | flags.emplace_back(std::move(jmcFlags)); |
1121 | 0 | } |
1122 | 0 | } |
1123 | 0 | } |
1124 | 0 | } |
1125 | 0 | } |
1126 | 0 | } |
1127 | | |
1128 | | cmTarget* cmLocalGenerator::AddCustomCommandToTarget( |
1129 | | std::string const& target, cmCustomCommandType type, |
1130 | | std::unique_ptr<cmCustomCommand> cc, cmObjectLibraryCommands objLibCommands) |
1131 | 0 | { |
1132 | 0 | cmTarget* t = this->Makefile->GetCustomCommandTarget( |
1133 | 0 | target, objLibCommands, this->DirectoryBacktrace); |
1134 | 0 | if (!t) { |
1135 | 0 | return nullptr; |
1136 | 0 | } |
1137 | | |
1138 | 0 | cc->SetBacktrace(this->DirectoryBacktrace); |
1139 | |
|
1140 | 0 | detail::AddCustomCommandToTarget(*this, cmCommandOrigin::Generator, t, type, |
1141 | 0 | std::move(cc)); |
1142 | |
|
1143 | 0 | return t; |
1144 | 0 | } |
1145 | | |
1146 | | cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( |
1147 | | std::unique_ptr<cmCustomCommand> cc, bool replace) |
1148 | 0 | { |
1149 | | // Make sure there is at least one output. |
1150 | 0 | if (cc->GetOutputs().empty()) { |
1151 | 0 | cmSystemTools::Error("Attempt to add a custom rule with no output!"); |
1152 | 0 | return nullptr; |
1153 | 0 | } |
1154 | | |
1155 | 0 | cc->SetBacktrace(this->DirectoryBacktrace); |
1156 | 0 | return detail::AddCustomCommandToOutput(*this, cmCommandOrigin::Generator, |
1157 | 0 | std::move(cc), replace); |
1158 | 0 | } |
1159 | | |
1160 | | cmTarget* cmLocalGenerator::AddUtilityCommand( |
1161 | | std::string const& utilityName, bool excludeFromAll, |
1162 | | std::unique_ptr<cmCustomCommand> cc) |
1163 | 0 | { |
1164 | 0 | cmTarget* target = |
1165 | 0 | this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll); |
1166 | 0 | target->SetIsGeneratorProvided(true); |
1167 | |
|
1168 | 0 | if (cc->GetCommandLines().empty() && cc->GetDepends().empty()) { |
1169 | 0 | return target; |
1170 | 0 | } |
1171 | | |
1172 | 0 | cc->SetBacktrace(this->DirectoryBacktrace); |
1173 | 0 | detail::AddUtilityCommand(*this, cmCommandOrigin::Generator, target, |
1174 | 0 | std::move(cc)); |
1175 | |
|
1176 | 0 | return target; |
1177 | 0 | } |
1178 | | |
1179 | | std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( |
1180 | | cmGeneratorTarget const* target, std::string const& lang, |
1181 | | std::string const& config, bool stripImplicitDirs, |
1182 | | bool appendAllImplicitDirs) const |
1183 | 0 | { |
1184 | 0 | std::vector<BT<std::string>> result; |
1185 | | // Do not repeat an include path. |
1186 | 0 | std::set<std::string> emitted; |
1187 | |
|
1188 | 0 | auto emitDir = [&result, &emitted](std::string const& dir) { |
1189 | 0 | if (emitted.insert(dir).second) { |
1190 | 0 | result.emplace_back(dir); |
1191 | 0 | } |
1192 | 0 | }; |
1193 | |
|
1194 | 0 | auto emitBT = [&result, &emitted](BT<std::string> const& dir) { |
1195 | 0 | if (emitted.insert(dir.Value).second) { |
1196 | 0 | result.emplace_back(dir); |
1197 | 0 | } |
1198 | 0 | }; |
1199 | | |
1200 | | // When automatic include directories are requested for a build then |
1201 | | // include the source and binary directories at the beginning of the |
1202 | | // include path to approximate include file behavior for an |
1203 | | // in-source build. This does not account for the case of a source |
1204 | | // file in a subdirectory of the current source directory but we |
1205 | | // cannot fix this because not all native build tools support |
1206 | | // per-source-file include paths. |
1207 | 0 | if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR")) { |
1208 | | // Current binary directory |
1209 | 0 | emitDir(this->StateSnapshot.GetDirectory().GetCurrentBinary()); |
1210 | | // Current source directory |
1211 | 0 | emitDir(this->StateSnapshot.GetDirectory().GetCurrentSource()); |
1212 | 0 | } |
1213 | |
|
1214 | 0 | if (!target) { |
1215 | 0 | return result; |
1216 | 0 | } |
1217 | | |
1218 | | // Standard include directories to be added unconditionally at the end. |
1219 | | // These are intended to simulate additional implicit include directories. |
1220 | 0 | cmList userStandardDirs; |
1221 | 0 | { |
1222 | 0 | std::string const value = this->Makefile->GetSafeDefinition( |
1223 | 0 | cmStrCat("CMAKE_", lang, "_STANDARD_INCLUDE_DIRECTORIES")); |
1224 | 0 | userStandardDirs.assign(value); |
1225 | 0 | for (std::string& usd : userStandardDirs) { |
1226 | 0 | cmSystemTools::ConvertToUnixSlashes(usd); |
1227 | 0 | } |
1228 | 0 | } |
1229 | | |
1230 | | // Implicit include directories |
1231 | 0 | std::vector<std::string> implicitDirs; |
1232 | 0 | std::set<std::string> implicitSet; |
1233 | | // Include directories to be excluded as if they were implicit. |
1234 | 0 | std::set<std::string> implicitExclude; |
1235 | 0 | { |
1236 | | // Raw list of implicit include directories |
1237 | | // Start with "standard" directories that we unconditionally add below. |
1238 | 0 | std::vector<std::string> impDirVec = userStandardDirs; |
1239 | | |
1240 | | // Load implicit include directories for this language. |
1241 | | // We ignore this for Fortran because: |
1242 | | // * There are no standard library headers to avoid overriding. |
1243 | | // * Compilers like gfortran do not search their own implicit include |
1244 | | // directories for modules ('.mod' files). |
1245 | 0 | if (lang != "Fortran") { |
1246 | 0 | size_t const impDirVecOldSize = impDirVec.size(); |
1247 | 0 | cmList::append(impDirVec, |
1248 | 0 | this->Makefile->GetDefinition(cmStrCat( |
1249 | 0 | "CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES"))); |
1250 | | // FIXME: Use cmRange with 'advance()' when it supports non-const. |
1251 | 0 | for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) { |
1252 | 0 | cmSystemTools::ConvertToUnixSlashes(impDirVec[i]); |
1253 | 0 | } |
1254 | | |
1255 | | // The CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES are computed using |
1256 | | // try_compile in CMAKE_DETERMINE_COMPILER_ABI, but the implicit include |
1257 | | // directories are not known during that try_compile. This can be a |
1258 | | // problem when the HIP runtime include path is /usr/include because the |
1259 | | // runtime include path is always added to the userDirs and the compiler |
1260 | | // includes standard library headers via "__clang_hip_runtime_wrapper.h". |
1261 | 0 | if (lang == "HIP" && impDirVec.size() == impDirVecOldSize && |
1262 | 0 | !cm::contains(impDirVec, "/usr/include")) { |
1263 | 0 | implicitExclude.emplace("/usr/include"); |
1264 | 0 | } |
1265 | 0 | } |
1266 | | |
1267 | | // The Platform/UnixPaths module used to hard-code /usr/include for C, CXX, |
1268 | | // and CUDA in CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES, but those |
1269 | | // variables are now computed. On macOS the /usr/include directory is |
1270 | | // inside the platform SDK so the computed value does not contain it |
1271 | | // directly. In this case adding -I/usr/include can hide SDK headers so we |
1272 | | // must still exclude it. |
1273 | 0 | if ((lang == "C" || lang == "CXX" || lang == "CUDA") && |
1274 | 0 | !cm::contains(impDirVec, "/usr/include") && |
1275 | 0 | std::find_if(impDirVec.begin(), impDirVec.end(), |
1276 | 0 | [](std::string const& d) { |
1277 | 0 | return cmHasLiteralSuffix(d, "/usr/include"); |
1278 | 0 | }) != impDirVec.end()) { |
1279 | | // Only exclude this hard coded path for backwards compatibility. |
1280 | 0 | implicitExclude.emplace("/usr/include"); |
1281 | 0 | } |
1282 | |
|
1283 | 0 | for (std::string const& i : impDirVec) { |
1284 | 0 | if (implicitSet.insert(this->GlobalGenerator->GetRealPath(i)).second) { |
1285 | 0 | implicitDirs.emplace_back(i); |
1286 | 0 | } |
1287 | 0 | } |
1288 | 0 | } |
1289 | |
|
1290 | 0 | bool const isCorCxx = (lang == "C" || lang == "CXX"); |
1291 | | |
1292 | | // Resolve symlinks in CPATH for comparison with resolved include paths. |
1293 | | // We do this here instead of when EnvCPATH is populated in case symlinks |
1294 | | // on disk have changed in the meantime. |
1295 | 0 | std::set<std::string> resolvedEnvCPATH; |
1296 | 0 | if (isCorCxx) { |
1297 | 0 | for (std::string const& i : this->EnvCPATH) { |
1298 | 0 | resolvedEnvCPATH.emplace(this->GlobalGenerator->GetRealPath(i)); |
1299 | 0 | } |
1300 | 0 | } |
1301 | | |
1302 | | // Checks if this is not an excluded (implicit) include directory. |
1303 | 0 | auto notExcluded = [this, &implicitSet, &implicitExclude, &resolvedEnvCPATH, |
1304 | 0 | isCorCxx](std::string const& dir) -> bool { |
1305 | 0 | std::string const& real_dir = this->GlobalGenerator->GetRealPath(dir); |
1306 | 0 | return |
1307 | | // Do not exclude directories that are not in any excluded set. |
1308 | 0 | !(cm::contains(implicitSet, real_dir) || |
1309 | 0 | cm::contains(implicitExclude, dir)) |
1310 | | // Do not exclude entries of the CPATH environment variable even though |
1311 | | // they are implicitly searched by the compiler. They are meant to be |
1312 | | // user-specified directories that can be re-ordered or converted to |
1313 | | // -isystem without breaking real compiler builtin headers. |
1314 | 0 | || (isCorCxx && cm::contains(resolvedEnvCPATH, real_dir)); |
1315 | 0 | }; |
1316 | | |
1317 | | // Get the target-specific include directories. |
1318 | 0 | std::vector<BT<std::string>> userDirs = |
1319 | 0 | target->GetIncludeDirectories(config, lang); |
1320 | | |
1321 | | // Support putting all the in-project include directories first if |
1322 | | // it is requested by the project. |
1323 | 0 | if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) { |
1324 | 0 | std::string const& topSourceDir = this->GetState()->GetSourceDirectory(); |
1325 | 0 | std::string const& topBinaryDir = this->GetState()->GetBinaryDirectory(); |
1326 | 0 | for (BT<std::string> const& udr : userDirs) { |
1327 | | // Emit this directory only if it is a subdirectory of the |
1328 | | // top-level source or binary tree. |
1329 | 0 | if (cmSystemTools::ComparePath(udr.Value, topSourceDir) || |
1330 | 0 | cmSystemTools::ComparePath(udr.Value, topBinaryDir) || |
1331 | 0 | cmSystemTools::IsSubDirectory(udr.Value, topSourceDir) || |
1332 | 0 | cmSystemTools::IsSubDirectory(udr.Value, topBinaryDir)) { |
1333 | 0 | if (notExcluded(udr.Value)) { |
1334 | 0 | emitBT(udr); |
1335 | 0 | } |
1336 | 0 | } |
1337 | 0 | } |
1338 | 0 | } |
1339 | | |
1340 | | // Emit remaining non implicit user directories. |
1341 | 0 | for (BT<std::string> const& udr : userDirs) { |
1342 | 0 | if (notExcluded(udr.Value)) { |
1343 | 0 | emitBT(udr); |
1344 | 0 | } |
1345 | 0 | } |
1346 | | |
1347 | | // Sort result |
1348 | 0 | MoveSystemIncludesToEnd(result, config, lang, target); |
1349 | | |
1350 | | // Append standard include directories for this language. |
1351 | 0 | userDirs.reserve(userDirs.size() + userStandardDirs.size()); |
1352 | 0 | for (std::string& usd : userStandardDirs) { |
1353 | 0 | emitDir(usd); |
1354 | 0 | userDirs.emplace_back(std::move(usd)); |
1355 | 0 | } |
1356 | | |
1357 | | // Append compiler implicit include directories |
1358 | 0 | if (!stripImplicitDirs) { |
1359 | | // Append implicit directories that were requested by the user only |
1360 | 0 | for (BT<std::string> const& udr : userDirs) { |
1361 | 0 | if (cm::contains(implicitSet, cmSystemTools::GetRealPath(udr.Value))) { |
1362 | 0 | emitBT(udr); |
1363 | 0 | } |
1364 | 0 | } |
1365 | | // Append remaining implicit directories (on demand) |
1366 | 0 | if (appendAllImplicitDirs) { |
1367 | 0 | for (std::string& imd : implicitDirs) { |
1368 | 0 | emitDir(imd); |
1369 | 0 | } |
1370 | 0 | } |
1371 | 0 | } |
1372 | |
|
1373 | 0 | return result; |
1374 | 0 | } |
1375 | | |
1376 | | void cmLocalGenerator::GetIncludeDirectoriesImplicit( |
1377 | | std::vector<std::string>& dirs, cmGeneratorTarget const* target, |
1378 | | std::string const& lang, std::string const& config, bool stripImplicitDirs, |
1379 | | bool appendAllImplicitDirs) const |
1380 | 0 | { |
1381 | 0 | std::vector<BT<std::string>> tmp = this->GetIncludeDirectoriesImplicit( |
1382 | 0 | target, lang, config, stripImplicitDirs, appendAllImplicitDirs); |
1383 | 0 | dirs.reserve(dirs.size() + tmp.size()); |
1384 | 0 | for (BT<std::string>& v : tmp) { |
1385 | 0 | dirs.emplace_back(std::move(v.Value)); |
1386 | 0 | } |
1387 | 0 | } |
1388 | | |
1389 | | std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectories( |
1390 | | cmGeneratorTarget const* target, std::string const& lang, |
1391 | | std::string const& config) const |
1392 | 0 | { |
1393 | 0 | return this->GetIncludeDirectoriesImplicit(target, lang, config); |
1394 | 0 | } |
1395 | | |
1396 | | void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, |
1397 | | cmGeneratorTarget const* target, |
1398 | | std::string const& lang, |
1399 | | std::string const& config) const |
1400 | 0 | { |
1401 | 0 | this->GetIncludeDirectoriesImplicit(dirs, target, lang, config); |
1402 | 0 | } |
1403 | | |
1404 | | void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags, |
1405 | | std::string const& config, |
1406 | | std::string const& linkLanguage, |
1407 | | cmGeneratorTarget* target) |
1408 | 0 | { |
1409 | 0 | std::vector<BT<std::string>> tmpFlags = |
1410 | 0 | this->GetStaticLibraryFlags(config, linkLanguage, target); |
1411 | 0 | this->AppendFlags(flags, tmpFlags); |
1412 | 0 | } |
1413 | | |
1414 | | std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags( |
1415 | | std::string const& config, std::string const& linkLanguage, |
1416 | | cmGeneratorTarget* target) |
1417 | 0 | { |
1418 | 0 | std::vector<BT<std::string>> flags; |
1419 | 0 | if (linkLanguage != "Swift" && !this->IsSplitSwiftBuild()) { |
1420 | 0 | std::string staticLibFlags; |
1421 | 0 | this->AddConfigVariableFlags(staticLibFlags, "CMAKE_STATIC_LINKER_FLAGS", |
1422 | 0 | config); |
1423 | 0 | if (!staticLibFlags.empty()) { |
1424 | 0 | flags.emplace_back(std::move(staticLibFlags)); |
1425 | 0 | } |
1426 | 0 | } |
1427 | |
|
1428 | 0 | std::string staticLibFlags; |
1429 | 0 | std::string const configUpper = cmSystemTools::UpperCase(config); |
1430 | 0 | this->AppendFlags(staticLibFlags, |
1431 | 0 | target->GetSafeProperty("STATIC_LIBRARY_FLAGS")); |
1432 | 0 | if (!configUpper.empty()) { |
1433 | 0 | std::string name = "STATIC_LIBRARY_FLAGS_" + configUpper; |
1434 | 0 | this->AppendFlags(staticLibFlags, target->GetSafeProperty(name)); |
1435 | 0 | } |
1436 | |
|
1437 | 0 | if (!staticLibFlags.empty()) { |
1438 | 0 | flags.emplace_back(std::move(staticLibFlags)); |
1439 | 0 | } |
1440 | |
|
1441 | 0 | std::vector<BT<std::string>> staticLibOpts = |
1442 | 0 | target->GetStaticLibraryLinkOptions(config, linkLanguage); |
1443 | | // STATIC_LIBRARY_OPTIONS are escaped. |
1444 | 0 | this->AppendCompileOptions(flags, staticLibOpts); |
1445 | |
|
1446 | 0 | return flags; |
1447 | 0 | } |
1448 | | |
1449 | | void cmLocalGenerator::GetDeviceLinkFlags( |
1450 | | cmLinkLineDeviceComputer& linkLineComputer, std::string const& config, |
1451 | | std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath, |
1452 | | std::string& linkPath, cmGeneratorTarget* target) |
1453 | 0 | { |
1454 | 0 | cmGeneratorTarget::DeviceLinkSetter setter(*target); |
1455 | |
|
1456 | 0 | cmComputeLinkInformation* pcli = target->GetLinkInformation(config); |
1457 | |
|
1458 | 0 | auto linklang = linkLineComputer.GetLinkerLanguage(target, config); |
1459 | 0 | auto ipoEnabled = target->IsIPOEnabled(linklang, config); |
1460 | 0 | if (!ipoEnabled && pcli) { |
1461 | 0 | ipoEnabled = linkLineComputer.ComputeRequiresDeviceLinkingIPOFlag(*pcli); |
1462 | 0 | } |
1463 | 0 | if (ipoEnabled) { |
1464 | 0 | if (cmValue cudaIPOFlags = this->Makefile->GetDefinition( |
1465 | 0 | "CMAKE_CUDA_DEVICE_LINK_OPTIONS_IPO")) { |
1466 | 0 | linkFlags += *cudaIPOFlags; |
1467 | 0 | } |
1468 | 0 | } |
1469 | |
|
1470 | 0 | if (pcli) { |
1471 | | // Compute the required device link libraries when |
1472 | | // resolving gpu lang device symbols |
1473 | 0 | this->OutputLinkLibraries(pcli, &linkLineComputer, linkLibs, frameworkPath, |
1474 | 0 | linkPath); |
1475 | 0 | } |
1476 | |
|
1477 | 0 | this->AddVisibilityPresetFlags(linkFlags, target, "CUDA"); |
1478 | 0 | this->GetGlobalGenerator()->EncodeLiteral(linkFlags); |
1479 | |
|
1480 | 0 | std::vector<std::string> linkOpts; |
1481 | 0 | target->GetLinkOptions(linkOpts, config, "CUDA"); |
1482 | 0 | this->SetLinkScriptShell(this->GetGlobalGenerator()->GetUseLinkScript()); |
1483 | | // LINK_OPTIONS are escaped. |
1484 | 0 | this->AppendCompileOptions(linkFlags, linkOpts); |
1485 | 0 | this->SetLinkScriptShell(false); |
1486 | 0 | } |
1487 | | |
1488 | | void cmLocalGenerator::GetTargetFlags( |
1489 | | cmLinkLineComputer* linkLineComputer, std::string const& config, |
1490 | | std::string& linkLibs, std::string& flags, std::string& linkFlags, |
1491 | | std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target) |
1492 | 0 | { |
1493 | 0 | std::vector<BT<std::string>> linkFlagsList; |
1494 | 0 | std::vector<BT<std::string>> linkPathList; |
1495 | 0 | std::vector<BT<std::string>> linkLibsList; |
1496 | 0 | this->GetTargetFlags(linkLineComputer, config, linkLibsList, flags, |
1497 | 0 | linkFlagsList, frameworkPath, linkPathList, target); |
1498 | 0 | this->AppendFlags(linkFlags, linkFlagsList); |
1499 | 0 | this->AppendFlags(linkPath, linkPathList); |
1500 | 0 | this->AppendFlags(linkLibs, linkLibsList); |
1501 | 0 | } |
1502 | | |
1503 | | void cmLocalGenerator::GetTargetFlags( |
1504 | | cmLinkLineComputer* linkLineComputer, std::string const& config, |
1505 | | std::vector<BT<std::string>>& linkLibs, std::string& flags, |
1506 | | std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath, |
1507 | | std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target) |
1508 | 0 | { |
1509 | 0 | std::string const configUpper = cmSystemTools::UpperCase(config); |
1510 | 0 | cmComputeLinkInformation* pcli = target->GetLinkInformation(config); |
1511 | |
|
1512 | 0 | std::string const linkLanguage = |
1513 | 0 | linkLineComputer->GetLinkerLanguage(target, config); |
1514 | |
|
1515 | 0 | { |
1516 | 0 | std::string createFlags; |
1517 | 0 | this->AppendTargetCreationLinkFlags(createFlags, target, linkLanguage); |
1518 | 0 | if (!createFlags.empty()) { |
1519 | 0 | linkFlags.emplace_back(std::move(createFlags)); |
1520 | 0 | } |
1521 | 0 | } |
1522 | |
|
1523 | 0 | switch (target->GetType()) { |
1524 | 0 | case cmStateEnums::STATIC_LIBRARY: |
1525 | 0 | linkFlags = this->GetStaticLibraryFlags(config, linkLanguage, target); |
1526 | 0 | break; |
1527 | 0 | case cmStateEnums::MODULE_LIBRARY: |
1528 | 0 | CM_FALLTHROUGH; |
1529 | 0 | case cmStateEnums::SHARED_LIBRARY: { |
1530 | 0 | if (this->IsSplitSwiftBuild() || linkLanguage != "Swift") { |
1531 | 0 | std::string libFlags; |
1532 | 0 | this->AddTargetTypeLinkerFlags(libFlags, target, linkLanguage, config); |
1533 | 0 | if (!libFlags.empty()) { |
1534 | 0 | linkFlags.emplace_back(std::move(libFlags)); |
1535 | 0 | } |
1536 | 0 | } |
1537 | |
|
1538 | 0 | std::string langLinkFlags; |
1539 | 0 | this->AddPerLanguageLinkFlags(langLinkFlags, target, linkLanguage, |
1540 | 0 | config); |
1541 | 0 | if (!langLinkFlags.empty()) { |
1542 | 0 | linkFlags.emplace_back(std::move(langLinkFlags)); |
1543 | 0 | } |
1544 | |
|
1545 | 0 | std::string sharedLibFlags; |
1546 | 0 | this->AddTargetPropertyLinkFlags(sharedLibFlags, target, config); |
1547 | 0 | if (!sharedLibFlags.empty()) { |
1548 | 0 | this->GetGlobalGenerator()->EncodeLiteral(sharedLibFlags); |
1549 | 0 | linkFlags.emplace_back(std::move(sharedLibFlags)); |
1550 | 0 | } |
1551 | |
|
1552 | 0 | std::vector<BT<std::string>> linkOpts = |
1553 | 0 | target->GetLinkOptions(config, linkLanguage); |
1554 | 0 | this->SetLinkScriptShell(this->GetGlobalGenerator()->GetUseLinkScript()); |
1555 | | // LINK_OPTIONS are escaped. |
1556 | 0 | this->AppendCompileOptions(linkFlags, linkOpts); |
1557 | 0 | this->SetLinkScriptShell(false); |
1558 | |
|
1559 | 0 | if (pcli) { |
1560 | 0 | this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, |
1561 | 0 | frameworkPath, linkPath); |
1562 | 0 | } |
1563 | 0 | } break; |
1564 | 0 | case cmStateEnums::EXECUTABLE: { |
1565 | 0 | if (linkLanguage != "Swift" || |
1566 | 0 | (this->IsSplitSwiftBuild() && |
1567 | 0 | target->GetPolicyStatusCMP0214() == cmPolicies::NEW)) { |
1568 | 0 | std::string exeFlags; |
1569 | 0 | this->AddTargetTypeLinkerFlags(exeFlags, target, linkLanguage, config); |
1570 | 0 | if (!exeFlags.empty()) { |
1571 | 0 | linkFlags.emplace_back(std::move(exeFlags)); |
1572 | 0 | } |
1573 | 0 | } |
1574 | |
|
1575 | 0 | std::string langLinkFlags; |
1576 | 0 | this->AddPerLanguageLinkFlags(langLinkFlags, target, linkLanguage, |
1577 | 0 | config); |
1578 | 0 | if (!langLinkFlags.empty()) { |
1579 | 0 | linkFlags.emplace_back(std::move(langLinkFlags)); |
1580 | 0 | } |
1581 | |
|
1582 | 0 | { |
1583 | 0 | auto exeType = cmStrCat( |
1584 | 0 | "CMAKE_", linkLanguage, "_CREATE_", |
1585 | 0 | (target->IsWin32Executable(config) ? "WIN32" : "CONSOLE"), "_EXE"); |
1586 | 0 | std::string exeFlags; |
1587 | 0 | this->AppendFlags(exeFlags, this->Makefile->GetDefinition(exeType), |
1588 | 0 | exeType, target, cmBuildStep::Link, linkLanguage); |
1589 | 0 | if (!exeFlags.empty()) { |
1590 | 0 | linkFlags.emplace_back(std::move(exeFlags)); |
1591 | 0 | } |
1592 | 0 | } |
1593 | |
|
1594 | 0 | std::string exeFlags; |
1595 | 0 | if (target->IsExecutableWithExports()) { |
1596 | 0 | exeFlags += this->Makefile->GetSafeDefinition( |
1597 | 0 | cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG")); |
1598 | 0 | exeFlags += " "; |
1599 | 0 | } |
1600 | |
|
1601 | 0 | this->AddLanguageFlagsForLinking(flags, target, linkLanguage, config); |
1602 | 0 | if (pcli) { |
1603 | 0 | this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, |
1604 | 0 | frameworkPath, linkPath); |
1605 | 0 | } |
1606 | |
|
1607 | 0 | if (this->Makefile->IsOn("BUILD_SHARED_LIBS")) { |
1608 | 0 | std::string sFlagVar = "CMAKE_SHARED_BUILD_" + linkLanguage + "_FLAGS"; |
1609 | 0 | exeFlags += this->Makefile->GetSafeDefinition(sFlagVar); |
1610 | 0 | exeFlags += " "; |
1611 | 0 | } |
1612 | |
|
1613 | 0 | std::string exeExportFlags = |
1614 | 0 | this->GetExeExportFlags(linkLanguage, *target); |
1615 | 0 | if (!exeExportFlags.empty()) { |
1616 | 0 | exeFlags += exeExportFlags; |
1617 | 0 | exeFlags += " "; |
1618 | 0 | } |
1619 | |
|
1620 | 0 | this->AddTargetPropertyLinkFlags(exeFlags, target, config); |
1621 | |
|
1622 | 0 | if (!exeFlags.empty()) { |
1623 | 0 | this->GetGlobalGenerator()->EncodeLiteral(exeFlags); |
1624 | 0 | linkFlags.emplace_back(std::move(exeFlags)); |
1625 | 0 | } |
1626 | |
|
1627 | 0 | std::vector<BT<std::string>> linkOpts = |
1628 | 0 | target->GetLinkOptions(config, linkLanguage); |
1629 | 0 | this->SetLinkScriptShell(this->GetGlobalGenerator()->GetUseLinkScript()); |
1630 | | // LINK_OPTIONS are escaped. |
1631 | 0 | this->AppendCompileOptions(linkFlags, linkOpts); |
1632 | 0 | this->SetLinkScriptShell(false); |
1633 | 0 | } break; |
1634 | 0 | default: |
1635 | 0 | break; |
1636 | 0 | } |
1637 | | |
1638 | 0 | std::string extraLinkFlags; |
1639 | 0 | this->AppendLinkerTypeFlags(extraLinkFlags, target, config, linkLanguage); |
1640 | 0 | this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config, |
1641 | 0 | linkLanguage); |
1642 | 0 | this->AppendWarningAsErrorLinkerFlags(extraLinkFlags, target, linkLanguage); |
1643 | 0 | this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage); |
1644 | 0 | this->AppendModuleDefinitionFlag(extraLinkFlags, target, linkLineComputer, |
1645 | 0 | config, linkLanguage); |
1646 | |
|
1647 | 0 | if (!extraLinkFlags.empty()) { |
1648 | 0 | this->GetGlobalGenerator()->EncodeLiteral(extraLinkFlags); |
1649 | 0 | linkFlags.emplace_back(std::move(extraLinkFlags)); |
1650 | 0 | } |
1651 | 0 | } |
1652 | | |
1653 | | void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target, |
1654 | | std::string const& config, |
1655 | | std::string const& lang, |
1656 | | std::string& flags, |
1657 | | std::string const& arch) |
1658 | 0 | { |
1659 | 0 | std::vector<BT<std::string>> tmpFlags = |
1660 | 0 | this->GetTargetCompileFlags(target, config, lang, arch); |
1661 | 0 | this->AppendFlags(flags, tmpFlags); |
1662 | 0 | } |
1663 | | |
1664 | | std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags( |
1665 | | cmGeneratorTarget* target, std::string const& config, |
1666 | | std::string const& lang, std::string const& arch) |
1667 | 0 | { |
1668 | 0 | std::vector<BT<std::string>> flags; |
1669 | 0 | std::string compileFlags; |
1670 | |
|
1671 | 0 | cmMakefile* mf = this->GetMakefile(); |
1672 | | |
1673 | | // Add language-specific flags. |
1674 | 0 | this->AddLanguageFlags(compileFlags, target, cmBuildStep::Compile, lang, |
1675 | 0 | config); |
1676 | |
|
1677 | 0 | if (target->IsIPOEnabled(lang, config)) { |
1678 | 0 | this->AppendFeatureOptions(compileFlags, lang, "IPO"); |
1679 | 0 | } |
1680 | |
|
1681 | 0 | this->AddArchitectureFlags(compileFlags, target, lang, config, arch); |
1682 | |
|
1683 | 0 | if (lang == "Fortran") { |
1684 | 0 | this->AppendFlags(compileFlags, |
1685 | 0 | this->GetTargetFortranFlags(target, config)); |
1686 | 0 | } else if (lang == "Swift") { |
1687 | | // Only set the compile mode if CMP0157 is set |
1688 | 0 | if (cm::optional<cmSwiftCompileMode> swiftCompileMode = |
1689 | 0 | this->GetSwiftCompileMode(target, config)) { |
1690 | 0 | std::string swiftCompileModeFlag; |
1691 | 0 | switch (*swiftCompileMode) { |
1692 | 0 | case cmSwiftCompileMode::Incremental: { |
1693 | 0 | swiftCompileModeFlag = "-incremental"; |
1694 | 0 | if (cmValue flag = |
1695 | 0 | mf->GetDefinition("CMAKE_Swift_COMPILE_OPTIONS_INCREMENTAL")) { |
1696 | 0 | swiftCompileModeFlag = *flag; |
1697 | 0 | } |
1698 | 0 | break; |
1699 | 0 | } |
1700 | 0 | case cmSwiftCompileMode::Wholemodule: { |
1701 | 0 | swiftCompileModeFlag = "-wmo"; |
1702 | 0 | if (cmValue flag = |
1703 | 0 | mf->GetDefinition("CMAKE_Swift_COMPILE_OPTIONS_WMO")) { |
1704 | 0 | swiftCompileModeFlag = *flag; |
1705 | 0 | } |
1706 | 0 | break; |
1707 | 0 | } |
1708 | 0 | case cmSwiftCompileMode::Singlefile: |
1709 | 0 | break; |
1710 | 0 | case cmSwiftCompileMode::Unknown: { |
1711 | 0 | this->IssueDiagnostic( |
1712 | 0 | cmDiagnostics::CMD_AUTHOR, |
1713 | 0 | cmStrCat("Unknown Swift_COMPILATION_MODE on target '", |
1714 | 0 | target->GetName(), '\'')); |
1715 | 0 | } |
1716 | 0 | } |
1717 | 0 | this->AppendFlags(compileFlags, swiftCompileModeFlag); |
1718 | 0 | } |
1719 | 0 | } |
1720 | | |
1721 | 0 | this->AddFeatureFlags(compileFlags, target, lang, config); |
1722 | 0 | this->AddVisibilityPresetFlags(compileFlags, target, lang); |
1723 | 0 | this->AddColorDiagnosticsFlags(compileFlags, lang); |
1724 | 0 | this->AppendFlags(compileFlags, mf->GetDefineFlags()); |
1725 | 0 | this->AppendFlags(compileFlags, |
1726 | 0 | this->GetFrameworkFlags(lang, config, target)); |
1727 | 0 | this->AppendFlags(compileFlags, |
1728 | 0 | this->GetXcFrameworkFlags(lang, config, target)); |
1729 | |
|
1730 | 0 | if (!compileFlags.empty()) { |
1731 | 0 | flags.emplace_back(std::move(compileFlags)); |
1732 | 0 | } |
1733 | 0 | this->AddCompileOptions(flags, target, lang, config); |
1734 | 0 | return flags; |
1735 | 0 | } |
1736 | | |
1737 | | std::string cmLocalGenerator::GetFrameworkFlags(std::string const& lang, |
1738 | | std::string const& config, |
1739 | | cmGeneratorTarget* target) |
1740 | 0 | { |
1741 | 0 | cmLocalGenerator* lg = target->GetLocalGenerator(); |
1742 | 0 | cmMakefile* mf = lg->GetMakefile(); |
1743 | |
|
1744 | 0 | if (!target->IsApple()) { |
1745 | 0 | return std::string(); |
1746 | 0 | } |
1747 | | |
1748 | 0 | cmValue fwSearchFlag = |
1749 | 0 | mf->GetDefinition(cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG")); |
1750 | 0 | cmValue sysFwSearchFlag = mf->GetDefinition( |
1751 | 0 | cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG")); |
1752 | |
|
1753 | 0 | if (!fwSearchFlag && !sysFwSearchFlag) { |
1754 | 0 | return std::string{}; |
1755 | 0 | } |
1756 | | |
1757 | 0 | std::set<std::string> emitted; |
1758 | | #ifdef __APPLE__ /* don't insert this when crosscompiling e.g. to iphone */ |
1759 | | emitted.insert("/System/Library/Frameworks"); |
1760 | | #endif |
1761 | 0 | std::vector<std::string> includes; |
1762 | |
|
1763 | 0 | lg->GetIncludeDirectories(includes, target, "C", config); |
1764 | | // check all include directories for frameworks as this |
1765 | | // will already have added a -F for the framework |
1766 | 0 | for (std::string const& include : includes) { |
1767 | 0 | if (lg->GetGlobalGenerator()->NameResolvesToFramework(include)) { |
1768 | 0 | std::string frameworkDir = cmStrCat(include, "/../"); |
1769 | 0 | frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir); |
1770 | 0 | emitted.insert(frameworkDir); |
1771 | 0 | } |
1772 | 0 | } |
1773 | |
|
1774 | 0 | std::string flags; |
1775 | 0 | if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) { |
1776 | 0 | std::vector<std::string> const& frameworks = cli->GetFrameworkPaths(); |
1777 | 0 | for (std::string const& framework : frameworks) { |
1778 | 0 | if (emitted.insert(framework).second) { |
1779 | 0 | if (sysFwSearchFlag && |
1780 | 0 | target->IsSystemIncludeDirectory(framework, config, lang)) { |
1781 | 0 | flags += *sysFwSearchFlag; |
1782 | 0 | } else { |
1783 | 0 | flags += *fwSearchFlag; |
1784 | 0 | } |
1785 | 0 | flags += |
1786 | 0 | lg->ConvertToOutputFormat(framework, cmOutputConverter::SHELL); |
1787 | 0 | flags += " "; |
1788 | 0 | } |
1789 | 0 | } |
1790 | 0 | } |
1791 | 0 | return flags; |
1792 | 0 | } |
1793 | | |
1794 | | std::string cmLocalGenerator::GetXcFrameworkFlags(std::string const& lang, |
1795 | | std::string const& config, |
1796 | | cmGeneratorTarget* target) |
1797 | 0 | { |
1798 | 0 | cmLocalGenerator* lg = target->GetLocalGenerator(); |
1799 | 0 | cmMakefile* mf = lg->GetMakefile(); |
1800 | |
|
1801 | 0 | if (!target->IsApple()) { |
1802 | 0 | return std::string(); |
1803 | 0 | } |
1804 | | |
1805 | 0 | cmValue includeSearchFlag = |
1806 | 0 | mf->GetDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang)); |
1807 | 0 | cmValue sysIncludeSearchFlag = |
1808 | 0 | mf->GetDefinition(cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang)); |
1809 | |
|
1810 | 0 | if (!includeSearchFlag && !sysIncludeSearchFlag) { |
1811 | 0 | return std::string{}; |
1812 | 0 | } |
1813 | | |
1814 | 0 | std::string flags; |
1815 | 0 | if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) { |
1816 | 0 | std::vector<std::string> const& paths = cli->GetXcFrameworkHeaderPaths(); |
1817 | 0 | for (std::string const& path : paths) { |
1818 | 0 | if (sysIncludeSearchFlag && |
1819 | 0 | target->IsSystemIncludeDirectory(path, config, lang)) { |
1820 | 0 | flags += *sysIncludeSearchFlag; |
1821 | 0 | } else { |
1822 | 0 | flags += *includeSearchFlag; |
1823 | 0 | } |
1824 | 0 | flags += lg->ConvertToOutputFormat(path, cmOutputConverter::SHELL); |
1825 | 0 | flags += " "; |
1826 | 0 | } |
1827 | 0 | } |
1828 | 0 | return flags; |
1829 | 0 | } |
1830 | | |
1831 | | void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target, |
1832 | | std::string const& config, |
1833 | | std::string const& lang, |
1834 | | std::set<std::string>& defines) const |
1835 | 0 | { |
1836 | 0 | std::set<BT<std::string>> tmp = this->GetTargetDefines(target, config, lang); |
1837 | 0 | for (BT<std::string> const& v : tmp) { |
1838 | 0 | defines.emplace(v.Value); |
1839 | 0 | } |
1840 | 0 | } |
1841 | | |
1842 | | std::set<BT<std::string>> cmLocalGenerator::GetTargetDefines( |
1843 | | cmGeneratorTarget const* target, std::string const& config, |
1844 | | std::string const& lang) const |
1845 | 0 | { |
1846 | 0 | std::set<BT<std::string>> defines; |
1847 | | |
1848 | | // Add the export symbol definition for shared library objects. |
1849 | 0 | if (std::string const* exportMacro = target->GetExportMacro()) { |
1850 | 0 | this->AppendDefines(defines, *exportMacro); |
1851 | 0 | } |
1852 | 0 | for (auto const& sharedLibCompileDef : |
1853 | 0 | target->GetSharedLibraryCompileDefs(config)) { |
1854 | 0 | this->AppendDefines(defines, sharedLibCompileDef); |
1855 | 0 | } |
1856 | | |
1857 | | // Add preprocessor definitions for this target and configuration. |
1858 | 0 | std::vector<BT<std::string>> targetDefines = |
1859 | 0 | target->GetCompileDefinitions(config, lang); |
1860 | 0 | this->AppendDefines(defines, targetDefines); |
1861 | |
|
1862 | 0 | return defines; |
1863 | 0 | } |
1864 | | |
1865 | | std::string cmLocalGenerator::GetTargetFortranFlags( |
1866 | | cmGeneratorTarget const* /*unused*/, std::string const& /*unused*/) |
1867 | 0 | { |
1868 | | // Implemented by specific generators that override this. |
1869 | 0 | return std::string(); |
1870 | 0 | } |
1871 | | |
1872 | | /** |
1873 | | * Output the linking rules on a command line. For executables, |
1874 | | * targetLibrary should be a NULL pointer. For libraries, it should point |
1875 | | * to the name of the library. This will not link a library against itself. |
1876 | | */ |
1877 | | void cmLocalGenerator::OutputLinkLibraries( |
1878 | | cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer, |
1879 | | std::string& linkLibraries, std::string& frameworkPath, |
1880 | | std::string& linkPath) |
1881 | 0 | { |
1882 | 0 | std::vector<BT<std::string>> linkLibrariesList; |
1883 | 0 | std::vector<BT<std::string>> linkPathList; |
1884 | 0 | this->OutputLinkLibraries(pcli, linkLineComputer, linkLibrariesList, |
1885 | 0 | frameworkPath, linkPathList); |
1886 | 0 | pcli->AppendValues(linkLibraries, linkLibrariesList); |
1887 | 0 | pcli->AppendValues(linkPath, linkPathList); |
1888 | 0 | } |
1889 | | |
1890 | | void cmLocalGenerator::OutputLinkLibraries( |
1891 | | cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer, |
1892 | | std::vector<BT<std::string>>& linkLibraries, std::string& frameworkPath, |
1893 | | std::vector<BT<std::string>>& linkPath) |
1894 | 0 | { |
1895 | 0 | cmComputeLinkInformation& cli = *pcli; |
1896 | |
|
1897 | 0 | std::string linkLanguage = cli.GetLinkLanguage(); |
1898 | |
|
1899 | 0 | std::string libPathFlag; |
1900 | 0 | if (cmValue value = this->Makefile->GetDefinition( |
1901 | 0 | "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_FLAG")) { |
1902 | 0 | libPathFlag = *value; |
1903 | 0 | } else { |
1904 | 0 | libPathFlag = |
1905 | 0 | this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG"); |
1906 | 0 | } |
1907 | |
|
1908 | 0 | std::string libPathTerminator; |
1909 | 0 | if (cmValue value = this->Makefile->GetDefinition( |
1910 | 0 | "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_TERMINATOR")) { |
1911 | 0 | libPathTerminator = *value; |
1912 | 0 | } else { |
1913 | 0 | libPathTerminator = |
1914 | 0 | this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_TERMINATOR"); |
1915 | 0 | } |
1916 | | |
1917 | | // Add standard link directories for this language |
1918 | 0 | std::string stdLinkDirString = this->Makefile->GetSafeDefinition( |
1919 | 0 | cmStrCat("CMAKE_", cli.GetLinkLanguage(), "_STANDARD_LINK_DIRECTORIES")); |
1920 | | |
1921 | | // Add standard libraries for this language. |
1922 | 0 | std::string stdLibString = this->Makefile->GetSafeDefinition( |
1923 | 0 | cmStrCat("CMAKE_", cli.GetLinkLanguage(), "_STANDARD_LIBRARIES")); |
1924 | | |
1925 | | // Append the framework search path flags. |
1926 | 0 | cmValue fwSearchFlag = this->Makefile->GetDefinition( |
1927 | 0 | cmStrCat("CMAKE_", linkLanguage, "_FRAMEWORK_SEARCH_FLAG")); |
1928 | |
|
1929 | 0 | frameworkPath = linkLineComputer->ComputeFrameworkPath(cli, fwSearchFlag); |
1930 | 0 | linkLineComputer->ComputeLinkPath(cli, libPathFlag, libPathTerminator, |
1931 | 0 | stdLinkDirString, linkPath); |
1932 | 0 | linkLineComputer->ComputeLinkLibraries(cli, stdLibString, linkLibraries); |
1933 | 0 | } |
1934 | | |
1935 | | std::string cmLocalGenerator::GetExeExportFlags( |
1936 | | std::string const& linkLanguage, cmGeneratorTarget& tgt) const |
1937 | 0 | { |
1938 | 0 | std::string linkFlags; |
1939 | | |
1940 | | // Flags to export symbols from an executable. |
1941 | 0 | if (tgt.GetType() == cmStateEnums::EXECUTABLE && |
1942 | 0 | this->StateSnapshot.GetState()->GetGlobalPropertyAsBool( |
1943 | 0 | "TARGET_SUPPORTS_SHARED_LIBS")) { |
1944 | | // Only add the flags if ENABLE_EXPORTS is on, |
1945 | | // except on AIX where we compute symbol exports. |
1946 | 0 | if (!tgt.IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS")) { |
1947 | 0 | linkFlags = this->Makefile->GetSafeDefinition( |
1948 | 0 | cmStrCat("CMAKE_SHARED_LIBRARY_LINK_", linkLanguage, "_FLAGS")); |
1949 | 0 | } |
1950 | 0 | } |
1951 | 0 | return linkFlags; |
1952 | 0 | } |
1953 | | |
1954 | | bool cmLocalGenerator::AllAppleArchSysrootsAreTheSame( |
1955 | | std::vector<std::string> const& archs, cmValue sysroot) |
1956 | 0 | { |
1957 | 0 | if (!sysroot) { |
1958 | 0 | return false; |
1959 | 0 | } |
1960 | | |
1961 | 0 | return std::all_of(archs.begin(), archs.end(), |
1962 | 0 | [this, sysroot](std::string const& arch) -> bool { |
1963 | 0 | std::string const& archSysroot = |
1964 | 0 | this->AppleArchSysroots[arch]; |
1965 | 0 | return cmIsOff(archSysroot) || *sysroot == archSysroot; |
1966 | 0 | }); |
1967 | 0 | } |
1968 | | |
1969 | | void cmLocalGenerator::AddArchitectureFlags(std::string& flags, |
1970 | | cmGeneratorTarget const* target, |
1971 | | std::string const& lang, |
1972 | | std::string const& config, |
1973 | | std::string const& filterArch) |
1974 | 0 | { |
1975 | | // Only add Apple specific flags on Apple platforms |
1976 | 0 | if (target->IsApple() && this->EmitUniversalBinaryFlags) { |
1977 | 0 | std::vector<std::string> archs = target->GetAppleArchs(config, lang); |
1978 | 0 | if (!archs.empty() && |
1979 | 0 | (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX" || |
1980 | 0 | lang == "ASM")) { |
1981 | 0 | for (std::string const& arch : archs) { |
1982 | 0 | if (filterArch.empty() || filterArch == arch) { |
1983 | 0 | flags += " -arch "; |
1984 | 0 | flags += arch; |
1985 | 0 | } |
1986 | 0 | } |
1987 | 0 | } |
1988 | |
|
1989 | 0 | cmValue sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT"); |
1990 | 0 | if (sysroot.IsEmpty() && |
1991 | 0 | this->Makefile->IsOn( |
1992 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_APPLE_SYSROOT_REQUIRED"))) { |
1993 | 0 | sysroot = this->Makefile->GetDefinition("_CMAKE_OSX_SYSROOT_PATH"); |
1994 | 0 | } |
1995 | 0 | if (sysroot && *sysroot == "/") { |
1996 | 0 | sysroot = nullptr; |
1997 | 0 | } |
1998 | 0 | std::string sysrootFlagVar = "CMAKE_" + lang + "_SYSROOT_FLAG"; |
1999 | 0 | cmValue sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar); |
2000 | 0 | if (cmNonempty(sysrootFlag)) { |
2001 | 0 | if (!this->AppleArchSysroots.empty() && |
2002 | 0 | !this->AllAppleArchSysrootsAreTheSame(archs, sysroot)) { |
2003 | 0 | for (std::string const& arch : archs) { |
2004 | 0 | std::string const& archSysroot = this->AppleArchSysroots[arch]; |
2005 | 0 | if (cmIsOff(archSysroot)) { |
2006 | 0 | continue; |
2007 | 0 | } |
2008 | 0 | if (filterArch.empty() || filterArch == arch) { |
2009 | 0 | flags += " -Xarch_" + arch + " "; |
2010 | | // Combine sysroot flag and path to work with -Xarch |
2011 | 0 | std::string arch_sysroot = *sysrootFlag + archSysroot; |
2012 | 0 | flags += this->ConvertToOutputFormat(arch_sysroot, SHELL); |
2013 | 0 | } |
2014 | 0 | } |
2015 | 0 | } else if (cmNonempty(sysroot)) { |
2016 | 0 | flags += " "; |
2017 | 0 | flags += *sysrootFlag; |
2018 | 0 | flags += " "; |
2019 | 0 | flags += this->ConvertToOutputFormat(*sysroot, SHELL); |
2020 | 0 | } |
2021 | 0 | } |
2022 | |
|
2023 | 0 | cmValue deploymentTarget = |
2024 | 0 | this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET"); |
2025 | 0 | if (cmNonempty(deploymentTarget)) { |
2026 | 0 | std::string deploymentTargetFlagVar = |
2027 | 0 | "CMAKE_" + lang + "_OSX_DEPLOYMENT_TARGET_FLAG"; |
2028 | 0 | cmValue deploymentTargetFlag = |
2029 | 0 | this->Makefile->GetDefinition(deploymentTargetFlagVar); |
2030 | 0 | if (cmNonempty(deploymentTargetFlag) && |
2031 | | // CMAKE_<LANG>_COMPILER_TARGET overrides a --target= for |
2032 | | // CMAKE_OSX_DEPLOYMENT_TARGET, e.g., for visionOS. |
2033 | 0 | (!cmHasLiteralPrefix(*deploymentTarget, "--target=") || |
2034 | 0 | this->Makefile |
2035 | 0 | ->GetDefinition(cmStrCat("CMAKE_", lang, "_COMPILER_TARGET")) |
2036 | 0 | .IsEmpty())) { |
2037 | 0 | std::string flag = *deploymentTargetFlag; |
2038 | | |
2039 | | // Add the deployment target architecture to the flag, if needed. |
2040 | 0 | static std::string const kARCH = "<ARCH>"; |
2041 | 0 | std::string::size_type archPos = flag.find(kARCH); |
2042 | 0 | if (archPos != std::string::npos) { |
2043 | | // This placeholder is meant for visionOS, so default to arm64 |
2044 | | // unless only non-arm64 archs are given. |
2045 | 0 | std::string const arch = |
2046 | 0 | (archs.empty() || cm::contains(archs, "arm64")) ? "arm64" |
2047 | 0 | : archs[0]; |
2048 | | // Replace the placeholder with its value. |
2049 | 0 | flag = cmStrCat(flag.substr(0, archPos), arch, |
2050 | 0 | flag.substr(archPos + kARCH.size())); |
2051 | 0 | } |
2052 | | |
2053 | | // Add the deployment target version to the flag. |
2054 | 0 | static std::string const kVERSION_MIN = "<VERSION_MIN>"; |
2055 | 0 | std::string::size_type verPos = flag.find(kVERSION_MIN); |
2056 | 0 | if (verPos != std::string::npos) { |
2057 | | // Replace the placeholder with its value. |
2058 | 0 | flag = cmStrCat(flag.substr(0, verPos), *deploymentTarget, |
2059 | 0 | flag.substr(verPos + kVERSION_MIN.size())); |
2060 | 0 | } else { |
2061 | | // There is no placeholder, so append the value. |
2062 | 0 | flag = cmStrCat(flag, *deploymentTarget); |
2063 | 0 | } |
2064 | |
|
2065 | 0 | flags += " "; |
2066 | 0 | flags += flag; |
2067 | 0 | } |
2068 | 0 | } |
2069 | 0 | } |
2070 | 0 | } |
2071 | | |
2072 | | void cmLocalGenerator::AddLanguageFlags(std::string& flags, |
2073 | | cmGeneratorTarget const* target, |
2074 | | cmBuildStep compileOrLink, |
2075 | | std::string const& lang, |
2076 | | std::string const& config) |
2077 | 0 | { |
2078 | | // Add language-specific flags. |
2079 | 0 | this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"), |
2080 | 0 | config); |
2081 | | |
2082 | | // Add the language standard flag for compiling, and sometimes linking. |
2083 | 0 | if (compileOrLink == cmBuildStep::Compile || |
2084 | 0 | (compileOrLink == cmBuildStep::Link && |
2085 | | // Some toolchains require use of the language standard flag |
2086 | | // when linking in order to use the matching standard library. |
2087 | | // FIXME: If CMake gains an abstraction for standard library |
2088 | | // selection, this will have to be reconciled with it. |
2089 | 0 | this->Makefile->IsOn( |
2090 | 0 | cmStrCat("CMAKE_", lang, "_LINK_WITH_STANDARD_COMPILE_OPTION")))) { |
2091 | 0 | cmStandardLevelResolver standardResolver(this->Makefile); |
2092 | 0 | std::string const& optionFlagDef = |
2093 | 0 | standardResolver.GetCompileOptionDef(target, lang, config); |
2094 | 0 | if (!optionFlagDef.empty()) { |
2095 | 0 | cmValue opt = |
2096 | 0 | target->Target->GetMakefile()->GetDefinition(optionFlagDef); |
2097 | 0 | if (opt) { |
2098 | 0 | cmList optList{ *opt }; |
2099 | 0 | for (std::string const& i : optList) { |
2100 | 0 | this->AppendFlagEscape(flags, i); |
2101 | 0 | } |
2102 | 0 | } |
2103 | 0 | } |
2104 | 0 | } |
2105 | |
|
2106 | 0 | std::string compilerId = this->Makefile->GetSafeDefinition( |
2107 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_ID")); |
2108 | |
|
2109 | 0 | std::string compilerSimulateId = this->Makefile->GetSafeDefinition( |
2110 | 0 | cmStrCat("CMAKE_", lang, "_SIMULATE_ID")); |
2111 | |
|
2112 | 0 | bool const compilerTargetsMsvcABI = |
2113 | 0 | (compilerId == "MSVC" || compilerSimulateId == "MSVC"); |
2114 | 0 | bool const compilerTargetsWatcomABI = |
2115 | 0 | (compilerId == "OpenWatcom" || compilerSimulateId == "OpenWatcom"); |
2116 | |
|
2117 | 0 | if (lang == "Swift") { |
2118 | 0 | if (cmValue v = target->GetProperty("Swift_LANGUAGE_VERSION")) { |
2119 | 0 | if (cmSystemTools::VersionCompare( |
2120 | 0 | cmSystemTools::OP_GREATER_EQUAL, |
2121 | 0 | this->Makefile->GetDefinition("CMAKE_Swift_COMPILER_VERSION"), |
2122 | 0 | "4.2")) { |
2123 | 0 | this->AppendFlags(flags, "-swift-version " + *v); |
2124 | 0 | } |
2125 | 0 | } |
2126 | 0 | } else if (lang == "CUDA") { |
2127 | 0 | target->AddCUDAArchitectureFlags(compileOrLink, config, flags); |
2128 | 0 | target->AddCUDAToolkitFlags(flags); |
2129 | 0 | } else if (lang == "ISPC") { |
2130 | 0 | target->AddISPCTargetFlags(flags); |
2131 | 0 | } else if (lang == "RC" && |
2132 | 0 | this->Makefile->GetSafeDefinition("CMAKE_RC_COMPILER") |
2133 | 0 | .find("llvm-rc") != std::string::npos) { |
2134 | 0 | compilerId = this->Makefile->GetSafeDefinition("CMAKE_C_COMPILER_ID"); |
2135 | 0 | if (!compilerId.empty()) { |
2136 | 0 | compilerSimulateId = |
2137 | 0 | this->Makefile->GetSafeDefinition("CMAKE_C_SIMULATE_ID"); |
2138 | 0 | } else { |
2139 | 0 | compilerId = this->Makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"); |
2140 | 0 | compilerSimulateId = |
2141 | 0 | this->Makefile->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID"); |
2142 | 0 | } |
2143 | 0 | } else if (lang == "HIP") { |
2144 | 0 | target->AddHIPArchitectureFlags(compileOrLink, config, flags); |
2145 | 0 | } else if (lang == "Rust") { |
2146 | 0 | target->AddRustTargetFlags(flags); |
2147 | 0 | } |
2148 | | |
2149 | | // Add VFS Overlay for Clang compilers |
2150 | 0 | if (compilerId == "Clang") { |
2151 | 0 | if (cmValue vfsOverlay = |
2152 | 0 | this->Makefile->GetDefinition("CMAKE_CLANG_VFS_OVERLAY")) { |
2153 | 0 | if (compilerSimulateId == "MSVC") { |
2154 | 0 | this->AppendCompileOptions( |
2155 | 0 | flags, |
2156 | 0 | std::vector<std::string>{ "-Xclang", "-ivfsoverlay", "-Xclang", |
2157 | 0 | *vfsOverlay }); |
2158 | 0 | } else { |
2159 | 0 | this->AppendCompileOptions( |
2160 | 0 | flags, std::vector<std::string>{ "-ivfsoverlay", *vfsOverlay }); |
2161 | 0 | } |
2162 | 0 | } |
2163 | 0 | } |
2164 | | // Add MSVC runtime library flags. This is activated by the presence |
2165 | | // of a default selection whether or not it is overridden by a property. |
2166 | 0 | cmValue msvcRuntimeLibraryDefault = |
2167 | 0 | this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT"); |
2168 | 0 | if (cmNonempty(msvcRuntimeLibraryDefault)) { |
2169 | 0 | cmValue msvcRuntimeLibraryValue = |
2170 | 0 | target->GetProperty("MSVC_RUNTIME_LIBRARY"); |
2171 | 0 | if (!msvcRuntimeLibraryValue) { |
2172 | 0 | msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault; |
2173 | 0 | } |
2174 | 0 | std::string const msvcRuntimeLibrary = cmGeneratorExpression::Evaluate( |
2175 | 0 | *msvcRuntimeLibraryValue, this, config, target); |
2176 | 0 | if (!msvcRuntimeLibrary.empty()) { |
2177 | 0 | if (cmValue msvcRuntimeLibraryOptions = this->Makefile->GetDefinition( |
2178 | 0 | "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" + |
2179 | 0 | msvcRuntimeLibrary)) { |
2180 | 0 | this->AppendCompileOptions(flags, *msvcRuntimeLibraryOptions); |
2181 | 0 | } else if (compilerTargetsMsvcABI && |
2182 | 0 | !cmSystemTools::GetErrorOccurredFlag()) { |
2183 | | // The compiler uses the MSVC ABI so it needs a known runtime library. |
2184 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
2185 | 0 | "MSVC_RUNTIME_LIBRARY value '" + |
2186 | 0 | msvcRuntimeLibrary + "' not known for this " + |
2187 | 0 | lang + " compiler."); |
2188 | 0 | } |
2189 | 0 | } |
2190 | 0 | } |
2191 | | |
2192 | | // Add Watcom runtime library flags. This is activated by the presence |
2193 | | // of a default selection whether or not it is overridden by a property. |
2194 | 0 | cmValue watcomRuntimeLibraryDefault = |
2195 | 0 | this->Makefile->GetDefinition("CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT"); |
2196 | 0 | if (cmNonempty(watcomRuntimeLibraryDefault)) { |
2197 | 0 | cmValue watcomRuntimeLibraryValue = |
2198 | 0 | target->GetProperty("WATCOM_RUNTIME_LIBRARY"); |
2199 | 0 | if (!watcomRuntimeLibraryValue) { |
2200 | 0 | watcomRuntimeLibraryValue = watcomRuntimeLibraryDefault; |
2201 | 0 | } |
2202 | 0 | std::string const watcomRuntimeLibrary = cmGeneratorExpression::Evaluate( |
2203 | 0 | *watcomRuntimeLibraryValue, this, config, target); |
2204 | 0 | if (!watcomRuntimeLibrary.empty()) { |
2205 | 0 | if (cmValue watcomRuntimeLibraryOptions = this->Makefile->GetDefinition( |
2206 | 0 | "CMAKE_" + lang + "_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_" + |
2207 | 0 | watcomRuntimeLibrary)) { |
2208 | 0 | this->AppendCompileOptions(flags, *watcomRuntimeLibraryOptions); |
2209 | 0 | } else if (compilerTargetsWatcomABI && |
2210 | 0 | !cmSystemTools::GetErrorOccurredFlag()) { |
2211 | | // The compiler uses the Watcom ABI so it needs a known runtime |
2212 | | // library. |
2213 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
2214 | 0 | "WATCOM_RUNTIME_LIBRARY value '" + |
2215 | 0 | watcomRuntimeLibrary + "' not known for this " + |
2216 | 0 | lang + " compiler."); |
2217 | 0 | } |
2218 | 0 | } |
2219 | 0 | } |
2220 | | |
2221 | | // Add MSVC runtime checks flags. This is activated by the presence |
2222 | | // of a default selection whether or not it is overridden by a property. |
2223 | 0 | cmValue msvcRuntimeChecksDefault = |
2224 | 0 | this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT"); |
2225 | 0 | if (cmNonempty(msvcRuntimeChecksDefault)) { |
2226 | 0 | cmValue msvcRuntimeChecksValue = |
2227 | 0 | target->GetProperty("MSVC_RUNTIME_CHECKS"); |
2228 | 0 | if (!msvcRuntimeChecksValue) { |
2229 | 0 | msvcRuntimeChecksValue = msvcRuntimeChecksDefault; |
2230 | 0 | } |
2231 | 0 | cmList msvcRuntimeChecksList = cmGeneratorExpression::Evaluate( |
2232 | 0 | *msvcRuntimeChecksValue, this, config, target); |
2233 | 0 | msvcRuntimeChecksList.remove_duplicates(); |
2234 | | |
2235 | | // RTC1/RTCsu VS GUI workaround |
2236 | 0 | std::string const stackFrameErrorCheck = "StackFrameErrorCheck"; |
2237 | 0 | std::string const unitinitializedVariable = "UninitializedVariable"; |
2238 | 0 | std::string const rtcSU = "RTCsu"; |
2239 | 0 | if ((cm::contains(msvcRuntimeChecksList, stackFrameErrorCheck) && |
2240 | 0 | cm::contains(msvcRuntimeChecksList, unitinitializedVariable)) || |
2241 | 0 | cm::contains(msvcRuntimeChecksList, rtcSU)) { |
2242 | 0 | msvcRuntimeChecksList.remove_items( |
2243 | 0 | { stackFrameErrorCheck, unitinitializedVariable, rtcSU }); |
2244 | 0 | msvcRuntimeChecksList.append(rtcSU); |
2245 | 0 | } |
2246 | |
|
2247 | 0 | for (std::string const& msvcRuntimeChecks : msvcRuntimeChecksList) { |
2248 | 0 | if (cmValue msvcRuntimeChecksOptions = |
2249 | 0 | this->Makefile->GetDefinition(cmStrCat( |
2250 | 0 | "CMAKE_", lang, |
2251 | 0 | "_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_" + msvcRuntimeChecks))) { |
2252 | 0 | this->AppendCompileOptions(flags, *msvcRuntimeChecksOptions); |
2253 | 0 | } else if (compilerTargetsMsvcABI && |
2254 | 0 | !cmSystemTools::GetErrorOccurredFlag()) { |
2255 | | // The compiler uses the MSVC ABI so it needs a known runtime checks. |
2256 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
2257 | 0 | cmStrCat("MSVC_RUNTIME_CHECKS value '", |
2258 | 0 | msvcRuntimeChecks, "' not known for this ", |
2259 | 0 | lang, " compiler.")); |
2260 | 0 | } |
2261 | 0 | } |
2262 | 0 | } |
2263 | | |
2264 | | // Add MSVC debug information format flags if CMP0141 is NEW. |
2265 | 0 | if (cm::optional<std::string> msvcDebugInformationFormat = |
2266 | 0 | this->GetMSVCDebugFormatName(config, target)) { |
2267 | 0 | if (!msvcDebugInformationFormat->empty()) { |
2268 | 0 | if (cmValue msvcDebugInformationFormatOptions = |
2269 | 0 | this->Makefile->GetDefinition( |
2270 | 0 | cmStrCat("CMAKE_", lang, |
2271 | 0 | "_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_", |
2272 | 0 | *msvcDebugInformationFormat))) { |
2273 | 0 | this->AppendCompileOptions(flags, *msvcDebugInformationFormatOptions); |
2274 | 0 | } else if (compilerTargetsMsvcABI && |
2275 | 0 | !cmSystemTools::GetErrorOccurredFlag()) { |
2276 | | // The compiler uses the MSVC ABI so it needs a known runtime library. |
2277 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
2278 | 0 | cmStrCat("MSVC_DEBUG_INFORMATION_FORMAT value '", |
2279 | 0 | *msvcDebugInformationFormat, |
2280 | 0 | "' not known for this ", lang, |
2281 | 0 | " compiler.")); |
2282 | 0 | } |
2283 | 0 | } |
2284 | 0 | } |
2285 | 0 | } |
2286 | | |
2287 | | void cmLocalGenerator::AddLanguageFlagsForLinking( |
2288 | | std::string& flags, cmGeneratorTarget const* target, std::string const& lang, |
2289 | | std::string const& config) |
2290 | 0 | { |
2291 | 0 | this->AddLanguageFlags(flags, target, cmBuildStep::Link, lang, config); |
2292 | |
|
2293 | 0 | if (target->IsIPOEnabled(lang, config)) { |
2294 | 0 | this->AppendFeatureOptions(flags, lang, "IPO"); |
2295 | 0 | } |
2296 | 0 | } |
2297 | | |
2298 | | cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse( |
2299 | | std::string const& name) const |
2300 | 0 | { |
2301 | 0 | auto imported = this->ImportedGeneratorTargets.find(name); |
2302 | 0 | if (imported != this->ImportedGeneratorTargets.end()) { |
2303 | 0 | return imported->second; |
2304 | 0 | } |
2305 | | |
2306 | | // find local alias to imported target |
2307 | 0 | auto aliased = this->AliasTargets.find(name); |
2308 | 0 | if (aliased != this->AliasTargets.end()) { |
2309 | 0 | imported = this->ImportedGeneratorTargets.find(aliased->second); |
2310 | 0 | if (imported != this->ImportedGeneratorTargets.end()) { |
2311 | 0 | return imported->second; |
2312 | 0 | } |
2313 | 0 | } |
2314 | | |
2315 | 0 | if (cmGeneratorTarget* t = this->FindLocalNonAliasGeneratorTarget(name)) { |
2316 | 0 | return t; |
2317 | 0 | } |
2318 | | |
2319 | 0 | return this->GetGlobalGenerator()->FindGeneratorTarget(name); |
2320 | 0 | } |
2321 | | |
2322 | | bool cmLocalGenerator::GetRealDependency(std::string const& inName, |
2323 | | std::string const& config, |
2324 | | std::string& dep, |
2325 | | cmPolicies::PolicyStatus cmp0212) |
2326 | 0 | { |
2327 | | // Older CMake code may specify the dependency using the target |
2328 | | // output file rather than the target name. Such code would have |
2329 | | // been written before there was support for target properties that |
2330 | | // modify the name so stripping down to just the file name should |
2331 | | // produce the target name in this case. |
2332 | 0 | std::string name = cmSystemTools::GetFilenameName(inName); |
2333 | | |
2334 | | // If the input name is the empty string, there is no real |
2335 | | // dependency. Short-circuit the other checks: |
2336 | 0 | if (name.empty()) { |
2337 | 0 | return false; |
2338 | 0 | } |
2339 | | |
2340 | | // Look for a CMake target with the given name. |
2341 | 0 | cmGeneratorTarget* target = this->FindGeneratorTargetToUse(name); |
2342 | 0 | if (!target && cmHasSuffix(name, ".exe"_s) && cmp0212 != cmPolicies::NEW) { |
2343 | | // If it doesn't exist, try to strip the `.exe` suffix per CMP0212. |
2344 | 0 | std::string strippedName = |
2345 | 0 | cmSystemTools::GetFilenameWithoutLastExtension(name); |
2346 | 0 | if (cmGeneratorTarget* strippedTarget = |
2347 | 0 | this->FindGeneratorTargetToUse(strippedName)) { |
2348 | 0 | name = strippedName; |
2349 | 0 | target = strippedTarget; |
2350 | 0 | } |
2351 | 0 | } |
2352 | |
|
2353 | 0 | if (target) { |
2354 | | // make sure it is not just a coincidence that the target name |
2355 | | // found is part of the inName |
2356 | 0 | if (cmSystemTools::FileIsFullPath(inName)) { |
2357 | 0 | std::string tLocation; |
2358 | 0 | if (target->GetType() >= cmStateEnums::EXECUTABLE && |
2359 | 0 | target->GetType() <= cmStateEnums::MODULE_LIBRARY) { |
2360 | 0 | tLocation = target->GetLocation(config); |
2361 | 0 | tLocation = cmSystemTools::GetFilenamePath(tLocation); |
2362 | 0 | tLocation = cmSystemTools::CollapseFullPath(tLocation); |
2363 | 0 | } |
2364 | 0 | std::string depLocation = |
2365 | 0 | cmSystemTools::GetFilenamePath(std::string(inName)); |
2366 | 0 | depLocation = cmSystemTools::CollapseFullPath(depLocation); |
2367 | 0 | if (depLocation != tLocation) { |
2368 | | // it is a full path to a depend that has the same name |
2369 | | // as a target but is in a different location so do not use |
2370 | | // the target as the depend |
2371 | 0 | dep = inName; |
2372 | 0 | return true; |
2373 | 0 | } |
2374 | 0 | } |
2375 | 0 | switch (target->GetType()) { |
2376 | 0 | case cmStateEnums::EXECUTABLE: |
2377 | 0 | case cmStateEnums::STATIC_LIBRARY: |
2378 | 0 | case cmStateEnums::SHARED_LIBRARY: |
2379 | 0 | case cmStateEnums::MODULE_LIBRARY: |
2380 | 0 | case cmStateEnums::UNKNOWN_LIBRARY: |
2381 | 0 | dep = target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, |
2382 | 0 | /*realname=*/true); |
2383 | 0 | return true; |
2384 | 0 | case cmStateEnums::OBJECT_LIBRARY: |
2385 | | // An object library has no single file on which to depend. |
2386 | | // This was listed to get the target-level dependency. |
2387 | 0 | case cmStateEnums::INTERFACE_LIBRARY: |
2388 | | // An interface library has no file on which to depend. |
2389 | | // This was listed to get the target-level dependency. |
2390 | 0 | case cmStateEnums::UTILITY: |
2391 | 0 | case cmStateEnums::GLOBAL_TARGET: |
2392 | | // A utility target has no file on which to depend. This was listed |
2393 | | // only to get the target-level dependency. |
2394 | 0 | return false; |
2395 | 0 | } |
2396 | 0 | } |
2397 | | |
2398 | | // The name was not that of a CMake target. It must name a file. |
2399 | 0 | if (cmSystemTools::FileIsFullPath(inName)) { |
2400 | | // This is a full path. Return it as given. |
2401 | 0 | dep = inName; |
2402 | 0 | return true; |
2403 | 0 | } |
2404 | | |
2405 | | // Check for a source file in this directory that matches the |
2406 | | // dependency. |
2407 | 0 | if (cmSourceFile* sf = this->Makefile->GetSource(inName)) { |
2408 | 0 | dep = sf->ResolveFullPath(); |
2409 | 0 | return true; |
2410 | 0 | } |
2411 | | |
2412 | | // Treat the name as relative to the source directory in which it |
2413 | | // was given. |
2414 | 0 | dep = cmStrCat(this->GetCurrentSourceDirectory(), '/', inName); |
2415 | | |
2416 | | // If the in-source path does not exist, assume it instead lives in the |
2417 | | // binary directory. |
2418 | 0 | if (!cmSystemTools::FileExists(dep)) { |
2419 | 0 | dep = cmStrCat(this->GetCurrentBinaryDirectory(), '/', inName); |
2420 | 0 | } |
2421 | |
|
2422 | 0 | dep = cmSystemTools::CollapseFullPath(dep); |
2423 | |
|
2424 | 0 | return true; |
2425 | 0 | } |
2426 | | |
2427 | | static void AddVisibilityCompileOption(std::string& flags, |
2428 | | cmGeneratorTarget const* target, |
2429 | | cmLocalGenerator* lg, |
2430 | | std::string const& lang) |
2431 | 0 | { |
2432 | 0 | std::string compileOption = "CMAKE_" + lang + "_COMPILE_OPTIONS_VISIBILITY"; |
2433 | 0 | cmValue opt = lg->GetMakefile()->GetDefinition(compileOption); |
2434 | 0 | if (!opt) { |
2435 | 0 | return; |
2436 | 0 | } |
2437 | 0 | std::string flagDefine = lang + "_VISIBILITY_PRESET"; |
2438 | |
|
2439 | 0 | cmValue prop = target->GetProperty(flagDefine); |
2440 | 0 | if (!prop) { |
2441 | 0 | return; |
2442 | 0 | } |
2443 | 0 | if ((*prop != "hidden") && (*prop != "default") && (*prop != "protected") && |
2444 | 0 | (*prop != "internal")) { |
2445 | 0 | std::ostringstream e; |
2446 | 0 | e << "Target " << target->GetName() << " uses unsupported value \"" |
2447 | 0 | << *prop << "\" for " << flagDefine << "." |
2448 | 0 | << " The supported values are: default, hidden, protected, and " |
2449 | 0 | "internal."; |
2450 | 0 | cmSystemTools::Error(e.str()); |
2451 | 0 | return; |
2452 | 0 | } |
2453 | 0 | std::string option = *opt + *prop; |
2454 | 0 | lg->AppendFlags(flags, option); |
2455 | 0 | } |
2456 | | |
2457 | | static void AddInlineVisibilityCompileOption(std::string& flags, |
2458 | | cmGeneratorTarget const* target, |
2459 | | cmLocalGenerator* lg, |
2460 | | std::string const& lang) |
2461 | 0 | { |
2462 | 0 | std::string compileOption = |
2463 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN"); |
2464 | 0 | cmValue opt = lg->GetMakefile()->GetDefinition(compileOption); |
2465 | 0 | if (!opt) { |
2466 | 0 | return; |
2467 | 0 | } |
2468 | | |
2469 | 0 | bool prop = target->GetPropertyAsBool("VISIBILITY_INLINES_HIDDEN"); |
2470 | 0 | if (!prop) { |
2471 | 0 | return; |
2472 | 0 | } |
2473 | 0 | lg->AppendFlags(flags, *opt); |
2474 | 0 | } |
2475 | | |
2476 | | void cmLocalGenerator::AddVisibilityPresetFlags( |
2477 | | std::string& flags, cmGeneratorTarget const* target, std::string const& lang) |
2478 | 0 | { |
2479 | 0 | if (lang.empty()) { |
2480 | 0 | return; |
2481 | 0 | } |
2482 | | |
2483 | 0 | AddVisibilityCompileOption(flags, target, this, lang); |
2484 | |
|
2485 | 0 | if (lang == "CXX" || lang == "OBJCXX") { |
2486 | 0 | AddInlineVisibilityCompileOption(flags, target, this, lang); |
2487 | 0 | } |
2488 | 0 | } |
2489 | | |
2490 | | void cmLocalGenerator::AddFeatureFlags(std::string& flags, |
2491 | | cmGeneratorTarget const* target, |
2492 | | std::string const& lang, |
2493 | | std::string const& config) |
2494 | 0 | { |
2495 | 0 | int targetType = target->GetType(); |
2496 | |
|
2497 | 0 | bool shared = ((targetType == cmStateEnums::SHARED_LIBRARY) || |
2498 | 0 | (targetType == cmStateEnums::MODULE_LIBRARY)); |
2499 | |
|
2500 | 0 | if (target->GetLinkInterfaceDependentBoolProperty( |
2501 | 0 | "POSITION_INDEPENDENT_CODE", config)) { |
2502 | 0 | this->AddPositionIndependentFlags(flags, lang, targetType); |
2503 | 0 | } |
2504 | 0 | if (shared) { |
2505 | 0 | this->AppendFeatureOptions(flags, lang, "DLL"); |
2506 | 0 | } |
2507 | 0 | } |
2508 | | |
2509 | | void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, |
2510 | | std::string const& lang, |
2511 | | int targetType) |
2512 | 0 | { |
2513 | 0 | std::string picFlags; |
2514 | |
|
2515 | 0 | if (targetType == cmStateEnums::EXECUTABLE) { |
2516 | 0 | picFlags = this->Makefile->GetSafeDefinition( |
2517 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIE")); |
2518 | 0 | } |
2519 | 0 | if (picFlags.empty()) { |
2520 | 0 | picFlags = this->Makefile->GetSafeDefinition( |
2521 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIC")); |
2522 | 0 | } |
2523 | 0 | if (!picFlags.empty()) { |
2524 | 0 | cmList options{ picFlags }; |
2525 | 0 | for (std::string const& o : options) { |
2526 | 0 | this->AppendFlagEscape(flags, o); |
2527 | 0 | } |
2528 | 0 | } |
2529 | 0 | } |
2530 | | |
2531 | | void cmLocalGenerator::AddColorDiagnosticsFlags(std::string& flags, |
2532 | | std::string const& lang) |
2533 | 0 | { |
2534 | 0 | cmValue diag = this->Makefile->GetDefinition("CMAKE_COLOR_DIAGNOSTICS"); |
2535 | 0 | if (diag.IsSet()) { |
2536 | 0 | std::string colorFlagName; |
2537 | 0 | if (diag.IsOn()) { |
2538 | 0 | colorFlagName = |
2539 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_COLOR_DIAGNOSTICS"); |
2540 | 0 | } else { |
2541 | 0 | colorFlagName = |
2542 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_COLOR_DIAGNOSTICS_OFF"); |
2543 | 0 | } |
2544 | |
|
2545 | 0 | cmList options{ this->Makefile->GetDefinition(colorFlagName) }; |
2546 | |
|
2547 | 0 | for (auto const& option : options) { |
2548 | 0 | this->AppendFlagEscape(flags, option); |
2549 | 0 | } |
2550 | 0 | } |
2551 | 0 | } |
2552 | | |
2553 | | void cmLocalGenerator::AddConfigVariableFlags(std::string& flags, |
2554 | | std::string const& var, |
2555 | | std::string const& config) |
2556 | 0 | { |
2557 | | // Add the flags from the variable itself. |
2558 | 0 | this->AppendFlags(flags, this->Makefile->GetSafeDefinition(var)); |
2559 | | // Add the flags from the build-type specific variable. |
2560 | 0 | if (!config.empty()) { |
2561 | 0 | std::string const flagsVar = |
2562 | 0 | cmStrCat(var, '_', cmSystemTools::UpperCase(config)); |
2563 | 0 | this->AppendFlags(flags, this->Makefile->GetSafeDefinition(flagsVar)); |
2564 | 0 | } |
2565 | 0 | } |
2566 | | void cmLocalGenerator::AddConfigVariableFlags(std::string& flags, |
2567 | | std::string const& var, |
2568 | | cmGeneratorTarget const* target, |
2569 | | cmBuildStep compileOrLink, |
2570 | | std::string const& lang, |
2571 | | std::string const& config) |
2572 | 0 | { |
2573 | 0 | std::string newFlags; |
2574 | 0 | this->AddConfigVariableFlags(newFlags, var, config); |
2575 | 0 | if (!newFlags.empty()) { |
2576 | 0 | this->AppendFlags(flags, newFlags, var, target, compileOrLink, lang); |
2577 | 0 | } |
2578 | 0 | } |
2579 | | |
2580 | | void cmLocalGenerator::AppendFlags(std::string& flags, |
2581 | | std::string const& newFlags) const |
2582 | 0 | { |
2583 | 0 | bool allSpaces = |
2584 | 0 | std::all_of(newFlags.begin(), newFlags.end(), cmsysString_isspace); |
2585 | |
|
2586 | 0 | if (!newFlags.empty() && !allSpaces) { |
2587 | 0 | if (!flags.empty()) { |
2588 | 0 | flags += " "; |
2589 | 0 | } |
2590 | 0 | flags += newFlags; |
2591 | 0 | } |
2592 | 0 | } |
2593 | | |
2594 | | void cmLocalGenerator::AppendFlags( |
2595 | | std::string& flags, std::vector<BT<std::string>> const& newFlags) const |
2596 | 0 | { |
2597 | 0 | for (BT<std::string> const& flag : newFlags) { |
2598 | 0 | this->AppendFlags(flags, flag.Value); |
2599 | 0 | } |
2600 | 0 | } |
2601 | | |
2602 | | void cmLocalGenerator::AppendFlagEscape(std::string& flags, |
2603 | | std::string const& rawFlag) const |
2604 | 0 | { |
2605 | 0 | this->AppendFlags( |
2606 | 0 | flags, |
2607 | 0 | this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti())); |
2608 | 0 | } |
2609 | | |
2610 | | void cmLocalGenerator::AppendLinkFlagsWithParsing( |
2611 | | std::string& flags, std::string const& newFlags, |
2612 | | cmGeneratorTarget const* target, std::string const& language) |
2613 | 0 | { |
2614 | 0 | std::vector<std::string> options; |
2615 | 0 | cmSystemTools::ParseUnixCommandLine(newFlags.c_str(), options); |
2616 | 0 | this->SetLinkScriptShell(this->GlobalGenerator->GetUseLinkScript()); |
2617 | 0 | std::vector<BT<std::string>> optionsWithBT{ options.size() }; |
2618 | 0 | std::transform(options.cbegin(), options.cend(), optionsWithBT.begin(), |
2619 | 0 | [](std::string const& item) -> BT<std::string> { |
2620 | 0 | return BT<std::string>{ item }; |
2621 | 0 | }); |
2622 | 0 | target->ResolveLinkerWrapper(optionsWithBT, language); |
2623 | 0 | for (auto const& item : optionsWithBT) { |
2624 | 0 | this->AppendFlagEscape(flags, item.Value); |
2625 | 0 | } |
2626 | 0 | this->SetLinkScriptShell(false); |
2627 | 0 | } |
2628 | | |
2629 | | void cmLocalGenerator::AppendFlags(std::string& flags, |
2630 | | std::string const& newFlags, |
2631 | | std::string const& name, |
2632 | | cmGeneratorTarget const* target, |
2633 | | cmBuildStep compileOrLink, |
2634 | | std::string const& language) |
2635 | 0 | { |
2636 | 0 | switch (target->GetPolicyStatusCMP0181()) { |
2637 | 0 | case cmPolicies::WARN: |
2638 | 0 | if (!this->Makefile->GetCMakeInstance()->GetIsInTryCompile() && |
2639 | 0 | this->Makefile->PolicyOptionalWarningEnabled( |
2640 | 0 | "CMAKE_POLICY_WARNING_CMP0181")) { |
2641 | 0 | this->Makefile->IssueDiagnostic( |
2642 | 0 | cmDiagnostics::CMD_AUTHOR, |
2643 | 0 | cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0181), |
2644 | 0 | "\nSince the policy is not set, the contents of variable '", |
2645 | 0 | name, |
2646 | 0 | "' will " |
2647 | 0 | "be used as is."), |
2648 | 0 | target->GetBacktrace()); |
2649 | 0 | } |
2650 | 0 | CM_FALLTHROUGH; |
2651 | 0 | case cmPolicies::OLD: |
2652 | 0 | this->AppendFlags( |
2653 | 0 | flags, this->GetGlobalGenerator()->GetEncodedLiteral(newFlags)); |
2654 | 0 | break; |
2655 | 0 | case cmPolicies::NEW: |
2656 | 0 | if (compileOrLink == cmBuildStep::Link) { |
2657 | 0 | this->AppendLinkFlagsWithParsing(flags, newFlags, target, language); |
2658 | 0 | } else { |
2659 | 0 | this->AppendFlags(flags, newFlags); |
2660 | 0 | } |
2661 | 0 | } |
2662 | 0 | } |
2663 | | |
2664 | | void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target) |
2665 | 0 | { |
2666 | 0 | std::vector<std::string> enabledLanguages = |
2667 | 0 | this->GetState()->GetEnabledLanguages(); |
2668 | 0 | if (std::find(enabledLanguages.begin(), enabledLanguages.end(), "ISPC") == |
2669 | 0 | enabledLanguages.end()) { |
2670 | 0 | return; |
2671 | 0 | } |
2672 | | |
2673 | 0 | cmValue ispcHeaderSuffixProp = target->GetProperty("ISPC_HEADER_SUFFIX"); |
2674 | 0 | assert(ispcHeaderSuffixProp); |
2675 | |
|
2676 | 0 | std::vector<std::string> ispcArchSuffixes = |
2677 | 0 | detail::ComputeISPCObjectSuffixes(target); |
2678 | 0 | bool const extra_objects = (ispcArchSuffixes.size() > 1); |
2679 | |
|
2680 | 0 | std::vector<std::string> configsList = |
2681 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
2682 | 0 | for (std::string const& config : configsList) { |
2683 | |
|
2684 | 0 | std::string rootObjectDir = target->GetObjectDirectory(config); |
2685 | 0 | std::string headerDir = rootObjectDir; |
2686 | 0 | if (cmValue prop = target->GetProperty("ISPC_HEADER_DIRECTORY")) { |
2687 | 0 | headerDir = cmSystemTools::CollapseFullPath( |
2688 | 0 | cmStrCat(this->GetBinaryDirectory(), '/', *prop)); |
2689 | 0 | } |
2690 | |
|
2691 | 0 | std::vector<cmSourceFile*> sources; |
2692 | 0 | target->GetSourceFiles(sources, config); |
2693 | | |
2694 | | // build up the list of ispc headers and extra objects that this target is |
2695 | | // generating |
2696 | 0 | for (cmSourceFile const* sf : sources) { |
2697 | | // Generate this object file's rule file. |
2698 | 0 | std::string const& lang = sf->GetLanguage(); |
2699 | 0 | if (lang == "ISPC") { |
2700 | 0 | std::string const& objectName = target->GetObjectName(sf); |
2701 | | |
2702 | | // Drop both ".obj" and the source file extension |
2703 | 0 | std::string ispcSource = |
2704 | 0 | cmSystemTools::GetFilenameWithoutLastExtension(objectName); |
2705 | 0 | ispcSource = |
2706 | 0 | cmSystemTools::GetFilenameWithoutLastExtension(ispcSource); |
2707 | |
|
2708 | 0 | auto headerPath = |
2709 | 0 | cmStrCat(headerDir, '/', ispcSource, *ispcHeaderSuffixProp); |
2710 | 0 | target->AddISPCGeneratedHeader(headerPath, config); |
2711 | 0 | if (extra_objects) { |
2712 | 0 | std::vector<std::pair<cmSourceFile const*, std::string>> objs; |
2713 | 0 | for (auto& obj : detail::ComputeISPCExtraObjects( |
2714 | 0 | objectName, rootObjectDir, ispcArchSuffixes)) { |
2715 | 0 | objs.push_back({ sf, std::move(obj) }); |
2716 | 0 | } |
2717 | 0 | target->AddISPCGeneratedObject(std::move(objs), config); |
2718 | 0 | } |
2719 | 0 | } |
2720 | 0 | } |
2721 | 0 | } |
2722 | 0 | } |
2723 | | |
2724 | | void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) |
2725 | 0 | { |
2726 | 0 | std::vector<std::string> configsList = |
2727 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
2728 | |
|
2729 | 0 | for (std::string const& config : configsList) { |
2730 | | // FIXME: Refactor collection of sources to not evaluate object |
2731 | | // libraries. |
2732 | 0 | std::vector<cmSourceFile*> sources; |
2733 | 0 | target->GetSourceFiles(sources, config); |
2734 | |
|
2735 | 0 | std::string const configUpper = cmSystemTools::UpperCase(config); |
2736 | 0 | static std::array<std::string, 4> const langs = { { "C", "CXX", "OBJC", |
2737 | 0 | "OBJCXX" } }; |
2738 | |
|
2739 | 0 | std::set<std::string> pchLangSet; |
2740 | 0 | if (this->GetGlobalGenerator()->IsXcode()) { |
2741 | 0 | for (std::string const& lang : langs) { |
2742 | 0 | std::string const pchHeader = target->GetPchHeader(config, lang, ""); |
2743 | 0 | if (!pchHeader.empty()) { |
2744 | 0 | pchLangSet.emplace(lang); |
2745 | 0 | } |
2746 | 0 | } |
2747 | 0 | } |
2748 | |
|
2749 | 0 | for (std::string const& lang : langs) { |
2750 | 0 | auto langSources = std::count_if( |
2751 | 0 | sources.begin(), sources.end(), [lang](cmSourceFile* sf) { |
2752 | 0 | return lang == sf->GetLanguage() && |
2753 | 0 | !sf->GetProperty("SKIP_PRECOMPILE_HEADERS"); |
2754 | 0 | }); |
2755 | 0 | if (langSources == 0) { |
2756 | 0 | continue; |
2757 | 0 | } |
2758 | | |
2759 | 0 | std::vector<std::string> pchArchs = target->GetPchArchs(config, lang); |
2760 | 0 | if (pchArchs.size() > 1) { |
2761 | 0 | std::string useMultiArchPch; |
2762 | 0 | for (std::string const& arch : pchArchs) { |
2763 | 0 | std::string const pchHeader = |
2764 | 0 | target->GetPchHeader(config, lang, arch); |
2765 | 0 | if (!pchHeader.empty()) { |
2766 | 0 | useMultiArchPch = cmStrCat(useMultiArchPch, ";-Xarch_", arch, |
2767 | 0 | ";-include", pchHeader); |
2768 | 0 | } |
2769 | 0 | } |
2770 | |
|
2771 | 0 | if (!useMultiArchPch.empty()) { |
2772 | |
|
2773 | 0 | target->Target->AppendProperty( |
2774 | 0 | cmStrCat(lang, "_COMPILE_OPTIONS_USE_PCH"), |
2775 | 0 | cmStrCat("$<$<CONFIG:", config, ">:", useMultiArchPch, '>')); |
2776 | 0 | } |
2777 | 0 | } |
2778 | |
|
2779 | 0 | for (std::string const& arch : pchArchs) { |
2780 | 0 | std::string const pchSource = target->GetPchSource(config, lang, arch); |
2781 | 0 | std::string const pchHeader = target->GetPchHeader(config, lang, arch); |
2782 | |
|
2783 | 0 | if (pchSource.empty() || pchHeader.empty()) { |
2784 | 0 | if (this->GetGlobalGenerator()->IsXcode() && !pchLangSet.empty()) { |
2785 | 0 | for (auto* sf : sources) { |
2786 | 0 | auto const sourceLanguage = sf->GetLanguage(); |
2787 | 0 | if (!sourceLanguage.empty() && |
2788 | 0 | pchLangSet.find(sourceLanguage) == pchLangSet.end()) { |
2789 | 0 | sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON"); |
2790 | 0 | } |
2791 | 0 | } |
2792 | 0 | } |
2793 | 0 | continue; |
2794 | 0 | } |
2795 | | |
2796 | 0 | cmValue pchExtension = |
2797 | 0 | this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION"); |
2798 | |
|
2799 | 0 | if (pchExtension.IsEmpty()) { |
2800 | 0 | continue; |
2801 | 0 | } |
2802 | | |
2803 | 0 | auto* reuseTarget = target->GetPchReuseTarget(); |
2804 | 0 | bool const haveReuseTarget = reuseTarget && reuseTarget != target; |
2805 | |
|
2806 | 0 | auto* pch_sf = this->Makefile->GetOrCreateSource( |
2807 | 0 | pchSource, false, cmSourceFileLocationKind::Known); |
2808 | 0 | pch_sf->SetSpecialSourceType( |
2809 | 0 | cmSourceFile::SpecialSourceType::PchSource); |
2810 | | // PCH sources should never be scanned as they cannot contain C++ |
2811 | | // module references. |
2812 | 0 | pch_sf->SetProperty("CXX_SCAN_FOR_MODULES", "0"); |
2813 | |
|
2814 | 0 | if (!this->GetGlobalGenerator()->IsXcode()) { |
2815 | 0 | if (!haveReuseTarget) { |
2816 | 0 | target->AddSource(pchSource, true); |
2817 | 0 | } |
2818 | |
|
2819 | 0 | std::string const pchFile = target->GetPchFile(config, lang, arch); |
2820 | | |
2821 | | // Exclude the pch files from linking |
2822 | 0 | if (this->Makefile->IsOn("CMAKE_LINK_PCH")) { |
2823 | 0 | if (!haveReuseTarget) { |
2824 | 0 | pch_sf->AppendProperty( |
2825 | 0 | "OBJECT_OUTPUTS", |
2826 | 0 | cmStrCat("$<$<CONFIG:", config, ">:", pchFile, '>')); |
2827 | 0 | } else { |
2828 | 0 | if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) { |
2829 | |
|
2830 | 0 | std::string const compilerId = |
2831 | 0 | this->Makefile->GetSafeDefinition( |
2832 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_ID")); |
2833 | |
|
2834 | 0 | std::string const compilerVersion = |
2835 | 0 | this->Makefile->GetSafeDefinition( |
2836 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_VERSION")); |
2837 | |
|
2838 | 0 | std::string const langFlags = |
2839 | 0 | this->Makefile->GetSafeDefinition( |
2840 | 0 | cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper)); |
2841 | |
|
2842 | 0 | bool editAndContinueDebugInfo = false; |
2843 | 0 | bool programDatabaseDebugInfo = false; |
2844 | 0 | cm::optional<std::string> msvcDebugInformationFormat = |
2845 | 0 | this->GetMSVCDebugFormatName(config, target); |
2846 | 0 | if (msvcDebugInformationFormat && |
2847 | 0 | !msvcDebugInformationFormat->empty()) { |
2848 | 0 | editAndContinueDebugInfo = |
2849 | 0 | *msvcDebugInformationFormat == "EditAndContinue"; |
2850 | 0 | programDatabaseDebugInfo = |
2851 | 0 | *msvcDebugInformationFormat == "ProgramDatabase"; |
2852 | 0 | } else { |
2853 | 0 | editAndContinueDebugInfo = |
2854 | 0 | langFlags.find("/ZI") != std::string::npos || |
2855 | 0 | langFlags.find("-ZI") != std::string::npos; |
2856 | 0 | programDatabaseDebugInfo = |
2857 | 0 | langFlags.find("/Zi") != std::string::npos || |
2858 | 0 | langFlags.find("-Zi") != std::string::npos; |
2859 | 0 | } |
2860 | |
|
2861 | 0 | if (editAndContinueDebugInfo) { |
2862 | 0 | this->CopyPchCompilePdb(config, lang, target, reuseTarget, |
2863 | 0 | { ".pdb", ".idb" }); |
2864 | 0 | } else if (programDatabaseDebugInfo) { |
2865 | 0 | this->CopyPchCompilePdb(config, lang, target, reuseTarget, |
2866 | 0 | { ".pdb" }); |
2867 | 0 | } |
2868 | 0 | } |
2869 | | |
2870 | | // Link to the pch object file |
2871 | 0 | std::string pchSourceObj; |
2872 | | // Fastbuild will propagate pch.obj for us, no need to link to it |
2873 | | // explicitly. |
2874 | 0 | if (!this->GetGlobalGenerator()->IsFastbuild()) { |
2875 | 0 | pchSourceObj = |
2876 | 0 | reuseTarget->GetPchFileObject(config, lang, arch); |
2877 | 0 | } |
2878 | |
|
2879 | 0 | if (target->GetType() != cmStateEnums::OBJECT_LIBRARY) { |
2880 | 0 | std::string linkerProperty = "LINK_FLAGS_"; |
2881 | 0 | if (target->GetType() == cmStateEnums::STATIC_LIBRARY) { |
2882 | 0 | linkerProperty = "STATIC_LIBRARY_FLAGS_"; |
2883 | 0 | } |
2884 | 0 | target->Target->AppendProperty( |
2885 | 0 | cmStrCat(linkerProperty, configUpper), |
2886 | 0 | cmStrCat(' ', |
2887 | 0 | this->ConvertToOutputFormat(pchSourceObj, SHELL)), |
2888 | 0 | cm::nullopt, true); |
2889 | 0 | } else if (reuseTarget->GetType() == |
2890 | 0 | cmStateEnums::OBJECT_LIBRARY) { |
2891 | 0 | target->Target->AppendProperty( |
2892 | 0 | "INTERFACE_LINK_LIBRARIES", |
2893 | 0 | cmStrCat("$<$<CONFIG:", config, |
2894 | 0 | ">:$<LINK_ONLY:", pchSourceObj, ">>")); |
2895 | 0 | } |
2896 | 0 | } |
2897 | 0 | } else { |
2898 | 0 | pch_sf->SetProperty("PCH_EXTENSION", pchExtension); |
2899 | 0 | } |
2900 | | |
2901 | | // Add pchHeader to source files, which will |
2902 | | // be grouped as "Precompile Header File" |
2903 | 0 | auto* pchHeader_sf = this->Makefile->GetOrCreateSource( |
2904 | 0 | pchHeader, false, cmSourceFileLocationKind::Known); |
2905 | 0 | pchHeader_sf->SetSpecialSourceType( |
2906 | 0 | cmSourceFile::SpecialSourceType::PchHeader); |
2907 | 0 | std::string err; |
2908 | 0 | pchHeader_sf->ResolveFullPath(&err); |
2909 | 0 | if (!err.empty()) { |
2910 | 0 | std::ostringstream msg; |
2911 | 0 | msg << "Unable to resolve full path of PCH-header '" << pchHeader |
2912 | 0 | << "' assigned to target " << target->GetName() |
2913 | 0 | << ", although its path is supposed to be known!"; |
2914 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, msg.str()); |
2915 | 0 | } |
2916 | 0 | target->AddSource(pchHeader); |
2917 | 0 | } |
2918 | 0 | } |
2919 | 0 | } |
2920 | 0 | } |
2921 | 0 | } |
2922 | | |
2923 | | void cmLocalGenerator::CopyPchCompilePdb( |
2924 | | std::string const& config, std::string const& language, |
2925 | | cmGeneratorTarget* target, cmGeneratorTarget* reuseTarget, |
2926 | | std::vector<std::string> const& extensions) |
2927 | 0 | { |
2928 | 0 | std::string const copy_script = cmStrCat(target->GetSupportDirectory(), |
2929 | 0 | "/copy_idb_pdb_", config, ".cmake"); |
2930 | 0 | cmGeneratedFileStream file(copy_script); |
2931 | 0 | file.SetCopyIfDifferent(true); |
2932 | |
|
2933 | 0 | file << "# CMake generated file\n"; |
2934 | |
|
2935 | 0 | file << "# The compiler generated pdb file needs to be written to disk\n" |
2936 | 0 | << "# by mspdbsrv. The foreach retry loop is needed to make sure\n" |
2937 | 0 | << "# the pdb file is ready to be copied.\n\n"; |
2938 | |
|
2939 | 0 | auto configGenex = [&](cm::string_view expr) -> std::string { |
2940 | 0 | if (this->GetGlobalGenerator()->IsMultiConfig()) { |
2941 | 0 | return cmStrCat("$<$<CONFIG:", config, ">:", expr, '>'); |
2942 | 0 | } |
2943 | 0 | return std::string(expr); |
2944 | 0 | }; |
2945 | |
|
2946 | 0 | std::vector<std::string> outputs; |
2947 | 0 | auto replaceExtension = [](std::string const& path, |
2948 | 0 | std::string const& ext) -> std::string { |
2949 | 0 | auto const dir = cmSystemTools::GetFilenamePath(path); |
2950 | 0 | auto const base = cmSystemTools::GetFilenameWithoutLastExtension(path); |
2951 | 0 | if (dir.empty()) { |
2952 | 0 | return cmStrCat(base, ext); |
2953 | 0 | } |
2954 | 0 | return cmStrCat(dir, '/', base, ext); |
2955 | 0 | }; |
2956 | 0 | for (auto const& extension : extensions) { |
2957 | 0 | std::string const from_file = |
2958 | 0 | replaceExtension(reuseTarget->GetCompilePDBPath(config), extension); |
2959 | 0 | std::string const to_dir = target->GetCompilePDBDirectory(config); |
2960 | 0 | std::string const to_file = |
2961 | 0 | replaceExtension(reuseTarget->GetCompilePDBName(config), extension); |
2962 | 0 | std::string const dest_file = cmStrCat(to_dir, '/', to_file); |
2963 | |
|
2964 | 0 | file << "foreach(retry RANGE 1 30)\n"; |
2965 | 0 | file << " if (EXISTS \"" << from_file << "\" AND (NOT EXISTS \"" |
2966 | 0 | << dest_file << "\" OR NOT \"" << dest_file << "\" IS_NEWER_THAN \"" |
2967 | 0 | << from_file << "\"))\n"; |
2968 | 0 | file << " file(MAKE_DIRECTORY \"" << to_dir << "\")\n"; |
2969 | 0 | file << " execute_process(COMMAND ${CMAKE_COMMAND} -E copy"; |
2970 | 0 | file << " \"" << from_file << "\"" << " \"" << to_dir |
2971 | 0 | << "\" RESULT_VARIABLE result " << " ERROR_QUIET)\n"; |
2972 | 0 | file << " if (NOT result EQUAL 0)\n" |
2973 | 0 | << " execute_process(COMMAND ${CMAKE_COMMAND}" |
2974 | 0 | << " -E sleep 1)\n" |
2975 | 0 | << " else()\n"; |
2976 | 0 | file << " break()\n" |
2977 | 0 | << " endif()\n"; |
2978 | 0 | file << " elseif(NOT EXISTS \"" << from_file << "\")\n" |
2979 | 0 | << " execute_process(COMMAND ${CMAKE_COMMAND}" << " -E sleep 1)\n" |
2980 | 0 | << " endif()\n"; |
2981 | 0 | file << "endforeach()\n"; |
2982 | 0 | outputs.push_back(configGenex(dest_file)); |
2983 | 0 | } |
2984 | |
|
2985 | 0 | cmCustomCommandLines commandLines = |
2986 | 0 | cmMakeSingleCommandLine({ configGenex(cmSystemTools::GetCMakeCommand()), |
2987 | 0 | configGenex("-P"), configGenex(copy_script) }); |
2988 | |
|
2989 | 0 | auto const comment = |
2990 | 0 | cmStrCat("Copying PDB for PCH reuse from ", reuseTarget->GetName(), |
2991 | 0 | " for ", target->GetName()); |
2992 | 0 | ; |
2993 | |
|
2994 | 0 | auto cc = cm::make_unique<cmCustomCommand>(); |
2995 | 0 | cc->SetCommandLines(commandLines); |
2996 | 0 | cc->SetComment(comment.c_str()); |
2997 | 0 | cc->SetStdPipesUTF8(true); |
2998 | 0 | cc->AppendDepends( |
2999 | 0 | { reuseTarget->GetPchFile(config, language), copy_script }); |
3000 | | // Fastbuild needs to know that this custom command actually depends on a |
3001 | | // target that produces PCH, so it can sort by dependencies correctly. |
3002 | 0 | if (this->GetGlobalGenerator()->IsFastbuild()) { |
3003 | 0 | cc->AppendDepends({ reuseTarget->GetName() }); |
3004 | 0 | } |
3005 | |
|
3006 | 0 | if (this->GetGlobalGenerator()->IsVisualStudio()) { |
3007 | 0 | cc->SetByproducts(outputs); |
3008 | 0 | this->AddCustomCommandToTarget( |
3009 | 0 | target->GetName(), cmCustomCommandType::PRE_BUILD, std::move(cc), |
3010 | 0 | cmObjectLibraryCommands::Accept); |
3011 | 0 | } else { |
3012 | 0 | cc->SetOutputs(outputs); |
3013 | 0 | cmSourceFile* copy_rule = this->AddCustomCommandToOutput(std::move(cc)); |
3014 | 0 | if (copy_rule) { |
3015 | 0 | copy_rule->SetProperty("CXX_SCAN_FOR_MODULES", "0"); |
3016 | 0 | auto* pch_pdb_sf = target->AddSource(copy_rule->ResolveFullPath()); |
3017 | 0 | pch_pdb_sf->SetSpecialSourceType( |
3018 | 0 | cmSourceFile::SpecialSourceType::PchPdbReuseSource); |
3019 | 0 | } |
3020 | 0 | } |
3021 | 0 | } |
3022 | | |
3023 | | cm::optional<std::string> cmLocalGenerator::GetMSVCDebugFormatName( |
3024 | | std::string const& config, cmGeneratorTarget const* target) |
3025 | 0 | { |
3026 | | // MSVC debug information format selection is activated by the presence |
3027 | | // of a default whether or not it is overridden by a property. |
3028 | 0 | cm::optional<std::string> msvcDebugInformationFormat; |
3029 | 0 | cmValue msvcDebugInformationFormatDefault = this->Makefile->GetDefinition( |
3030 | 0 | "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT"); |
3031 | 0 | if (cmNonempty(msvcDebugInformationFormatDefault)) { |
3032 | 0 | cmValue msvcDebugInformationFormatValue = |
3033 | 0 | target->GetProperty("MSVC_DEBUG_INFORMATION_FORMAT"); |
3034 | 0 | if (!msvcDebugInformationFormatValue) { |
3035 | 0 | msvcDebugInformationFormatValue = msvcDebugInformationFormatDefault; |
3036 | 0 | } |
3037 | 0 | msvcDebugInformationFormat = cmGeneratorExpression::Evaluate( |
3038 | 0 | *msvcDebugInformationFormatValue, this, config, target); |
3039 | 0 | } |
3040 | 0 | return msvcDebugInformationFormat; |
3041 | 0 | } |
3042 | | |
3043 | | cm::optional<cmSwiftCompileMode> cmLocalGenerator::GetSwiftCompileMode( |
3044 | | cmGeneratorTarget const* target, std::string const& config) |
3045 | 0 | { |
3046 | 0 | cmMakefile const* mf = this->GetMakefile(); |
3047 | 0 | cmValue const swiftCompileModeDefault = |
3048 | 0 | mf->GetDefinition("CMAKE_Swift_COMPILATION_MODE_DEFAULT"); |
3049 | 0 | if (!cmNonempty(swiftCompileModeDefault)) { |
3050 | 0 | return {}; |
3051 | 0 | } |
3052 | 0 | cmValue swiftCompileMode = target->GetProperty("Swift_COMPILATION_MODE"); |
3053 | 0 | if (!swiftCompileMode) { |
3054 | 0 | swiftCompileMode = swiftCompileModeDefault; |
3055 | 0 | } |
3056 | |
|
3057 | 0 | std::string const expandedCompileMode = |
3058 | 0 | cmGeneratorExpression::Evaluate(*swiftCompileMode, this, config, target); |
3059 | 0 | if (expandedCompileMode == "wholemodule") { |
3060 | 0 | return cmSwiftCompileMode::Wholemodule; |
3061 | 0 | } |
3062 | 0 | if (expandedCompileMode == "singlefile") { |
3063 | 0 | return cmSwiftCompileMode::Singlefile; |
3064 | 0 | } |
3065 | 0 | if (expandedCompileMode == "incremental") { |
3066 | 0 | return cmSwiftCompileMode::Incremental; |
3067 | 0 | } |
3068 | 0 | return cmSwiftCompileMode::Unknown; |
3069 | 0 | } |
3070 | | |
3071 | | bool cmLocalGenerator::IsSplitSwiftBuild() const |
3072 | 0 | { |
3073 | 0 | return cmNonempty(this->GetMakefile()->GetDefinition( |
3074 | 0 | "CMAKE_Swift_COMPILATION_MODE_DEFAULT")); |
3075 | 0 | } |
3076 | | |
3077 | | namespace { |
3078 | | |
3079 | | inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, |
3080 | | std::string const& filename) |
3081 | 0 | { |
3082 | 0 | target->AddSourceFileToUnityBatch(sf->ResolveFullPath()); |
3083 | 0 | sf->SetProperty("UNITY_SOURCE_FILE", filename); |
3084 | 0 | } |
3085 | | } |
3086 | | |
3087 | | cmLocalGenerator::UnitySource cmLocalGenerator::WriteUnitySource( |
3088 | | cmGeneratorTarget* target, std::vector<std::string> const& configs, |
3089 | | cmRange<std::vector<UnityBatchedSource>::const_iterator> sources, |
3090 | | cmValue beforeInclude, cmValue afterInclude, std::string filename, |
3091 | | std::string const& unityFileDirectory, UnityPathMode pathMode) const |
3092 | 0 | { |
3093 | 0 | cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); |
3094 | 0 | cmGeneratedFileStream file( |
3095 | 0 | filename, false, target->GetGlobalGenerator()->GetMakefileEncoding()); |
3096 | 0 | file.SetCopyIfDifferent(true); |
3097 | 0 | file << "/* generated by CMake */\n\n"; |
3098 | |
|
3099 | 0 | bool perConfig = false; |
3100 | 0 | for (UnityBatchedSource const& ubs : sources) { |
3101 | 0 | cm::optional<std::string> cond; |
3102 | 0 | if (ubs.Configs.size() != configs.size()) { |
3103 | 0 | perConfig = true; |
3104 | 0 | cond = std::string(); |
3105 | 0 | cm::string_view sep; |
3106 | 0 | for (size_t ci : ubs.Configs) { |
3107 | 0 | cond = cmStrCat(*cond, sep, "defined(CMAKE_UNITY_CONFIG_", |
3108 | 0 | cmSystemTools::UpperCase(configs[ci]), ')'); |
3109 | 0 | sep = " || "_s; |
3110 | 0 | } |
3111 | 0 | } |
3112 | 0 | RegisterUnitySources(target, ubs.Source, filename); |
3113 | 0 | WriteUnitySourceInclude(file, cond, ubs.Source->ResolveFullPath(), |
3114 | 0 | beforeInclude, afterInclude, uniqueIdName, |
3115 | 0 | pathMode, unityFileDirectory); |
3116 | 0 | } |
3117 | |
|
3118 | 0 | return UnitySource(std::move(filename), perConfig); |
3119 | 0 | } |
3120 | | |
3121 | | void cmLocalGenerator::WriteUnitySourceInclude( |
3122 | | std::ostream& unity_file, cm::optional<std::string> const& cond, |
3123 | | std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude, |
3124 | | cmValue uniqueIdName, UnityPathMode pathMode, |
3125 | | std::string const& unityFileDirectory) const |
3126 | 0 | { |
3127 | 0 | if (cond) { |
3128 | 0 | unity_file << "#if " << *cond << "\n"; |
3129 | 0 | } |
3130 | |
|
3131 | 0 | std::string pathToHash; |
3132 | 0 | std::string relocatableIncludePath; |
3133 | 0 | auto PathEqOrSubDir = [](std::string const& a, std::string const& b) { |
3134 | 0 | return (cmSystemTools::ComparePath(a, b) || |
3135 | 0 | cmSystemTools::IsSubDirectory(a, b)); |
3136 | 0 | }; |
3137 | 0 | auto const path = cmSystemTools::GetFilenamePath(sf_full_path); |
3138 | 0 | if (PathEqOrSubDir(path, this->GetBinaryDirectory())) { |
3139 | 0 | relocatableIncludePath = |
3140 | 0 | cmSystemTools::RelativePath(unityFileDirectory, sf_full_path); |
3141 | 0 | pathToHash = "BLD_" + |
3142 | 0 | cmSystemTools::RelativePath(this->GetBinaryDirectory(), sf_full_path); |
3143 | 0 | } else if (PathEqOrSubDir(path, this->GetSourceDirectory())) { |
3144 | 0 | relocatableIncludePath = |
3145 | 0 | cmSystemTools::RelativePath(this->GetSourceDirectory(), sf_full_path); |
3146 | 0 | pathToHash = "SRC_" + relocatableIncludePath; |
3147 | 0 | } else { |
3148 | 0 | relocatableIncludePath = sf_full_path; |
3149 | 0 | pathToHash = "ABS_" + sf_full_path; |
3150 | 0 | } |
3151 | |
|
3152 | 0 | if (cmNonempty(uniqueIdName)) { |
3153 | 0 | cmCryptoHash hasher(cmCryptoHash::AlgoMD5); |
3154 | 0 | unity_file << "/* " << pathToHash << " */\n" |
3155 | 0 | << "#undef " << *uniqueIdName << "\n" |
3156 | 0 | << "#define " << *uniqueIdName << " unity_" |
3157 | 0 | << hasher.HashString(pathToHash) << "\n"; |
3158 | 0 | } |
3159 | |
|
3160 | 0 | if (beforeInclude) { |
3161 | 0 | unity_file << *beforeInclude << "\n"; |
3162 | 0 | } |
3163 | | |
3164 | | // clang-tidy-17 has new include checks that needs NOLINT too. |
3165 | 0 | unity_file |
3166 | 0 | << "/* NOLINTNEXTLINE(bugprone-suspicious-include,misc-include-cleaner) " |
3167 | 0 | "*/\n"; |
3168 | 0 | if (pathMode == UnityPathMode::Relative) { |
3169 | 0 | unity_file << "#include \"" << relocatableIncludePath << "\"\n"; |
3170 | 0 | } else { |
3171 | 0 | unity_file << "#include \"" << sf_full_path << "\"\n"; |
3172 | 0 | } |
3173 | |
|
3174 | 0 | if (afterInclude) { |
3175 | 0 | unity_file << *afterInclude << "\n"; |
3176 | 0 | } |
3177 | 0 | if (cond) { |
3178 | 0 | unity_file << "#endif\n"; |
3179 | 0 | } |
3180 | 0 | unity_file << "\n"; |
3181 | 0 | } |
3182 | | |
3183 | | namespace { |
3184 | | std::string unity_file_extension(std::string const& lang) |
3185 | 0 | { |
3186 | 0 | std::string extension; |
3187 | 0 | if (lang == "C") { |
3188 | 0 | extension = "_c.c"; |
3189 | 0 | } else if (lang == "CXX") { |
3190 | 0 | extension = "_cxx.cxx"; |
3191 | 0 | } else if (lang == "CUDA") { |
3192 | 0 | extension = "_cu.cu"; |
3193 | 0 | } else if (lang == "OBJC") { |
3194 | 0 | extension = "_m.m"; |
3195 | 0 | } else if (lang == "OBJCXX") { |
3196 | 0 | extension = "_mm.mm"; |
3197 | 0 | } |
3198 | 0 | return extension; |
3199 | 0 | } |
3200 | | |
3201 | | char const* unity_file_prefix(cmGeneratorTarget* target) |
3202 | 0 | { |
3203 | 0 | if (cmValue val = target->GetProperty("UNITY_BUILD_FILENAME_PREFIX")) { |
3204 | 0 | return val->c_str(); |
3205 | 0 | } |
3206 | 0 | return "unity_"; |
3207 | 0 | } |
3208 | | } |
3209 | | |
3210 | | std::vector<cmLocalGenerator::UnitySource> |
3211 | | cmLocalGenerator::AddUnityFilesModeAuto( |
3212 | | cmGeneratorTarget* target, std::string const& lang, |
3213 | | std::vector<std::string> const& configs, |
3214 | | std::vector<UnityBatchedSource> const& filtered_sources, |
3215 | | cmValue beforeInclude, cmValue afterInclude, |
3216 | | std::string const& filename_base, UnityPathMode pathMode, size_t batchSize) |
3217 | 0 | { |
3218 | 0 | if (batchSize == 0) { |
3219 | 0 | batchSize = filtered_sources.size(); |
3220 | 0 | } |
3221 | 0 | char const* filename_prefix = unity_file_prefix(target); |
3222 | 0 | std::vector<UnitySource> unity_files; |
3223 | 0 | for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; |
3224 | 0 | itemsLeft > 0; itemsLeft -= chunk, ++batch) { |
3225 | |
|
3226 | 0 | chunk = std::min(itemsLeft, batchSize); |
3227 | |
|
3228 | 0 | std::string filename = cmStrCat(filename_base, filename_prefix, batch, |
3229 | 0 | unity_file_extension(lang)); |
3230 | 0 | auto const begin = filtered_sources.begin() + batch * batchSize; |
3231 | 0 | auto const end = begin + chunk; |
3232 | 0 | unity_files.emplace_back(this->WriteUnitySource( |
3233 | 0 | target, configs, cmMakeRange(begin, end), beforeInclude, afterInclude, |
3234 | 0 | std::move(filename), filename_base, pathMode)); |
3235 | 0 | } |
3236 | 0 | return unity_files; |
3237 | 0 | } |
3238 | | |
3239 | | std::vector<cmLocalGenerator::UnitySource> |
3240 | | cmLocalGenerator::AddUnityFilesModeGroup( |
3241 | | cmGeneratorTarget* target, std::string const& lang, |
3242 | | std::vector<std::string> const& configs, |
3243 | | std::vector<UnityBatchedSource> const& filtered_sources, |
3244 | | cmValue beforeInclude, cmValue afterInclude, |
3245 | | std::string const& filename_base, UnityPathMode pathMode) |
3246 | 0 | { |
3247 | 0 | std::vector<UnitySource> unity_files; |
3248 | | |
3249 | | // sources organized by group name. Drop any source |
3250 | | // without a group |
3251 | 0 | std::unordered_map<std::string, std::vector<UnityBatchedSource>> |
3252 | 0 | explicit_mapping; |
3253 | 0 | for (UnityBatchedSource const& ubs : filtered_sources) { |
3254 | 0 | if (cmValue value = ubs.Source->GetProperty("UNITY_GROUP")) { |
3255 | 0 | auto i = explicit_mapping.find(*value); |
3256 | 0 | if (i == explicit_mapping.end()) { |
3257 | 0 | std::vector<UnityBatchedSource> sources{ ubs }; |
3258 | 0 | explicit_mapping.emplace(*value, std::move(sources)); |
3259 | 0 | } else { |
3260 | 0 | i->second.emplace_back(ubs); |
3261 | 0 | } |
3262 | 0 | } |
3263 | 0 | } |
3264 | |
|
3265 | 0 | char const* filename_prefix = unity_file_prefix(target); |
3266 | 0 | for (auto const& item : explicit_mapping) { |
3267 | 0 | auto const& name = item.first; |
3268 | 0 | std::string filename = cmStrCat(filename_base, filename_prefix, name, |
3269 | 0 | unity_file_extension(lang)); |
3270 | 0 | unity_files.emplace_back(this->WriteUnitySource( |
3271 | 0 | target, configs, cmMakeRange(item.second), beforeInclude, afterInclude, |
3272 | 0 | std::move(filename), filename_base, pathMode)); |
3273 | 0 | } |
3274 | |
|
3275 | 0 | return unity_files; |
3276 | 0 | } |
3277 | | |
3278 | | void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) |
3279 | 0 | { |
3280 | | // cmFastbuildNormalTargetGenerator handles unity build. |
3281 | 0 | if (this->GetGlobalGenerator()->IsFastbuild() || |
3282 | 0 | !target->GetPropertyAsBool("UNITY_BUILD")) { |
3283 | 0 | return; |
3284 | 0 | } |
3285 | | |
3286 | 0 | std::vector<UnityBatchedSource> unitySources; |
3287 | |
|
3288 | 0 | std::vector<std::string> configs = |
3289 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
3290 | |
|
3291 | 0 | std::map<cmSourceFile const*, size_t> index; |
3292 | |
|
3293 | 0 | for (size_t ci = 0; ci < configs.size(); ++ci) { |
3294 | | // FIXME: Refactor collection of sources to not evaluate object libraries. |
3295 | | // Their final set of object files might be transformed by unity builds. |
3296 | 0 | std::vector<cmSourceFile*> sources; |
3297 | 0 | target->GetSourceFiles(sources, configs[ci]); |
3298 | 0 | for (cmSourceFile* sf : sources) { |
3299 | | // Files which need C++ scanning cannot participate in unity builds as |
3300 | | // there is a single place in TUs that may perform module-dependency bits |
3301 | | // and a unity source cannot `#include` them in-order and represent a |
3302 | | // valid TU. |
3303 | 0 | if (sf->GetLanguage() == "CXX"_s && |
3304 | 0 | target->NeedDyndepForSource("CXX", configs[ci], sf)) { |
3305 | 0 | continue; |
3306 | 0 | } |
3307 | | |
3308 | 0 | auto mi = index.find(sf); |
3309 | 0 | if (mi == index.end()) { |
3310 | 0 | unitySources.emplace_back(sf); |
3311 | 0 | std::map<cmSourceFile const*, size_t>::value_type entry( |
3312 | 0 | sf, unitySources.size() - 1); |
3313 | 0 | mi = index.insert(entry).first; |
3314 | 0 | } |
3315 | 0 | unitySources[mi->second].Configs.emplace_back(ci); |
3316 | 0 | } |
3317 | 0 | } |
3318 | |
|
3319 | 0 | std::string filename_base = |
3320 | 0 | cmStrCat(target->GetCMFSupportDirectory(), "/Unity/"); |
3321 | |
|
3322 | 0 | cmValue batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE"); |
3323 | 0 | size_t const unityBatchSize = batchSizeString |
3324 | 0 | ? static_cast<size_t>(std::atoi(batchSizeString->c_str())) |
3325 | 0 | : 0; |
3326 | |
|
3327 | 0 | cmValue beforeInclude = |
3328 | 0 | target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE"); |
3329 | 0 | cmValue afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE"); |
3330 | 0 | cmValue unityMode = target->GetProperty("UNITY_BUILD_MODE"); |
3331 | 0 | UnityPathMode pathMode = target->GetPropertyAsBool("UNITY_BUILD_RELOCATABLE") |
3332 | 0 | ? UnityPathMode::Relative |
3333 | 0 | : UnityPathMode::Absolute; |
3334 | |
|
3335 | 0 | for (std::string lang : { "C", "CXX", "OBJC", "OBJCXX", "CUDA" }) { |
3336 | 0 | std::vector<UnityBatchedSource> filtered_sources; |
3337 | 0 | std::copy_if(unitySources.begin(), unitySources.end(), |
3338 | 0 | std::back_inserter(filtered_sources), |
3339 | 0 | [&](UnityBatchedSource const& ubs) -> bool { |
3340 | 0 | cmSourceFile* sf = ubs.Source; |
3341 | 0 | return sf->GetLanguage() == lang && |
3342 | 0 | !sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") && |
3343 | 0 | !sf->GetPropertyAsBool("HEADER_FILE_ONLY") && |
3344 | 0 | !sf->GetProperty("COMPILE_OPTIONS") && |
3345 | 0 | !sf->GetProperty("COMPILE_DEFINITIONS") && |
3346 | 0 | !sf->GetProperty("COMPILE_FLAGS") && |
3347 | 0 | !sf->GetProperty("INCLUDE_DIRECTORIES"); |
3348 | 0 | }); |
3349 | |
|
3350 | 0 | std::vector<UnitySource> unity_files; |
3351 | 0 | if (!unityMode || *unityMode == "BATCH") { |
3352 | 0 | unity_files = AddUnityFilesModeAuto( |
3353 | 0 | target, lang, configs, filtered_sources, beforeInclude, afterInclude, |
3354 | 0 | filename_base, pathMode, unityBatchSize); |
3355 | 0 | } else if (unityMode && *unityMode == "GROUP") { |
3356 | 0 | unity_files = AddUnityFilesModeGroup( |
3357 | 0 | target, lang, configs, filtered_sources, beforeInclude, afterInclude, |
3358 | 0 | filename_base, pathMode); |
3359 | 0 | } else { |
3360 | | // unity mode is set to an unsupported value |
3361 | 0 | std::string e("Invalid UNITY_BUILD_MODE value of " + *unityMode + |
3362 | 0 | " assigned to target " + target->GetName() + |
3363 | 0 | ". Acceptable values are BATCH and GROUP."); |
3364 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, e); |
3365 | 0 | } |
3366 | |
|
3367 | 0 | for (UnitySource const& file : unity_files) { |
3368 | 0 | auto* unity = this->GetMakefile()->GetOrCreateSource(file.Path); |
3369 | 0 | unity->SetSpecialSourceType( |
3370 | 0 | cmSourceFile::SpecialSourceType::UnitySource); |
3371 | 0 | target->AddSource(file.Path, true); |
3372 | 0 | unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON"); |
3373 | 0 | unity->SetProperty("UNITY_SOURCE_FILE", file.Path); |
3374 | 0 | unity->SetProperty("CXX_SCAN_FOR_MODULES", "0"); |
3375 | 0 | if (file.PerConfig) { |
3376 | 0 | unity->SetProperty("COMPILE_DEFINITIONS", |
3377 | 0 | "CMAKE_UNITY_CONFIG_$<UPPER_CASE:$<CONFIG>>"); |
3378 | 0 | } |
3379 | |
|
3380 | 0 | if (pathMode == UnityPathMode::Relative) { |
3381 | 0 | unity->AppendProperty("INCLUDE_DIRECTORIES", |
3382 | 0 | this->GetSourceDirectory(), false); |
3383 | 0 | } |
3384 | 0 | } |
3385 | 0 | } |
3386 | 0 | } |
3387 | | |
3388 | | void cmLocalGenerator::AddPerLanguageLinkFlags(std::string& flags, |
3389 | | cmGeneratorTarget const* target, |
3390 | | std::string const& lang, |
3391 | | std::string const& config) |
3392 | 0 | { |
3393 | 0 | switch (target->GetType()) { |
3394 | 0 | case cmStateEnums::MODULE_LIBRARY: |
3395 | 0 | case cmStateEnums::SHARED_LIBRARY: |
3396 | 0 | case cmStateEnums::EXECUTABLE: |
3397 | 0 | break; |
3398 | 0 | default: |
3399 | 0 | return; |
3400 | 0 | } |
3401 | | |
3402 | 0 | std::string langLinkFlags = |
3403 | 0 | this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", lang, "_LINK_FLAGS")); |
3404 | |
|
3405 | 0 | switch (target->GetPolicyStatusCMP0210()) { |
3406 | 0 | case cmPolicies::WARN: |
3407 | | // WARN only when CMAKE_<LANG>_LINK_FLAGS is set, and when the current |
3408 | | // target is not an executable, and CMAKE_<LANG>_LINK_FLAGS is not equal |
3409 | | // to CMAKE_EXECUTABLE_CREATE_<LANG>_FLAGS. This warns users trying to |
3410 | | // use the NEW behavior on old projects (since CMake will be ignoring |
3411 | | // their wishes), while also exempting cases when the latter variable |
3412 | | // (substituted for the former spelling under the NEW behavior) is being |
3413 | | // used legitimately by CMake. |
3414 | | // Additionally, WARN at most once per language, instead of on every |
3415 | | // target. |
3416 | 0 | if (!langLinkFlags.empty() && |
3417 | 0 | target->GetType() != cmStateEnums::EXECUTABLE && |
3418 | 0 | langLinkFlags != |
3419 | 0 | this->Makefile->GetSafeDefinition( |
3420 | 0 | cmStrCat("CMAKE_EXECUTABLE_CREATE_", lang, "_FLAGS")) && |
3421 | 0 | this->GlobalGenerator->ShouldWarnCMP0210(lang)) { |
3422 | 0 | this->IssueDiagnostic( |
3423 | 0 | cmDiagnostics::CMD_AUTHOR, |
3424 | 0 | cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0210), "\n", |
3425 | 0 | "For compatibility with older versions of CMake, ", |
3426 | 0 | "CMAKE_", lang, "_LINK_FLAGS will be ignored for all ", |
3427 | 0 | "non-EXECUTABLE targets which use these flags.")); |
3428 | 0 | } |
3429 | 0 | CM_FALLTHROUGH; |
3430 | 0 | case cmPolicies::OLD: |
3431 | | // OLD behavior is to do nothing here, since the use of |
3432 | | // CMAKE_<LANG>_LINK_FLAGS for EXECUTABLEs is handled elsewhere. |
3433 | 0 | break; |
3434 | 0 | case cmPolicies::NEW: |
3435 | | // NEW behavior is to support per-language link flags for all target |
3436 | | // types. |
3437 | 0 | this->AppendLinkFlagsWithParsing(flags, langLinkFlags, target, lang); |
3438 | 0 | if (!config.empty()) { |
3439 | 0 | std::string lankLinkFlagsConfig = |
3440 | 0 | this->Makefile->GetSafeDefinition(cmStrCat( |
3441 | 0 | "CMAKE_", lang, "_LINK_FLAGS_", cmSystemTools::UpperCase(config))); |
3442 | 0 | this->AppendLinkFlagsWithParsing(flags, lankLinkFlagsConfig, target, |
3443 | 0 | lang); |
3444 | 0 | } |
3445 | 0 | break; |
3446 | 0 | } |
3447 | 0 | } |
3448 | | |
3449 | | void cmLocalGenerator::AppendTargetCreationLinkFlags( |
3450 | | std::string& flags, cmGeneratorTarget const* target, |
3451 | | std::string const& linkLanguage) |
3452 | 0 | { |
3453 | 0 | std::string createFlagsVar; |
3454 | 0 | cmValue createFlagsVal; |
3455 | 0 | switch (target->GetType()) { |
3456 | 0 | case cmStateEnums::STATIC_LIBRARY: |
3457 | 0 | break; |
3458 | 0 | case cmStateEnums::MODULE_LIBRARY: |
3459 | 0 | createFlagsVar = |
3460 | 0 | cmStrCat("CMAKE_SHARED_MODULE_CREATE_", linkLanguage, "_FLAGS"); |
3461 | 0 | createFlagsVal = this->Makefile->GetDefinition(createFlagsVar); |
3462 | | // On some platforms we use shared library creation flags for modules. |
3463 | 0 | CM_FALLTHROUGH; |
3464 | 0 | case cmStateEnums::SHARED_LIBRARY: |
3465 | 0 | if (!createFlagsVal) { |
3466 | 0 | createFlagsVar = |
3467 | 0 | cmStrCat("CMAKE_SHARED_LIBRARY_CREATE_", linkLanguage, "_FLAGS"); |
3468 | 0 | createFlagsVal = this->Makefile->GetDefinition(createFlagsVar); |
3469 | 0 | } |
3470 | 0 | break; |
3471 | 0 | case cmStateEnums::EXECUTABLE: |
3472 | 0 | createFlagsVar = target->GetPolicyStatusCMP0210() == cmPolicies::NEW |
3473 | 0 | ? cmStrCat("CMAKE_EXECUTABLE_CREATE_", linkLanguage, "_FLAGS") |
3474 | 0 | : cmStrCat("CMAKE_", linkLanguage, "_LINK_FLAGS"); |
3475 | 0 | createFlagsVal = this->Makefile->GetDefinition(createFlagsVar); |
3476 | 0 | break; |
3477 | 0 | default: |
3478 | 0 | break; |
3479 | 0 | } |
3480 | 0 | if (createFlagsVal) { |
3481 | 0 | this->AppendFlags(flags, *createFlagsVal, createFlagsVar, target, |
3482 | 0 | cmBuildStep::Link, linkLanguage); |
3483 | 0 | } |
3484 | 0 | } |
3485 | | |
3486 | | void cmLocalGenerator::AppendLinkerTypeFlags(std::string& flags, |
3487 | | cmGeneratorTarget* target, |
3488 | | std::string const& config, |
3489 | | std::string const& linkLanguage) |
3490 | 0 | { |
3491 | 0 | switch (target->GetType()) { |
3492 | 0 | case cmStateEnums::EXECUTABLE: |
3493 | 0 | case cmStateEnums::SHARED_LIBRARY: |
3494 | 0 | case cmStateEnums::MODULE_LIBRARY: |
3495 | 0 | break; |
3496 | 0 | default: |
3497 | 0 | return; |
3498 | 0 | } |
3499 | | |
3500 | 0 | auto linkMode = |
3501 | 0 | cmStrCat("CMAKE_", linkLanguage, target->IsDeviceLink() ? "_DEVICE_" : "_", |
3502 | 0 | "LINK_MODE"); |
3503 | 0 | auto mode = this->Makefile->GetDefinition(linkMode); |
3504 | 0 | if (mode && mode != "DRIVER"_s) { |
3505 | 0 | return; |
3506 | 0 | } |
3507 | | |
3508 | 0 | auto linkerType = target->GetLinkerTypeProperty(linkLanguage, config); |
3509 | 0 | if (linkerType.empty()) { |
3510 | 0 | linkerType = "DEFAULT"; |
3511 | 0 | } |
3512 | 0 | auto usingLinker = |
3513 | 0 | cmStrCat("CMAKE_", linkLanguage, "_USING_", |
3514 | 0 | target->IsDeviceLink() ? "DEVICE_" : "", "LINKER_", linkerType); |
3515 | 0 | auto linkerTypeFlags = this->Makefile->GetDefinition(usingLinker); |
3516 | 0 | if (linkerTypeFlags) { |
3517 | 0 | if (!linkerTypeFlags.IsEmpty()) { |
3518 | 0 | auto linkerFlags = cmExpandListWithBacktrace(linkerTypeFlags); |
3519 | 0 | target->ResolveLinkerWrapper(linkerFlags, linkLanguage); |
3520 | 0 | this->AppendFlags(flags, linkerFlags); |
3521 | 0 | } |
3522 | 0 | } else if (linkerType != "DEFAULT"_s) { |
3523 | 0 | auto isCMakeLinkerType = [](std::string const& type) -> bool { |
3524 | 0 | return std::all_of(type.cbegin(), type.cend(), cmsysString_isupper); |
3525 | 0 | }; |
3526 | 0 | if (isCMakeLinkerType(linkerType)) { |
3527 | 0 | this->IssueMessage( |
3528 | 0 | MessageType::FATAL_ERROR, |
3529 | 0 | cmStrCat("LINKER_TYPE '", linkerType, |
3530 | 0 | "' is unknown or not supported by this toolchain.")); |
3531 | 0 | } else { |
3532 | 0 | this->IssueMessage( |
3533 | 0 | MessageType::FATAL_ERROR, |
3534 | 0 | cmStrCat("LINKER_TYPE '", linkerType, |
3535 | 0 | "' is unknown. Did you forget to define the '", usingLinker, |
3536 | 0 | "' variable?")); |
3537 | 0 | } |
3538 | 0 | } |
3539 | 0 | } |
3540 | | |
3541 | | void cmLocalGenerator::AddTargetTypeLinkerFlags( |
3542 | | std::string& flags, cmGeneratorTarget const* target, std::string const& lang, |
3543 | | std::string const& config) |
3544 | 0 | { |
3545 | 0 | std::string linkerFlagsVar; |
3546 | 0 | switch (target->GetType()) { |
3547 | 0 | case cmStateEnums::EXECUTABLE: |
3548 | 0 | linkerFlagsVar = "CMAKE_EXE_LINKER_FLAGS"; |
3549 | 0 | break; |
3550 | 0 | case cmStateEnums::SHARED_LIBRARY: |
3551 | 0 | linkerFlagsVar = "CMAKE_SHARED_LINKER_FLAGS"; |
3552 | 0 | break; |
3553 | 0 | case cmStateEnums::MODULE_LIBRARY: |
3554 | 0 | linkerFlagsVar = "CMAKE_MODULE_LINKER_FLAGS"; |
3555 | 0 | break; |
3556 | 0 | default: |
3557 | 0 | return; |
3558 | 0 | } |
3559 | 0 | this->AddConfigVariableFlags(flags, linkerFlagsVar, target, |
3560 | 0 | cmBuildStep::Link, lang, config); |
3561 | 0 | } |
3562 | | |
3563 | | void cmLocalGenerator::AddTargetPropertyLinkFlags( |
3564 | | std::string& flags, cmGeneratorTarget const* target, |
3565 | | std::string const& config) |
3566 | 0 | { |
3567 | 0 | cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS"); |
3568 | 0 | if (targetLinkFlags) { |
3569 | 0 | this->AppendFlags(flags, *targetLinkFlags); |
3570 | 0 | } |
3571 | 0 | if (!config.empty()) { |
3572 | 0 | cmValue targetLinkFlagsConfig = target->GetProperty( |
3573 | 0 | cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(config))); |
3574 | 0 | if (targetLinkFlagsConfig) { |
3575 | 0 | this->AppendFlags(flags, *targetLinkFlagsConfig); |
3576 | 0 | } |
3577 | 0 | } |
3578 | 0 | } |
3579 | | |
3580 | | void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags, |
3581 | | cmGeneratorTarget* target, |
3582 | | std::string const& config, |
3583 | | std::string const& lang) |
3584 | 0 | { |
3585 | 0 | if (!target->IsIPOEnabled(lang, config)) { |
3586 | 0 | return; |
3587 | 0 | } |
3588 | | |
3589 | 0 | switch (target->GetType()) { |
3590 | 0 | case cmStateEnums::EXECUTABLE: |
3591 | 0 | case cmStateEnums::SHARED_LIBRARY: |
3592 | 0 | case cmStateEnums::MODULE_LIBRARY: |
3593 | 0 | break; |
3594 | 0 | default: |
3595 | 0 | return; |
3596 | 0 | } |
3597 | | |
3598 | 0 | std::string const name = "CMAKE_" + lang + "_LINK_OPTIONS_IPO"; |
3599 | 0 | cmValue rawFlagsList = this->Makefile->GetDefinition(name); |
3600 | 0 | if (!rawFlagsList) { |
3601 | 0 | return; |
3602 | 0 | } |
3603 | | |
3604 | 0 | cmList flagsList{ *rawFlagsList }; |
3605 | 0 | for (std::string const& o : flagsList) { |
3606 | 0 | this->AppendFlagEscape(flags, o); |
3607 | 0 | } |
3608 | 0 | } |
3609 | | |
3610 | | void cmLocalGenerator::AppendPositionIndependentLinkerFlags( |
3611 | | std::string& flags, cmGeneratorTarget* target, std::string const& config, |
3612 | | std::string const& lang) |
3613 | 0 | { |
3614 | | // For now, only EXECUTABLE is concerned |
3615 | 0 | if (target->GetType() != cmStateEnums::EXECUTABLE) { |
3616 | 0 | return; |
3617 | 0 | } |
3618 | | |
3619 | 0 | char const* PICValue = target->GetLinkPIEProperty(config); |
3620 | 0 | if (!PICValue && lang != "Rust") { |
3621 | | // POSITION_INDEPENDENT_CODE is not set, note that for Rust we do not |
3622 | | // return as the compiler tends to enable PIE all the time, which is the |
3623 | | // opposite of what C & C++ compilers do. So instead of letting the rust |
3624 | | // compiler decide on its own whether PIE should be enabled, we explicit |
3625 | | // set it. |
3626 | 0 | return; |
3627 | 0 | } |
3628 | | |
3629 | 0 | std::string const mode = cmIsOn(PICValue) ? "PIE" : "NO_PIE"; |
3630 | |
|
3631 | 0 | std::string supported = "CMAKE_" + lang + "_LINK_" + mode + "_SUPPORTED"; |
3632 | 0 | if (this->Makefile->GetDefinition(supported).IsOff()) { |
3633 | 0 | return; |
3634 | 0 | } |
3635 | | |
3636 | 0 | std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_" + mode; |
3637 | |
|
3638 | 0 | auto pieFlags = this->Makefile->GetSafeDefinition(name); |
3639 | 0 | if (pieFlags.empty()) { |
3640 | 0 | return; |
3641 | 0 | } |
3642 | | |
3643 | 0 | cmList flagsList{ pieFlags }; |
3644 | 0 | for (auto const& flag : flagsList) { |
3645 | 0 | this->AppendFlagEscape(flags, flag); |
3646 | 0 | } |
3647 | 0 | } |
3648 | | |
3649 | | void cmLocalGenerator::AppendWarningAsErrorLinkerFlags( |
3650 | | std::string& flags, cmGeneratorTarget* target, std::string const& lang) |
3651 | 0 | { |
3652 | 0 | if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) { |
3653 | 0 | return; |
3654 | 0 | } |
3655 | | |
3656 | 0 | switch (target->GetType()) { |
3657 | 0 | case cmStateEnums::EXECUTABLE: |
3658 | 0 | case cmStateEnums::SHARED_LIBRARY: |
3659 | 0 | case cmStateEnums::MODULE_LIBRARY: |
3660 | 0 | break; |
3661 | 0 | default: |
3662 | 0 | return; |
3663 | 0 | } |
3664 | | |
3665 | 0 | auto const wError = target->GetProperty("LINK_WARNING_AS_ERROR"); |
3666 | 0 | if (wError.IsOff()) { |
3667 | 0 | return; |
3668 | 0 | } |
3669 | 0 | cmList wErrorOptions; |
3670 | 0 | if (wError.IsOn()) { |
3671 | 0 | wErrorOptions = { "DRIVER", "LINKER" }; |
3672 | 0 | } else { |
3673 | 0 | wErrorOptions = wError; |
3674 | 0 | std::sort(wErrorOptions.begin(), wErrorOptions.end()); |
3675 | 0 | wErrorOptions.erase( |
3676 | 0 | std::unique(wErrorOptions.begin(), wErrorOptions.end()), |
3677 | 0 | wErrorOptions.end()); |
3678 | 0 | } |
3679 | |
|
3680 | 0 | auto linkModeIsDriver = |
3681 | 0 | this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_LINK_MODE")) == |
3682 | 0 | "DRIVER"_s; |
3683 | 0 | std::string errorMessage; |
3684 | 0 | for (auto const& option : wErrorOptions) { |
3685 | 0 | if (option != "DRIVER"_s && option != "LINKER"_s) { |
3686 | 0 | errorMessage += cmStrCat(" ", option, '\n'); |
3687 | 0 | continue; |
3688 | 0 | } |
3689 | | |
3690 | 0 | if (option == "DRIVER"_s && !linkModeIsDriver) { |
3691 | 0 | continue; |
3692 | 0 | } |
3693 | | |
3694 | 0 | auto const wErrorOpts = this->Makefile->GetDefinition(cmStrCat( |
3695 | 0 | "CMAKE_", lang, '_', (option == "DRIVER"_s ? "COMPILE" : "LINK"), |
3696 | 0 | "_OPTIONS_WARNING_AS_ERROR")); |
3697 | 0 | if (wErrorOpts.IsSet()) { |
3698 | 0 | auto items = |
3699 | 0 | cmExpandListWithBacktrace(wErrorOpts, target->GetBacktrace()); |
3700 | 0 | if (option == "LINKER"_s) { |
3701 | 0 | target->ResolveLinkerWrapper(items, lang); |
3702 | 0 | } |
3703 | 0 | for (auto const& item : items) { |
3704 | 0 | this->AppendFlagEscape(flags, item.Value); |
3705 | 0 | } |
3706 | 0 | } |
3707 | 0 | } |
3708 | 0 | if (!errorMessage.empty()) { |
3709 | 0 | this->Makefile->GetCMakeInstance()->IssueMessage( |
3710 | 0 | MessageType::FATAL_ERROR, |
3711 | 0 | cmStrCat( |
3712 | 0 | "Erroneous value(s) for 'LINK_WARNING_AS_ERROR' property of target '", |
3713 | 0 | target->GetName(), "':\n", errorMessage)); |
3714 | 0 | } |
3715 | 0 | } |
3716 | | |
3717 | | void cmLocalGenerator::AppendDependencyInfoLinkerFlags( |
3718 | | std::string& flags, cmGeneratorTarget* target, std::string const& config, |
3719 | | std::string const& linkLanguage) |
3720 | 0 | { |
3721 | 0 | if (!this->GetGlobalGenerator()->SupportsLinkerDependencyFile() || |
3722 | 0 | !target->HasLinkDependencyFile(config)) { |
3723 | 0 | return; |
3724 | 0 | } |
3725 | | |
3726 | 0 | auto depFlag = *this->Makefile->GetDefinition( |
3727 | 0 | cmStrCat("CMAKE_", linkLanguage, "_LINKER_DEPFILE_FLAGS")); |
3728 | 0 | if (depFlag.empty()) { |
3729 | 0 | return; |
3730 | 0 | } |
3731 | | |
3732 | 0 | auto depFile = this->ConvertToOutputFormat( |
3733 | 0 | this->MaybeRelativeToWorkDir(this->GetLinkDependencyFile(target, config)), |
3734 | 0 | cmOutputConverter::SHELL); |
3735 | 0 | auto rulePlaceholderExpander = this->CreateRulePlaceholderExpander(); |
3736 | 0 | cmRulePlaceholderExpander::RuleVariables linkDepsVariables; |
3737 | 0 | linkDepsVariables.DependencyFile = depFile.c_str(); |
3738 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this, depFlag, |
3739 | 0 | linkDepsVariables); |
3740 | 0 | auto depFlags = cmExpandListWithBacktrace(depFlag); |
3741 | 0 | target->ResolveLinkerWrapper(depFlags, linkLanguage); |
3742 | |
|
3743 | 0 | this->AppendFlags(flags, depFlags); |
3744 | 0 | } |
3745 | | |
3746 | | std::string cmLocalGenerator::GetLinkDependencyFile( |
3747 | | cmGeneratorTarget* /*target*/, std::string const& /*config*/) const |
3748 | 0 | { |
3749 | 0 | return "link.d"; |
3750 | 0 | } |
3751 | | |
3752 | | void cmLocalGenerator::AppendModuleDefinitionFlag( |
3753 | | std::string& flags, cmGeneratorTarget const* target, |
3754 | | cmLinkLineComputer* linkLineComputer, std::string const& config, |
3755 | | std::string const& lang) |
3756 | 0 | { |
3757 | 0 | cmGeneratorTarget::ModuleDefinitionInfo const* mdi = |
3758 | 0 | target->GetModuleDefinitionInfo(config); |
3759 | 0 | if (!mdi || mdi->DefFile.empty()) { |
3760 | 0 | return; |
3761 | 0 | } |
3762 | | |
3763 | 0 | cmValue defFileFlag = this->Makefile->GetDefinition( |
3764 | 0 | cmStrCat("CMAKE_", lang, "_LINK_DEF_FILE_FLAG")); |
3765 | 0 | if (!defFileFlag) { |
3766 | 0 | defFileFlag = this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG"); |
3767 | 0 | } |
3768 | 0 | if (!defFileFlag) { |
3769 | 0 | return; |
3770 | 0 | } |
3771 | | |
3772 | | // Append the flag and value. Use ConvertToLinkReference to help |
3773 | | // vs6's "cl -link" pass it to the linker. |
3774 | 0 | std::string flag = |
3775 | 0 | cmStrCat(*defFileFlag, |
3776 | 0 | this->ConvertToOutputFormat( |
3777 | 0 | linkLineComputer->ConvertToLinkReference(mdi->DefFile), |
3778 | 0 | cmOutputConverter::SHELL)); |
3779 | 0 | this->AppendFlags(flags, flag); |
3780 | 0 | } |
3781 | | |
3782 | | bool cmLocalGenerator::AppendLWYUFlags(std::string& flags, |
3783 | | cmGeneratorTarget const* target, |
3784 | | std::string const& lang) |
3785 | 0 | { |
3786 | 0 | auto useLWYU = target->GetPropertyAsBool("LINK_WHAT_YOU_USE") && |
3787 | 0 | (target->GetType() == cmStateEnums::TargetType::EXECUTABLE || |
3788 | 0 | target->GetType() == cmStateEnums::TargetType::SHARED_LIBRARY || |
3789 | 0 | target->GetType() == cmStateEnums::TargetType::MODULE_LIBRARY); |
3790 | |
|
3791 | 0 | if (useLWYU) { |
3792 | 0 | auto const& lwyuFlag = this->GetMakefile()->GetSafeDefinition( |
3793 | 0 | cmStrCat("CMAKE_", lang, "_LINK_WHAT_YOU_USE_FLAG")); |
3794 | 0 | useLWYU = !lwyuFlag.empty(); |
3795 | |
|
3796 | 0 | if (useLWYU) { |
3797 | 0 | std::vector<BT<std::string>> lwyuOpts; |
3798 | 0 | lwyuOpts.emplace_back(lwyuFlag); |
3799 | 0 | this->AppendFlags(flags, target->ResolveLinkerWrapper(lwyuOpts, lang)); |
3800 | 0 | } |
3801 | 0 | } |
3802 | |
|
3803 | 0 | return useLWYU; |
3804 | 0 | } |
3805 | | |
3806 | | void cmLocalGenerator::AppendCompileOptions(std::string& options, |
3807 | | std::string const& options_list, |
3808 | | char const* regex) const |
3809 | 0 | { |
3810 | | // Short-circuit if there are no options. |
3811 | 0 | if (options_list.empty()) { |
3812 | 0 | return; |
3813 | 0 | } |
3814 | | |
3815 | | // Expand the list of options. |
3816 | 0 | cmList options_vec{ options_list }; |
3817 | 0 | this->AppendCompileOptions(options, options_vec, regex); |
3818 | 0 | } |
3819 | | |
3820 | | void cmLocalGenerator::AppendCompileOptions( |
3821 | | std::string& options, std::vector<std::string> const& options_vec, |
3822 | | char const* regex) const |
3823 | 0 | { |
3824 | 0 | if (regex) { |
3825 | | // Filter flags upon specified reges. |
3826 | 0 | cmsys::RegularExpression r(regex); |
3827 | |
|
3828 | 0 | for (std::string const& opt : options_vec) { |
3829 | 0 | if (r.find(opt)) { |
3830 | 0 | this->AppendFlagEscape(options, opt); |
3831 | 0 | } |
3832 | 0 | } |
3833 | 0 | } else { |
3834 | 0 | for (std::string const& opt : options_vec) { |
3835 | 0 | this->AppendFlagEscape(options, opt); |
3836 | 0 | } |
3837 | 0 | } |
3838 | 0 | } |
3839 | | |
3840 | | void cmLocalGenerator::AppendCompileOptions( |
3841 | | std::vector<BT<std::string>>& options, |
3842 | | std::vector<BT<std::string>> const& options_vec, char const* regex) const |
3843 | 0 | { |
3844 | 0 | if (regex) { |
3845 | | // Filter flags upon specified regular expressions. |
3846 | 0 | cmsys::RegularExpression r(regex); |
3847 | |
|
3848 | 0 | for (BT<std::string> const& opt : options_vec) { |
3849 | 0 | if (r.find(opt.Value)) { |
3850 | 0 | std::string flag; |
3851 | 0 | this->AppendFlagEscape(flag, opt.Value); |
3852 | 0 | options.emplace_back(std::move(flag), opt.Backtrace); |
3853 | 0 | } |
3854 | 0 | } |
3855 | 0 | } else { |
3856 | 0 | for (BT<std::string> const& opt : options_vec) { |
3857 | 0 | std::string flag; |
3858 | 0 | this->AppendFlagEscape(flag, opt.Value); |
3859 | 0 | options.emplace_back(std::move(flag), opt.Backtrace); |
3860 | 0 | } |
3861 | 0 | } |
3862 | 0 | } |
3863 | | |
3864 | | void cmLocalGenerator::AppendIncludeDirectories( |
3865 | | std::vector<std::string>& includes, std::string const& includes_list, |
3866 | | cmSourceFile const& sourceFile) const |
3867 | 0 | { |
3868 | | // Short-circuit if there are no includes. |
3869 | 0 | if (includes_list.empty()) { |
3870 | 0 | return; |
3871 | 0 | } |
3872 | | |
3873 | | // Expand the list of includes. |
3874 | 0 | cmList includes_vec{ includes_list }; |
3875 | 0 | this->AppendIncludeDirectories(includes, includes_vec, sourceFile); |
3876 | 0 | } |
3877 | | |
3878 | | void cmLocalGenerator::AppendIncludeDirectories( |
3879 | | std::vector<std::string>& includes, |
3880 | | std::vector<std::string> const& includes_vec, |
3881 | | cmSourceFile const& sourceFile) const |
3882 | 0 | { |
3883 | 0 | std::unordered_set<std::string> uniqueIncludes; |
3884 | |
|
3885 | 0 | for (std::string const& include : includes_vec) { |
3886 | 0 | if (!cmSystemTools::FileIsFullPath(include)) { |
3887 | 0 | std::ostringstream e; |
3888 | 0 | e << "Found relative path while evaluating include directories of " |
3889 | 0 | "\"" |
3890 | 0 | << sourceFile.GetLocation().GetName() << "\":\n \"" << include |
3891 | 0 | << "\"\n"; |
3892 | |
|
3893 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
3894 | 0 | return; |
3895 | 0 | } |
3896 | | |
3897 | 0 | std::string inc = include; |
3898 | |
|
3899 | 0 | if (!cmIsOff(inc)) { |
3900 | 0 | cmSystemTools::ConvertToUnixSlashes(inc); |
3901 | 0 | } |
3902 | |
|
3903 | 0 | if (uniqueIncludes.insert(inc).second) { |
3904 | 0 | includes.push_back(std::move(inc)); |
3905 | 0 | } |
3906 | 0 | } |
3907 | 0 | } |
3908 | | |
3909 | | void cmLocalGenerator::AppendDefines(std::set<std::string>& defines, |
3910 | | std::string const& defines_list) const |
3911 | 0 | { |
3912 | 0 | std::set<BT<std::string>> tmp; |
3913 | 0 | this->AppendDefines(tmp, cmExpandListWithBacktrace(defines_list)); |
3914 | 0 | for (BT<std::string> const& i : tmp) { |
3915 | 0 | defines.emplace(i.Value); |
3916 | 0 | } |
3917 | 0 | } |
3918 | | |
3919 | | void cmLocalGenerator::AppendDefines( |
3920 | | std::set<std::string>& defines, |
3921 | | std::vector<BT<std::string>> const& defines_vec) const |
3922 | 0 | { |
3923 | 0 | std::set<BT<std::string>> tmp; |
3924 | 0 | this->AppendDefines(tmp, defines_vec); |
3925 | 0 | for (BT<std::string> const& i : tmp) { |
3926 | 0 | defines.emplace(i.Value); |
3927 | 0 | } |
3928 | 0 | } |
3929 | | |
3930 | | void cmLocalGenerator::AppendDefines(std::set<BT<std::string>>& defines, |
3931 | | std::string const& defines_list) const |
3932 | 0 | { |
3933 | | // Short-circuit if there are no definitions. |
3934 | 0 | if (defines_list.empty()) { |
3935 | 0 | return; |
3936 | 0 | } |
3937 | | |
3938 | | // Expand the list of definitions. |
3939 | 0 | this->AppendDefines(defines, cmExpandListWithBacktrace(defines_list)); |
3940 | 0 | } |
3941 | | |
3942 | | void cmLocalGenerator::AppendDefines( |
3943 | | std::set<BT<std::string>>& defines, |
3944 | | std::vector<BT<std::string>> const& defines_vec) const |
3945 | 0 | { |
3946 | 0 | for (BT<std::string> const& d : defines_vec) { |
3947 | | // Skip unsupported definitions. |
3948 | 0 | if (!this->CheckDefinition(d.Value)) { |
3949 | 0 | continue; |
3950 | 0 | } |
3951 | | // remove any leading -D |
3952 | 0 | if (cmHasLiteralPrefix(d.Value, "-D")) { |
3953 | 0 | defines.emplace(d.Value.substr(2), d.Backtrace); |
3954 | 0 | } else { |
3955 | 0 | defines.insert(d); |
3956 | 0 | } |
3957 | 0 | } |
3958 | 0 | } |
3959 | | |
3960 | | void cmLocalGenerator::JoinDefines(std::set<std::string> const& defines, |
3961 | | std::string& definesString, |
3962 | | std::string const& lang) |
3963 | 0 | { |
3964 | | // Lookup the define flag for the current language. |
3965 | 0 | std::string dflag = "-D"; |
3966 | 0 | if (!lang.empty()) { |
3967 | 0 | cmValue df = |
3968 | 0 | this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_DEFINE_FLAG")); |
3969 | 0 | if (cmNonempty(df)) { |
3970 | 0 | dflag = *df; |
3971 | 0 | } |
3972 | 0 | } |
3973 | 0 | char const* itemSeparator = definesString.empty() ? "" : " "; |
3974 | 0 | for (std::string const& define : defines) { |
3975 | | // Append the definition with proper escaping. |
3976 | 0 | std::string def = dflag; |
3977 | 0 | if (this->GetState()->UseWatcomWMake()) { |
3978 | | // The Watcom compiler does its own command line parsing instead |
3979 | | // of using the windows shell rules. Definitions are one of |
3980 | | // -DNAME |
3981 | | // -DNAME=<cpp-token> |
3982 | | // -DNAME="c-string with spaces and other characters(?@#$)" |
3983 | | // |
3984 | | // Watcom will properly parse each of these cases from the |
3985 | | // command line without any escapes. However we still have to |
3986 | | // get the '$' and '#' characters through WMake as '$$' and |
3987 | | // '$#'. |
3988 | 0 | for (char c : define) { |
3989 | 0 | if (c == '$' || c == '#') { |
3990 | 0 | def += '$'; |
3991 | 0 | } |
3992 | 0 | def += c; |
3993 | 0 | } |
3994 | 0 | } else { |
3995 | | // Make the definition appear properly on the command line. Use |
3996 | | // -DNAME="value" instead of -D"NAME=value" for historical reasons. |
3997 | 0 | std::string::size_type eq = define.find('='); |
3998 | 0 | def += define.substr(0, eq); |
3999 | 0 | if (eq != std::string::npos) { |
4000 | 0 | def += "="; |
4001 | 0 | def += this->EscapeForShell(define.substr(eq + 1), true); |
4002 | 0 | } |
4003 | 0 | } |
4004 | 0 | definesString += itemSeparator; |
4005 | 0 | itemSeparator = " "; |
4006 | 0 | definesString += def; |
4007 | 0 | } |
4008 | 0 | } |
4009 | | |
4010 | | void cmLocalGenerator::AppendFeatureOptions(std::string& flags, |
4011 | | std::string const& lang, |
4012 | | char const* feature) |
4013 | 0 | { |
4014 | 0 | cmValue optionList = this->Makefile->GetDefinition( |
4015 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_", feature)); |
4016 | 0 | if (optionList) { |
4017 | 0 | cmList options{ *optionList }; |
4018 | 0 | for (std::string const& o : options) { |
4019 | 0 | this->AppendFlagEscape(flags, o); |
4020 | 0 | } |
4021 | 0 | } |
4022 | 0 | } |
4023 | | |
4024 | | cmValue cmLocalGenerator::GetFeature(std::string const& feature, |
4025 | | std::string const& config) |
4026 | 0 | { |
4027 | 0 | std::string featureName = feature; |
4028 | | // TODO: Define accumulation policy for features (prepend, append, |
4029 | | // replace). Currently we always replace. |
4030 | 0 | if (!config.empty()) { |
4031 | 0 | featureName += "_"; |
4032 | 0 | featureName += cmSystemTools::UpperCase(config); |
4033 | 0 | } |
4034 | 0 | cmStateSnapshot snp = this->StateSnapshot; |
4035 | 0 | while (snp.IsValid()) { |
4036 | 0 | if (cmValue value = snp.GetDirectory().GetProperty(featureName)) { |
4037 | 0 | return value; |
4038 | 0 | } |
4039 | 0 | snp = snp.GetBuildsystemDirectoryParent(); |
4040 | 0 | } |
4041 | 0 | return nullptr; |
4042 | 0 | } |
4043 | | |
4044 | | std::string cmLocalGenerator::GetProjectName() const |
4045 | 0 | { |
4046 | 0 | return this->StateSnapshot.GetProjectName(); |
4047 | 0 | } |
4048 | | |
4049 | | std::string cmLocalGenerator::ConstructComment( |
4050 | | cmCustomCommandGenerator const& ccg, char const* default_comment) const |
4051 | 0 | { |
4052 | | // Check for a comment provided with the command. |
4053 | 0 | if (cm::optional<std::string> comment = ccg.GetComment()) { |
4054 | 0 | return *comment; |
4055 | 0 | } |
4056 | | |
4057 | | // Construct a reasonable default comment if possible. |
4058 | 0 | if (!ccg.GetOutputs().empty()) { |
4059 | 0 | std::string comment; |
4060 | 0 | comment = "Generating "; |
4061 | 0 | char const* sep = ""; |
4062 | 0 | for (std::string const& o : ccg.GetOutputs()) { |
4063 | 0 | comment += sep; |
4064 | 0 | comment += this->MaybeRelativeToCurBinDir(o); |
4065 | 0 | sep = ", "; |
4066 | 0 | } |
4067 | 0 | return comment; |
4068 | 0 | } |
4069 | | |
4070 | | // Otherwise use the provided default. |
4071 | 0 | return default_comment; |
4072 | 0 | } |
4073 | | |
4074 | | class cmInstallTargetGeneratorLocal : public cmInstallTargetGenerator |
4075 | | { |
4076 | | public: |
4077 | | cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t, |
4078 | | std::string const& dest, bool implib) |
4079 | 0 | : cmInstallTargetGenerator( |
4080 | 0 | t, dest, implib, "", std::vector<std::string>(), "Unspecified", |
4081 | 0 | cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), false, |
4082 | 0 | false) |
4083 | 0 | { |
4084 | 0 | this->Compute(lg); |
4085 | 0 | } |
4086 | | }; |
4087 | | |
4088 | | void cmLocalGenerator::GenerateTargetInstallRules( |
4089 | | std::ostream& os, std::string const& config, |
4090 | | std::vector<std::string> const& configurationTypes) |
4091 | 0 | { |
4092 | | // Convert the old-style install specification from each target to |
4093 | | // an install generator and run it. |
4094 | 0 | auto const& tgts = this->GetGeneratorTargets(); |
4095 | 0 | for (auto const& l : tgts) { |
4096 | 0 | if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { |
4097 | 0 | continue; |
4098 | 0 | } |
4099 | | |
4100 | | // Include the user-specified pre-install script for this target. |
4101 | 0 | if (cmValue preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) { |
4102 | 0 | cmInstallScriptGenerator g(*preinstall, false, "", false, false); |
4103 | 0 | g.Generate(os, config, configurationTypes); |
4104 | 0 | } |
4105 | | |
4106 | | // Install this target if a destination is given. |
4107 | 0 | if (!l->Target->GetInstallPath().empty()) { |
4108 | | // Compute the full install destination. Note that converting |
4109 | | // to unix slashes also removes any trailing slash. |
4110 | | // We also skip over the leading slash given by the user. |
4111 | 0 | std::string destination = l->Target->GetInstallPath().substr(1); |
4112 | 0 | cmSystemTools::ConvertToUnixSlashes(destination); |
4113 | 0 | if (destination.empty()) { |
4114 | 0 | destination = "."; |
4115 | 0 | } |
4116 | | |
4117 | | // Generate the proper install generator for this target type. |
4118 | 0 | switch (l->GetType()) { |
4119 | 0 | case cmStateEnums::EXECUTABLE: |
4120 | 0 | case cmStateEnums::STATIC_LIBRARY: |
4121 | 0 | case cmStateEnums::MODULE_LIBRARY: { |
4122 | | // Use a target install generator. |
4123 | 0 | cmInstallTargetGeneratorLocal g(this, l->GetName(), destination, |
4124 | 0 | false); |
4125 | 0 | g.Generate(os, config, configurationTypes); |
4126 | 0 | } break; |
4127 | 0 | case cmStateEnums::SHARED_LIBRARY: { |
4128 | | #if defined(_WIN32) || defined(__CYGWIN__) |
4129 | | // Special code to handle DLL. Install the import library |
4130 | | // to the normal destination and the DLL to the runtime |
4131 | | // destination. |
4132 | | cmInstallTargetGeneratorLocal g1(this, l->GetName(), destination, |
4133 | | true); |
4134 | | g1.Generate(os, config, configurationTypes); |
4135 | | // We also skip over the leading slash given by the user. |
4136 | | destination = l->Target->GetRuntimeInstallPath().substr(1); |
4137 | | cmSystemTools::ConvertToUnixSlashes(destination); |
4138 | | cmInstallTargetGeneratorLocal g2(this, l->GetName(), destination, |
4139 | | false); |
4140 | | g2.Generate(os, config, configurationTypes); |
4141 | | #else |
4142 | | // Use a target install generator. |
4143 | 0 | cmInstallTargetGeneratorLocal g(this, l->GetName(), destination, |
4144 | 0 | false); |
4145 | 0 | g.Generate(os, config, configurationTypes); |
4146 | 0 | #endif |
4147 | 0 | } break; |
4148 | 0 | default: |
4149 | 0 | break; |
4150 | 0 | } |
4151 | 0 | } |
4152 | | |
4153 | | // Include the user-specified post-install script for this target. |
4154 | 0 | if (cmValue postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) { |
4155 | 0 | cmInstallScriptGenerator g(*postinstall, false, "", false, false); |
4156 | 0 | g.Generate(os, config, configurationTypes); |
4157 | 0 | } |
4158 | 0 | } |
4159 | 0 | } |
4160 | | |
4161 | | namespace { |
4162 | | bool cmLocalGeneratorShortenObjectName(std::string& objName, |
4163 | | std::string::size_type max_len) |
4164 | 0 | { |
4165 | | // Check if the path can be shortened using an md5 sum replacement for |
4166 | | // a portion of the path. |
4167 | 0 | std::string::size_type md5Len = 32; |
4168 | 0 | std::string::size_type numExtraChars = objName.size() - max_len + md5Len; |
4169 | 0 | std::string::size_type pos = objName.find('/', numExtraChars); |
4170 | 0 | if (pos == std::string::npos) { |
4171 | 0 | pos = objName.rfind('/', numExtraChars); |
4172 | 0 | if (pos == std::string::npos || pos <= md5Len) { |
4173 | 0 | return false; |
4174 | 0 | } |
4175 | 0 | } |
4176 | | |
4177 | | // Replace the beginning of the path portion of the object name with |
4178 | | // its own md5 sum. |
4179 | 0 | cmCryptoHash md5(cmCryptoHash::AlgoMD5); |
4180 | 0 | std::string md5name = cmStrCat(md5.HashString(objName.substr(0, pos)), |
4181 | 0 | cm::string_view(objName).substr(pos)); |
4182 | 0 | objName = md5name; |
4183 | | |
4184 | | // The object name is now shorter, check if it is short enough. |
4185 | 0 | return pos >= numExtraChars; |
4186 | 0 | } |
4187 | | |
4188 | | bool cmLocalGeneratorCheckObjectName(std::string& objName, |
4189 | | std::string::size_type dir_len, |
4190 | | std::string::size_type max_total_len) |
4191 | 0 | { |
4192 | | // Enforce the maximum file name length if possible. |
4193 | 0 | std::string::size_type max_obj_len = max_total_len; |
4194 | 0 | if (dir_len < max_total_len) { |
4195 | 0 | max_obj_len = max_total_len - dir_len; |
4196 | 0 | if (objName.size() > max_obj_len) { |
4197 | | // The current object file name is too long. Try to shorten it. |
4198 | 0 | return cmLocalGeneratorShortenObjectName(objName, max_obj_len); |
4199 | 0 | } |
4200 | | // The object file name is short enough. |
4201 | 0 | return true; |
4202 | 0 | } |
4203 | | // The build directory in which the object will be stored is |
4204 | | // already too deep. |
4205 | 0 | return false; |
4206 | 0 | } |
4207 | | } |
4208 | | |
4209 | | std::string cmLocalGenerator::CreateSafeObjectFileName( |
4210 | | std::string const& sin) const |
4211 | 0 | { |
4212 | | // Start with the original name. |
4213 | 0 | std::string ssin = sin; |
4214 | | |
4215 | | // Avoid full paths by removing leading slashes. |
4216 | 0 | ssin.erase(0, ssin.find_first_not_of('/')); |
4217 | | |
4218 | | // Avoid full paths by removing colons. |
4219 | 0 | std::replace(ssin.begin(), ssin.end(), ':', '_'); |
4220 | | |
4221 | | // Avoid relative paths that go up the tree. |
4222 | 0 | cmSystemTools::ReplaceString(ssin, "../", "__/"); |
4223 | | |
4224 | | // Avoid spaces. |
4225 | 0 | std::replace(ssin.begin(), ssin.end(), ' ', '_'); |
4226 | |
|
4227 | 0 | return ssin; |
4228 | 0 | } |
4229 | | |
4230 | | void cmLocalGenerator::ComputeSourceGroupSearchIndex() |
4231 | 0 | { |
4232 | 0 | #if !defined(CMAKE_BOOTSTRAP) |
4233 | 0 | SourceGroupVector const& sourceGroups = this->Makefile->GetSourceGroups(); |
4234 | | |
4235 | | // Build lookup index from sources to source groups |
4236 | 0 | std::queue<cmSourceGroup*> sgToVisit; |
4237 | 0 | for (auto const& group : sourceGroups) { |
4238 | 0 | cmSourceGroup* cmSourceGroup = group.get(); |
4239 | 0 | sgToVisit.emplace(cmSourceGroup); |
4240 | 0 | } |
4241 | |
|
4242 | 0 | while (!sgToVisit.empty()) { |
4243 | 0 | cmSourceGroup* sourceGroup = sgToVisit.front(); |
4244 | 0 | sgToVisit.pop(); |
4245 | 0 | for (auto const& sgChild : sourceGroup->GetGroupChildren()) { |
4246 | 0 | sgToVisit.emplace(sgChild.get()); |
4247 | 0 | } |
4248 | 0 | for (std::string const& source : sourceGroup->GetGroupFiles()) { |
4249 | 0 | this->SourceGroupSearchIndex.emplace(source, sourceGroup); |
4250 | 0 | } |
4251 | 0 | } |
4252 | 0 | #endif |
4253 | 0 | } |
4254 | | |
4255 | | cmSourceGroup* cmLocalGenerator::FindSourceGroup(std::string const& source) |
4256 | 0 | { |
4257 | 0 | #if !defined(CMAKE_BOOTSTRAP) |
4258 | 0 | auto const indexIt = SourceGroupSearchIndex.find(source); |
4259 | 0 | if (indexIt != SourceGroupSearchIndex.cend()) { |
4260 | 0 | if (cmSourceGroup* result = indexIt->second) { |
4261 | 0 | return result; |
4262 | 0 | } |
4263 | 0 | } |
4264 | | |
4265 | 0 | cmSourceGroup* sourceGroup = |
4266 | 0 | cmSourceGroup::FindSourceGroup(source, this->Makefile->GetSourceGroups()); |
4267 | 0 | if (sourceGroup) { |
4268 | | // Update index if we have a miss |
4269 | 0 | SourceGroupSearchIndex.emplace(source, sourceGroup); |
4270 | 0 | } |
4271 | 0 | return sourceGroup; |
4272 | | #else |
4273 | | static_cast<void>(source); |
4274 | | return nullptr; |
4275 | | #endif |
4276 | 0 | } |
4277 | | |
4278 | | std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName( |
4279 | | std::string const& sin, std::string const& dir_max) |
4280 | 0 | { |
4281 | | // Look for an existing mapped name for this object file. |
4282 | 0 | auto it = this->UniqueObjectNamesMap.find(sin); |
4283 | | |
4284 | | // If no entry exists create one. |
4285 | 0 | if (it == this->UniqueObjectNamesMap.end()) { |
4286 | 0 | auto ssin = this->CreateSafeObjectFileName(sin); |
4287 | | |
4288 | | // Mangle the name if necessary. |
4289 | 0 | if (this->Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES")) { |
4290 | 0 | bool done; |
4291 | 0 | int cc = 0; |
4292 | 0 | char rpstr[100]; |
4293 | 0 | snprintf(rpstr, sizeof(rpstr), "_p_"); |
4294 | 0 | cmSystemTools::ReplaceString(ssin, "+", rpstr); |
4295 | 0 | std::string sssin = sin; |
4296 | 0 | do { |
4297 | 0 | done = true; |
4298 | 0 | for (it = this->UniqueObjectNamesMap.begin(); |
4299 | 0 | it != this->UniqueObjectNamesMap.end(); ++it) { |
4300 | 0 | if (it->second == ssin) { |
4301 | 0 | done = false; |
4302 | 0 | } |
4303 | 0 | } |
4304 | 0 | if (done) { |
4305 | 0 | break; |
4306 | 0 | } |
4307 | 0 | sssin = ssin; |
4308 | 0 | cmSystemTools::ReplaceString(ssin, "_p_", rpstr); |
4309 | 0 | snprintf(rpstr, sizeof(rpstr), "_p%d_", cc++); |
4310 | 0 | } while (!done); |
4311 | 0 | } |
4312 | |
|
4313 | 0 | if (!cmLocalGeneratorCheckObjectName(ssin, dir_max.size(), |
4314 | 0 | this->ObjectPathMax)) { |
4315 | | // Warn if this is the first time the path has been seen. |
4316 | 0 | if (this->ObjectMaxPathViolations.insert(dir_max).second) { |
4317 | 0 | std::ostringstream m; |
4318 | | /* clang-format off */ |
4319 | 0 | m << "The object file directory\n" |
4320 | 0 | << " " << dir_max << "\n" |
4321 | 0 | << "has " << dir_max.size() << " characters. " |
4322 | 0 | << "The maximum full path to an object file is " |
4323 | 0 | << this->ObjectPathMax << " characters " |
4324 | 0 | << "(see CMAKE_OBJECT_PATH_MAX). " |
4325 | 0 | << "Object file\n" |
4326 | 0 | << " " << ssin << "\n" |
4327 | 0 | << "cannot be safely placed under this directory. " |
4328 | 0 | << "The build may not work correctly."; |
4329 | | /* clang-format on */ |
4330 | 0 | this->IssueMessage(MessageType::WARNING, m.str()); |
4331 | 0 | } |
4332 | 0 | } |
4333 | | |
4334 | | // Insert the newly mapped object file name. |
4335 | 0 | std::map<std::string, std::string>::value_type e(sin, ssin); |
4336 | 0 | it = this->UniqueObjectNamesMap.insert(e).first; |
4337 | 0 | } |
4338 | | |
4339 | | // Return the map entry. |
4340 | 0 | return it->second; |
4341 | 0 | } |
4342 | | |
4343 | | void cmLocalGenerator::ComputeObjectFilenames( |
4344 | | std::map<cmSourceFile const*, cmObjectLocations>& /*unused*/, |
4345 | | std::string const& /*unused*/, cmGeneratorTarget const* /*unused*/) |
4346 | 0 | { |
4347 | 0 | } |
4348 | | |
4349 | | bool cmLocalGenerator::IsWindowsShell() const |
4350 | 0 | { |
4351 | 0 | return this->GetState()->UseWindowsShell(); |
4352 | 0 | } |
4353 | | |
4354 | | bool cmLocalGenerator::IsWatcomWMake() const |
4355 | 0 | { |
4356 | 0 | return this->GetState()->UseWatcomWMake(); |
4357 | 0 | } |
4358 | | |
4359 | | bool cmLocalGenerator::IsMinGWMake() const |
4360 | 0 | { |
4361 | 0 | return this->GetState()->UseMinGWMake(); |
4362 | 0 | } |
4363 | | |
4364 | | bool cmLocalGenerator::IsNMake() const |
4365 | 0 | { |
4366 | 0 | return this->GetState()->UseNMake(); |
4367 | 0 | } |
4368 | | |
4369 | | bool cmLocalGenerator::IsNinjaMulti() const |
4370 | 0 | { |
4371 | 0 | return this->GetState()->UseNinjaMulti(); |
4372 | 0 | } |
4373 | | |
4374 | | bool cmLocalGenerator::IsWindowsVSIDE() const |
4375 | 0 | { |
4376 | 0 | return this->GetState()->UseWindowsVSIDE(); |
4377 | 0 | } |
4378 | | |
4379 | | namespace { |
4380 | | std::string relativeIfUnder(std::string const& top, std::string const& cur, |
4381 | | std::string const& path) |
4382 | 0 | { |
4383 | | // Use a path relative to 'cur' if it can be expressed without |
4384 | | // a `../` sequence that leaves 'top'. |
4385 | 0 | if (cmSystemTools::IsSubDirectory(path, cur) || |
4386 | 0 | (cmSystemTools::IsSubDirectory(cur, top) && |
4387 | 0 | cmSystemTools::IsSubDirectory(path, top))) { |
4388 | 0 | return cmSystemTools::ForceToRelativePath(cur, path); |
4389 | 0 | } |
4390 | 0 | return path; |
4391 | 0 | } |
4392 | | } |
4393 | | |
4394 | | std::string cmLocalGenerator::GetRelativeSourceFileName( |
4395 | | cmSourceFile const& source) const |
4396 | 0 | { |
4397 | | // Construct the object file name using the full path to the source |
4398 | | // file which is its only unique identification. |
4399 | 0 | std::string const& fullPath = source.GetFullPath(); |
4400 | | |
4401 | | // Try referencing the source relative to the source tree. |
4402 | 0 | std::string relFromSource = relativeIfUnder( |
4403 | 0 | this->GetSourceDirectory(), this->GetCurrentSourceDirectory(), fullPath); |
4404 | 0 | assert(!relFromSource.empty()); |
4405 | 0 | bool relSource = !cmSystemTools::FileIsFullPath(relFromSource); |
4406 | 0 | bool subSource = relSource && relFromSource[0] != '.'; |
4407 | | |
4408 | | // Try referencing the source relative to the binary tree. |
4409 | 0 | std::string relFromBinary = relativeIfUnder( |
4410 | 0 | this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory(), fullPath); |
4411 | 0 | assert(!relFromBinary.empty()); |
4412 | 0 | bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary); |
4413 | 0 | bool subBinary = relBinary && relFromBinary[0] != '.'; |
4414 | | |
4415 | | // Select a nice-looking reference to the source file to construct |
4416 | | // the object file name. |
4417 | 0 | std::string objectName; |
4418 | | // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 |
4419 | | // NOLINTNEXTLINE(bugprone-branch-clone) |
4420 | 0 | if ((relSource && !relBinary) || (subSource && !subBinary)) { |
4421 | 0 | objectName = relFromSource; |
4422 | 0 | } else if ((relBinary && !relSource) || (subBinary && !subSource) || |
4423 | 0 | relFromBinary.length() < relFromSource.length()) { |
4424 | 0 | objectName = relFromBinary; |
4425 | 0 | } else { |
4426 | 0 | objectName = relFromSource; |
4427 | 0 | } |
4428 | 0 | return objectName; |
4429 | 0 | } |
4430 | | |
4431 | | std::string cmLocalGenerator::GetCustomObjectFileName( |
4432 | | cmSourceFile const& source) const |
4433 | 0 | { |
4434 | 0 | if (!this->GetGlobalGenerator()->SupportsCustomObjectNames()) { |
4435 | 0 | return std::string{}; |
4436 | 0 | } |
4437 | | |
4438 | 0 | if (auto objName = source.GetProperty("OBJECT_NAME")) { |
4439 | 0 | cmGeneratorExpression ge(*this->GetCMakeInstance()); |
4440 | 0 | auto cge = ge.Parse(objName); |
4441 | 0 | static std::string const INVALID_GENEX = |
4442 | 0 | "_cmake_invalid_object_name_genex"; |
4443 | 0 | static std::string const INVALID_VALUE = |
4444 | 0 | "_cmake_invalid_object_name_value"; |
4445 | |
|
4446 | 0 | if (!cge) { |
4447 | 0 | this->Makefile->IssueMessage( |
4448 | 0 | MessageType::FATAL_ERROR, |
4449 | 0 | cmStrCat("The \"OBJECT_NAME\" property for\n ", source.GetFullPath(), |
4450 | 0 | "\nis not a valid generator expression (", objName, ").")); |
4451 | 0 | return INVALID_GENEX; |
4452 | 0 | } |
4453 | 0 | if (cge->GetHadHeadSensitiveCondition()) { |
4454 | | // Not reachable; all target-sensitive genexes actually fail to parse. |
4455 | 0 | this->Makefile->IssueMessage( |
4456 | 0 | MessageType::FATAL_ERROR, |
4457 | 0 | cmStrCat("The \"OBJECT_NAME\" property for\n ", source.GetFullPath(), |
4458 | 0 | "\ncontains a condition that queries the consuming target " |
4459 | 0 | "which is not supported (", |
4460 | 0 | objName, ").")); |
4461 | 0 | return INVALID_GENEX; |
4462 | 0 | } |
4463 | 0 | if (cge->GetHadLinkLanguageSensitiveCondition()) { |
4464 | | // Not reachable; all target-sensitive genexes actually fail to parse. |
4465 | 0 | this->Makefile->IssueMessage( |
4466 | 0 | MessageType::FATAL_ERROR, |
4467 | 0 | cmStrCat("The \"OBJECT_NAME\" property for\n ", source.GetFullPath(), |
4468 | 0 | "\ncontains a condition that queries the link language " |
4469 | 0 | "which is not supported (", |
4470 | 0 | objName, ").")); |
4471 | 0 | return INVALID_GENEX; |
4472 | 0 | } |
4473 | | |
4474 | 0 | auto objNameValue = cge->Evaluate(this, ""); |
4475 | 0 | if (cge->GetHadContextSensitiveCondition()) { |
4476 | 0 | this->Makefile->IssueMessage( |
4477 | 0 | MessageType::FATAL_ERROR, |
4478 | 0 | cmStrCat("The \"OBJECT_NAME\" property for\n ", source.GetFullPath(), |
4479 | 0 | "\ncontains a context-sensitive condition which is not " |
4480 | 0 | "supported (", |
4481 | 0 | objName, ").")); |
4482 | 0 | return INVALID_GENEX; |
4483 | 0 | } |
4484 | | |
4485 | | // Skip if it evaluates to empty. |
4486 | 0 | if (!objNameValue.empty()) { |
4487 | 0 | cmCMakePath objNamePath = objNameValue; |
4488 | | // Verify that it is a relative path. |
4489 | 0 | if (objNamePath.IsAbsolute()) { |
4490 | 0 | this->Makefile->IssueMessage( |
4491 | 0 | MessageType::FATAL_ERROR, |
4492 | 0 | cmStrCat( |
4493 | 0 | "The \"OBJECT_NAME\" property for\n ", source.GetFullPath(), |
4494 | 0 | "\nresolves to an absolute path which is not supported:\n ", |
4495 | 0 | objNameValue)); |
4496 | 0 | return INVALID_VALUE; |
4497 | 0 | } |
4498 | 0 | auto isInvalidComponent = [](cmCMakePath const& component) -> bool { |
4499 | 0 | return component == ".."_s; |
4500 | 0 | }; |
4501 | | // Verify that it contains no `..` components. |
4502 | 0 | if (std::any_of(objNamePath.begin(), objNamePath.end(), |
4503 | 0 | isInvalidComponent)) { |
4504 | 0 | this->Makefile->IssueMessage( |
4505 | 0 | MessageType::FATAL_ERROR, |
4506 | 0 | cmStrCat("The \"OBJECT_NAME\" property for\n ", |
4507 | 0 | source.GetFullPath(), "\ncontains an invalid component (", |
4508 | 0 | objNameValue, ").")); |
4509 | 0 | return INVALID_VALUE; |
4510 | 0 | } |
4511 | | |
4512 | 0 | return objNameValue; |
4513 | 0 | } |
4514 | 0 | } |
4515 | | |
4516 | 0 | return std::string{}; |
4517 | 0 | } |
4518 | | |
4519 | | std::string cmLocalGenerator::GetCustomInstallObjectFileName( |
4520 | | cmSourceFile const& source, std::string const& config, |
4521 | | char const* custom_ext) const |
4522 | 0 | { |
4523 | 0 | if (auto objName = source.GetProperty("INSTALL_OBJECT_NAME")) { |
4524 | 0 | cmGeneratorExpression ge(*this->GetCMakeInstance()); |
4525 | 0 | auto cge = ge.Parse(objName); |
4526 | 0 | static std::string const INVALID_GENEX = |
4527 | 0 | "_cmake_invalid_object_name_genex"; |
4528 | 0 | static std::string const INVALID_VALUE = |
4529 | 0 | "_cmake_invalid_object_name_value"; |
4530 | |
|
4531 | 0 | if (!cge) { |
4532 | 0 | this->Makefile->IssueMessage( |
4533 | 0 | MessageType::FATAL_ERROR, |
4534 | 0 | cmStrCat("The \"INSTALL_OBJECT_NAME\" property for\n ", |
4535 | 0 | source.GetFullPath(), |
4536 | 0 | "\nis not a valid generator expression (", objName, ").")); |
4537 | 0 | return INVALID_GENEX; |
4538 | 0 | } |
4539 | 0 | if (cge->GetHadHeadSensitiveCondition()) { |
4540 | | // Not reachable; all target-sensitive genexes actually fail to parse. |
4541 | 0 | this->Makefile->IssueMessage( |
4542 | 0 | MessageType::FATAL_ERROR, |
4543 | 0 | cmStrCat("The \"INSTALL_OBJECT_NAME\" property for\n ", |
4544 | 0 | source.GetFullPath(), |
4545 | 0 | "\ncontains a condition that queries the consuming target " |
4546 | 0 | "which is not supported (", |
4547 | 0 | objName, ").")); |
4548 | 0 | return INVALID_GENEX; |
4549 | 0 | } |
4550 | 0 | if (cge->GetHadLinkLanguageSensitiveCondition()) { |
4551 | | // Not reachable; all target-sensitive genexes actually fail to parse. |
4552 | 0 | this->Makefile->IssueMessage( |
4553 | 0 | MessageType::FATAL_ERROR, |
4554 | 0 | cmStrCat("The \"INSTALL_OBJECT_NAME\" property for\n ", |
4555 | 0 | source.GetFullPath(), |
4556 | 0 | "\ncontains a condition that queries the link language " |
4557 | 0 | "which is not supported (", |
4558 | 0 | objName, ").")); |
4559 | 0 | return INVALID_GENEX; |
4560 | 0 | } |
4561 | | |
4562 | 0 | auto objNameValue = cge->Evaluate(this, config); |
4563 | | |
4564 | | // Skip if it evaluates to empty. |
4565 | 0 | if (!objNameValue.empty()) { |
4566 | 0 | cmCMakePath objNamePath = objNameValue; |
4567 | | // Verify that it is a relative path. |
4568 | 0 | if (objNamePath.IsAbsolute()) { |
4569 | 0 | this->Makefile->IssueMessage( |
4570 | 0 | MessageType::FATAL_ERROR, |
4571 | 0 | cmStrCat( |
4572 | 0 | "The \"INSTALL_OBJECT_NAME\" property for\n ", |
4573 | 0 | source.GetFullPath(), |
4574 | 0 | "\nresolves to an absolute path which is not supported:\n ", |
4575 | 0 | objNameValue)); |
4576 | 0 | return INVALID_VALUE; |
4577 | 0 | } |
4578 | 0 | auto isInvalidComponent = [](cmCMakePath const& component) -> bool { |
4579 | 0 | return component == ".."_s; |
4580 | 0 | }; |
4581 | | // Verify that it contains no `..` components. |
4582 | 0 | if (std::any_of(objNamePath.begin(), objNamePath.end(), |
4583 | 0 | isInvalidComponent)) { |
4584 | 0 | this->Makefile->IssueMessage( |
4585 | 0 | MessageType::FATAL_ERROR, |
4586 | 0 | cmStrCat("The \"INSTALL_OBJECT_NAME\" property for\n ", |
4587 | 0 | source.GetFullPath(), "\ncontains an invalid component (", |
4588 | 0 | objNameValue, ").")); |
4589 | 0 | return INVALID_VALUE; |
4590 | 0 | } |
4591 | | |
4592 | 0 | if (custom_ext) { |
4593 | 0 | objNameValue += custom_ext; |
4594 | 0 | } else { |
4595 | 0 | objNameValue += |
4596 | 0 | this->GetGlobalGenerator()->GetLanguageOutputExtension(source); |
4597 | 0 | } |
4598 | |
|
4599 | 0 | return objNameValue; |
4600 | 0 | } |
4601 | 0 | } |
4602 | | |
4603 | 0 | return std::string{}; |
4604 | 0 | } |
4605 | | |
4606 | | void cmLocalGenerator::FillCustomInstallObjectLocations( |
4607 | | cmSourceFile const& source, std::string const& config, |
4608 | | char const* custom_ext, |
4609 | | std::map<std::string, cmObjectLocation>& mapping) const |
4610 | 0 | { |
4611 | 0 | auto installLoc = |
4612 | 0 | this->GetCustomInstallObjectFileName(source, config, custom_ext); |
4613 | 0 | if (!installLoc.empty()) { |
4614 | 0 | mapping[config] = installLoc; |
4615 | 0 | } |
4616 | 0 | } |
4617 | | |
4618 | | std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( |
4619 | | cmSourceFile const& source, std::string const& dir_max, |
4620 | | bool* hasSourceExtension, char const* customOutputExtension, |
4621 | | bool const* forceShortObjectName) |
4622 | 0 | { |
4623 | 0 | bool useShortObjectNames = this->UseShortObjectNames(); |
4624 | 0 | if (forceShortObjectName) { |
4625 | 0 | useShortObjectNames = *forceShortObjectName; |
4626 | 0 | } |
4627 | |
|
4628 | 0 | if (!useShortObjectNames && |
4629 | 0 | this->GetGlobalGenerator()->SupportsCustomObjectNames()) { |
4630 | 0 | auto customName = this->GetCustomObjectFileName(source); |
4631 | 0 | if (!customName.empty()) { |
4632 | 0 | auto ext = this->GlobalGenerator->GetLanguageOutputExtension(source); |
4633 | 0 | if (customOutputExtension) { |
4634 | 0 | ext = *customOutputExtension; |
4635 | 0 | } |
4636 | 0 | return cmStrCat(customName, ext); |
4637 | 0 | } |
4638 | 0 | } |
4639 | | |
4640 | | // This can return an absolute path in the case where source is |
4641 | | // not relative to the current source or binary directories |
4642 | 0 | std::string objectName = this->GetRelativeSourceFileName(source); |
4643 | | // if it is still a full path check for the try compile case |
4644 | | // try compile never have in source sources, and should not |
4645 | | // have conflicting source file names in the same target |
4646 | 0 | if (cmSystemTools::FileIsFullPath(objectName)) { |
4647 | 0 | if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) { |
4648 | 0 | objectName = cmSystemTools::GetFilenameName(source.GetFullPath()); |
4649 | 0 | } |
4650 | 0 | } |
4651 | 0 | bool const isPchObject = source.IsPchHeader() || source.IsPchSource(); |
4652 | | |
4653 | | // Short object path policy selected, use as little info as necessary to |
4654 | | // select an object name |
4655 | 0 | bool keptSourceExtension = true; |
4656 | 0 | if (useShortObjectNames) { |
4657 | 0 | objectName = this->GetShortObjectFileName(source); |
4658 | 0 | keptSourceExtension = false; |
4659 | 0 | } |
4660 | | |
4661 | | // Ensure that for the CMakeFiles/<target>.dir/generated_source_file |
4662 | | // we don't end up having: |
4663 | | // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj |
4664 | 0 | cmValue unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE"); |
4665 | 0 | cmValue pchExtension = source.GetProperty("PCH_EXTENSION"); |
4666 | 0 | if (unitySourceFile || pchExtension || isPchObject) { |
4667 | 0 | if (pchExtension) { |
4668 | 0 | customOutputExtension = pchExtension->c_str(); |
4669 | 0 | } |
4670 | |
|
4671 | 0 | cmsys::RegularExpression var("(CMakeFiles/[^/]+.dir/)"); |
4672 | 0 | if (var.find(objectName)) { |
4673 | 0 | objectName.erase(var.start(), var.end() - var.start()); |
4674 | 0 | } |
4675 | 0 | } |
4676 | | |
4677 | | // Replace the original source file extension with the object file |
4678 | | // extension. |
4679 | 0 | if (!source.GetPropertyAsBool("KEEP_EXTENSION")) { |
4680 | | // Decide whether this language wants to replace the source |
4681 | | // extension with the object extension. |
4682 | 0 | bool replaceExt = false; |
4683 | 0 | std::string lang = source.GetLanguage(); |
4684 | 0 | if (!lang.empty()) { |
4685 | 0 | replaceExt = this->Makefile->IsOn( |
4686 | 0 | cmStrCat("CMAKE_", lang, "_OUTPUT_EXTENSION_REPLACE")); |
4687 | 0 | } |
4688 | | |
4689 | | // Remove the source extension if it is to be replaced. |
4690 | 0 | if (replaceExt || customOutputExtension) { |
4691 | 0 | keptSourceExtension = false; |
4692 | 0 | std::string::size_type dot_pos = objectName.rfind('.'); |
4693 | 0 | if (dot_pos != std::string::npos) { |
4694 | 0 | objectName = objectName.substr(0, dot_pos); |
4695 | 0 | } |
4696 | 0 | } |
4697 | | |
4698 | | // Strip source file extension when shortening object file paths |
4699 | 0 | if (useShortObjectNames) { |
4700 | 0 | objectName = cmSystemTools::GetFilenameWithoutExtension(objectName); |
4701 | 0 | } |
4702 | | // Store the new extension. |
4703 | 0 | if (customOutputExtension) { |
4704 | 0 | objectName += customOutputExtension; |
4705 | 0 | } else { |
4706 | 0 | objectName += this->GlobalGenerator->GetLanguageOutputExtension(source); |
4707 | 0 | } |
4708 | 0 | } |
4709 | 0 | if (hasSourceExtension) { |
4710 | 0 | *hasSourceExtension = keptSourceExtension; |
4711 | 0 | } |
4712 | |
|
4713 | 0 | if (source.GetLanguage() == "Rust") { |
4714 | 0 | cmValue const rustEmit = source.GetRustEmitProperty(); |
4715 | | // Rust requires any rlib to start with lib prefix on all platforms to |
4716 | | // allow linking to them as crate. So we enforce having lib prefix for rust |
4717 | | // "object" files. |
4718 | 0 | if (rustEmit == "link") { |
4719 | 0 | cmCMakePath objectPath(objectName); |
4720 | 0 | std::string const objectFileName = |
4721 | 0 | "lib" + objectPath.GetFileName().String(); |
4722 | 0 | objectPath.ReplaceFileName(objectFileName); |
4723 | 0 | objectName = objectPath.String(); |
4724 | 0 | } |
4725 | 0 | } |
4726 | | |
4727 | | // Convert to a safe name. |
4728 | 0 | return this->CreateSafeUniqueObjectFileName(objectName, dir_max); |
4729 | 0 | } |
4730 | | |
4731 | | bool cmLocalGenerator::UseShortObjectNames( |
4732 | | cmStateEnums::IntermediateDirKind kind) const |
4733 | 0 | { |
4734 | 0 | return this->GlobalGenerator->UseShortObjectNames(kind); |
4735 | 0 | } |
4736 | | |
4737 | | std::string cmLocalGenerator::GetObjectOutputRoot( |
4738 | | cmStateEnums::IntermediateDirKind kind) const |
4739 | 0 | { |
4740 | 0 | if (this->UseShortObjectNames(kind)) { |
4741 | 0 | return cmStrCat(this->GetCurrentBinaryDirectory(), '/', |
4742 | 0 | this->GlobalGenerator->GetShortBinaryOutputDir()); |
4743 | 0 | } |
4744 | 0 | return cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles"); |
4745 | 0 | } |
4746 | | |
4747 | | bool cmLocalGenerator::AlwaysUsesCMFPaths() const |
4748 | 0 | { |
4749 | 0 | return true; |
4750 | 0 | } |
4751 | | |
4752 | | std::string cmLocalGenerator::GetShortObjectFileName( |
4753 | | cmSourceFile const& source) const |
4754 | 0 | { |
4755 | 0 | std::string objectName = this->GetRelativeSourceFileName(source); |
4756 | 0 | cmCryptoHash objNameHasher(cmCryptoHash::AlgoSHA3_512); |
4757 | 0 | std::string terseObjectName = |
4758 | 0 | objNameHasher.HashString(objectName).substr(0, 8); |
4759 | 0 | return terseObjectName; |
4760 | 0 | } |
4761 | | |
4762 | | std::string cmLocalGenerator::ComputeShortTargetDirectory( |
4763 | | cmGeneratorTarget const* target) const |
4764 | 0 | { |
4765 | 0 | auto const& tgtName = target->GetName(); |
4766 | 0 | return this->GetGlobalGenerator()->ComputeTargetShortName( |
4767 | 0 | this->GetCurrentBinaryDirectory(), tgtName); |
4768 | 0 | } |
4769 | | |
4770 | | std::string cmLocalGenerator::GetSourceFileLanguage(cmSourceFile const& source) |
4771 | 0 | { |
4772 | 0 | return source.GetLanguage(); |
4773 | 0 | } |
4774 | | |
4775 | | cmake* cmLocalGenerator::GetCMakeInstance() const |
4776 | 0 | { |
4777 | 0 | return this->GlobalGenerator->GetCMakeInstance(); |
4778 | 0 | } |
4779 | | |
4780 | | std::string const& cmLocalGenerator::GetSourceDirectory() const |
4781 | 0 | { |
4782 | 0 | return this->GetCMakeInstance()->GetHomeDirectory(); |
4783 | 0 | } |
4784 | | |
4785 | | std::string const& cmLocalGenerator::GetBinaryDirectory() const |
4786 | 0 | { |
4787 | 0 | return this->GetCMakeInstance()->GetHomeOutputDirectory(); |
4788 | 0 | } |
4789 | | |
4790 | | std::string const& cmLocalGenerator::GetCurrentBinaryDirectory() const |
4791 | 0 | { |
4792 | 0 | return this->StateSnapshot.GetDirectory().GetCurrentBinary(); |
4793 | 0 | } |
4794 | | |
4795 | | std::string const& cmLocalGenerator::GetCurrentSourceDirectory() const |
4796 | 0 | { |
4797 | 0 | return this->StateSnapshot.GetDirectory().GetCurrentSource(); |
4798 | 0 | } |
4799 | | |
4800 | | std::string cmLocalGenerator::GetTargetDirectory( |
4801 | | cmGeneratorTarget const* /*unused*/, |
4802 | | cmStateEnums::IntermediateDirKind /*kind*/) const |
4803 | 0 | { |
4804 | 0 | cmSystemTools::Error("GetTargetDirectory" |
4805 | 0 | " called on cmLocalGenerator"); |
4806 | 0 | return ""; |
4807 | 0 | } |
4808 | | |
4809 | | cmPolicies::PolicyStatus cmLocalGenerator::GetPolicyStatus( |
4810 | | cmPolicies::PolicyID id) const |
4811 | 0 | { |
4812 | 0 | return this->Makefile->GetPolicyStatus(id); |
4813 | 0 | } |
4814 | | |
4815 | | bool cmLocalGenerator::CheckDefinition(std::string const& define) const |
4816 | 0 | { |
4817 | | // Many compilers do not support -DNAME(arg)=sdf so we disable it. |
4818 | 0 | std::string::size_type pos = define.find_first_of("(="); |
4819 | 0 | if (pos != std::string::npos) { |
4820 | 0 | if (define[pos] == '(') { |
4821 | 0 | std::ostringstream e; |
4822 | | /* clang-format off */ |
4823 | 0 | e << "WARNING: Function-style preprocessor definitions may not be " |
4824 | 0 | "passed on the compiler command line because many compilers " |
4825 | 0 | "do not support it.\n" |
4826 | 0 | "CMake is dropping a preprocessor definition: " << define << "\n" |
4827 | 0 | "Consider defining the macro in a (configured) header file.\n"; |
4828 | | /* clang-format on */ |
4829 | 0 | cmSystemTools::Message(e.str()); |
4830 | 0 | return false; |
4831 | 0 | } |
4832 | 0 | } |
4833 | | |
4834 | | // Many compilers do not support # in the value so we disable it. |
4835 | 0 | if (define.find_first_of('#') != std::string::npos) { |
4836 | 0 | std::ostringstream e; |
4837 | | /* clang-format off */ |
4838 | 0 | e << "WARNING: Preprocessor definitions containing '#' may not be " |
4839 | 0 | "passed on the compiler command line because many compilers " |
4840 | 0 | "do not support it.\n" |
4841 | 0 | "CMake is dropping a preprocessor definition: " << define << "\n" |
4842 | 0 | "Consider defining the macro in a (configured) header file.\n"; |
4843 | | /* clang-format on */ |
4844 | 0 | cmSystemTools::Message(e.str()); |
4845 | 0 | return false; |
4846 | 0 | } |
4847 | | |
4848 | | // Assume it is supported. |
4849 | 0 | return true; |
4850 | 0 | } |
4851 | | |
4852 | | static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target, |
4853 | | std::string const& prop) |
4854 | 0 | { |
4855 | 0 | if (cmValue val = target->GetProperty(prop)) { |
4856 | 0 | mf->AddDefinition(prop, *val); |
4857 | 0 | } |
4858 | 0 | } |
4859 | | |
4860 | | void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target, |
4861 | | std::string const& targetName, |
4862 | | std::string const& fname) |
4863 | 0 | { |
4864 | | // Find the Info.plist template. |
4865 | 0 | cmValue in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST"); |
4866 | 0 | std::string inFile = cmNonempty(in) ? *in : "MacOSXBundleInfo.plist.in"; |
4867 | 0 | if (!cmSystemTools::FileIsFullPath(inFile)) { |
4868 | 0 | std::string inMod = this->Makefile->GetModulesFile(inFile); |
4869 | 0 | if (!inMod.empty()) { |
4870 | 0 | inFile = inMod; |
4871 | 0 | } |
4872 | 0 | } |
4873 | 0 | if (!cmSystemTools::FileExists(inFile, true)) { |
4874 | 0 | std::ostringstream e; |
4875 | 0 | e << "Target " << target->GetName() << " Info.plist template \"" << inFile |
4876 | 0 | << "\" could not be found."; |
4877 | 0 | cmSystemTools::Error(e.str()); |
4878 | 0 | return; |
4879 | 0 | } |
4880 | | |
4881 | | // Convert target properties to variables in an isolated makefile |
4882 | | // scope to configure the file. If properties are set they will |
4883 | | // override user make variables. If not the configuration will fall |
4884 | | // back to the directory-level values set by the user. |
4885 | 0 | cmMakefile* mf = this->Makefile; |
4886 | 0 | cmMakefile::ScopePushPop varScope(mf); |
4887 | 0 | mf->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", targetName); |
4888 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_INFO_STRING"); |
4889 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_ICON_FILE"); |
4890 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_GUI_IDENTIFIER"); |
4891 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_LONG_VERSION_STRING"); |
4892 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_NAME"); |
4893 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING"); |
4894 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION"); |
4895 | 0 | cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT"); |
4896 | 0 | mf->ConfigureFile(inFile, fname, false, false, false); |
4897 | 0 | } |
4898 | | |
4899 | | void cmLocalGenerator::GenerateFrameworkInfoPList( |
4900 | | cmGeneratorTarget* target, std::string const& targetName, |
4901 | | std::string const& fname) |
4902 | 0 | { |
4903 | | // Find the Info.plist template. |
4904 | 0 | cmValue in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST"); |
4905 | 0 | std::string inFile = cmNonempty(in) ? *in : "MacOSXFrameworkInfo.plist.in"; |
4906 | 0 | if (!cmSystemTools::FileIsFullPath(inFile)) { |
4907 | 0 | std::string inMod = this->Makefile->GetModulesFile(inFile); |
4908 | 0 | if (!inMod.empty()) { |
4909 | 0 | inFile = inMod; |
4910 | 0 | } |
4911 | 0 | } |
4912 | 0 | if (!cmSystemTools::FileExists(inFile, true)) { |
4913 | 0 | std::ostringstream e; |
4914 | 0 | e << "Target " << target->GetName() << " Info.plist template \"" << inFile |
4915 | 0 | << "\" could not be found."; |
4916 | 0 | cmSystemTools::Error(e.str()); |
4917 | 0 | return; |
4918 | 0 | } |
4919 | | |
4920 | | // Convert target properties to variables in an isolated makefile |
4921 | | // scope to configure the file. If properties are set they will |
4922 | | // override user make variables. If not the configuration will fall |
4923 | | // back to the directory-level values set by the user. |
4924 | 0 | cmMakefile* mf = this->Makefile; |
4925 | 0 | cmMakefile::ScopePushPop varScope(mf); |
4926 | 0 | mf->AddDefinition("MACOSX_FRAMEWORK_NAME", targetName); |
4927 | 0 | cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_ICON_FILE"); |
4928 | 0 | cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER"); |
4929 | 0 | cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING"); |
4930 | 0 | cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_NAME"); |
4931 | 0 | cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION"); |
4932 | 0 | mf->ConfigureFile(inFile, fname, false, false, false); |
4933 | 0 | } |
4934 | | |
4935 | | namespace { |
4936 | | cm::string_view CustomOutputRoleKeyword(cmLocalGenerator::OutputRole role) |
4937 | 0 | { |
4938 | 0 | return (role == cmLocalGenerator::OutputRole::Primary ? "OUTPUT"_s |
4939 | 0 | : "BYPRODUCTS"_s); |
4940 | 0 | } |
4941 | | |
4942 | | void CreateGeneratedSource(cmLocalGenerator& lg, std::string const& output, |
4943 | | cmLocalGenerator::OutputRole role, |
4944 | | cmCommandOrigin origin, |
4945 | | cmListFileBacktrace const& lfbt) |
4946 | 0 | { |
4947 | 0 | if (cmGeneratorExpression::Find(output) != std::string::npos) { |
4948 | 0 | lg.GetCMakeInstance()->IssueMessage( |
4949 | 0 | MessageType::FATAL_ERROR, |
4950 | 0 | "Generator expressions in custom command outputs are not implemented!", |
4951 | 0 | lfbt); |
4952 | 0 | return; |
4953 | 0 | } |
4954 | | |
4955 | | // Make sure the file will not be generated into the source |
4956 | | // directory during an out of source build. |
4957 | 0 | if (!lg.GetMakefile()->CanIWriteThisFile(output)) { |
4958 | 0 | lg.GetCMakeInstance()->IssueMessage( |
4959 | 0 | MessageType::FATAL_ERROR, |
4960 | 0 | cmStrCat(CustomOutputRoleKeyword(role), " path\n ", output, |
4961 | 0 | "\nin a source directory as an output of custom command."), |
4962 | 0 | lfbt); |
4963 | 0 | return; |
4964 | 0 | } |
4965 | | |
4966 | | // Make sure the output file name has no invalid characters. |
4967 | 0 | bool const hashNotAllowed = lg.GetState()->UseBorlandMake(); |
4968 | 0 | std::string::size_type pos = output.find_first_of("<>"); |
4969 | 0 | if (pos == std::string::npos && hashNotAllowed) { |
4970 | 0 | pos = output.find_first_of('#'); |
4971 | 0 | } |
4972 | |
|
4973 | 0 | if (pos != std::string::npos) { |
4974 | 0 | lg.GetCMakeInstance()->IssueMessage( |
4975 | 0 | MessageType::FATAL_ERROR, |
4976 | 0 | cmStrCat(CustomOutputRoleKeyword(role), " containing a \"", output[pos], |
4977 | 0 | "\" is not allowed."), |
4978 | 0 | lfbt); |
4979 | 0 | return; |
4980 | 0 | } |
4981 | | |
4982 | | // Outputs without generator expressions from the project are already |
4983 | | // created and marked as generated. Do not mark them again, because |
4984 | | // other commands might have overwritten the property. |
4985 | 0 | if (origin == cmCommandOrigin::Generator) { |
4986 | 0 | lg.GetMakefile()->GetOrCreateGeneratedSource(output); |
4987 | 0 | } |
4988 | 0 | } |
4989 | | |
4990 | | std::string ComputeCustomCommandRuleFileName(cmLocalGenerator& lg, |
4991 | | cmListFileBacktrace const& bt, |
4992 | | std::string const& output) |
4993 | 0 | { |
4994 | | // If the output path has no generator expressions, use it directly. |
4995 | 0 | if (cmGeneratorExpression::Find(output) == std::string::npos) { |
4996 | 0 | return output; |
4997 | 0 | } |
4998 | | |
4999 | | // The output path contains a generator expression, but we must choose |
5000 | | // a single source file path to which to attach the custom command. |
5001 | | // Use some heuristics to provide a nice-looking name when possible. |
5002 | | |
5003 | | // If the only genex is $<CONFIG>, replace that gracefully. |
5004 | 0 | { |
5005 | 0 | std::string simple = output; |
5006 | 0 | cmSystemTools::ReplaceString(simple, "$<CONFIG>", "(CONFIG)"); |
5007 | 0 | if (cmGeneratorExpression::Find(simple) == std::string::npos) { |
5008 | 0 | return simple; |
5009 | 0 | } |
5010 | 0 | } |
5011 | | |
5012 | | // If the genex evaluates to the same value in all configurations, use that. |
5013 | 0 | { |
5014 | 0 | std::vector<std::string> allConfigOutputs = |
5015 | 0 | lg.ExpandCustomCommandOutputGenex(output, bt); |
5016 | 0 | if (allConfigOutputs.size() == 1) { |
5017 | 0 | return allConfigOutputs.front(); |
5018 | 0 | } |
5019 | 0 | } |
5020 | | |
5021 | | // Fall back to a deterministic unique name. |
5022 | 0 | cmCryptoHash h(cmCryptoHash::AlgoSHA256); |
5023 | 0 | return cmStrCat(lg.GetCurrentBinaryDirectory(), "/CMakeFiles/", |
5024 | 0 | h.HashString(output).substr(0, 16)); |
5025 | 0 | } |
5026 | | |
5027 | | cmSourceFile* AddCustomCommand(cmLocalGenerator& lg, cmCommandOrigin origin, |
5028 | | std::unique_ptr<cmCustomCommand> cc, |
5029 | | bool replace) |
5030 | 0 | { |
5031 | 0 | cmMakefile* mf = lg.GetMakefile(); |
5032 | 0 | auto const& lfbt = cc->GetBacktrace(); |
5033 | 0 | auto const& outputs = cc->GetOutputs(); |
5034 | 0 | auto const& byproducts = cc->GetByproducts(); |
5035 | 0 | auto const& commandLines = cc->GetCommandLines(); |
5036 | | |
5037 | | // Choose a source file on which to store the custom command. |
5038 | 0 | cmSourceFile* file = nullptr; |
5039 | 0 | if (!commandLines.empty() && cc->HasMainDependency()) { |
5040 | 0 | auto const& main_dependency = cc->GetMainDependency(); |
5041 | | // The main dependency was specified. Use it unless a different |
5042 | | // custom command already used it. |
5043 | 0 | file = mf->GetSource(main_dependency); |
5044 | 0 | if (file && file->GetCustomCommand() && !replace) { |
5045 | | // The main dependency already has a custom command. |
5046 | 0 | if (commandLines == file->GetCustomCommand()->GetCommandLines()) { |
5047 | | // The existing custom command is identical. Silently ignore |
5048 | | // the duplicate. |
5049 | 0 | return file; |
5050 | 0 | } |
5051 | | // The existing custom command is different. We need to |
5052 | | // generate a rule file for this new command. |
5053 | 0 | file = nullptr; |
5054 | 0 | } else if (!file) { |
5055 | 0 | file = mf->CreateSource(main_dependency); |
5056 | 0 | } |
5057 | 0 | } |
5058 | | |
5059 | | // Generate a rule file if the main dependency is not available. |
5060 | 0 | if (!file) { |
5061 | 0 | cmGlobalGenerator* gg = lg.GetGlobalGenerator(); |
5062 | | |
5063 | | // Construct a rule file associated with the first output produced. |
5064 | 0 | std::string outName = gg->GenerateRuleFile( |
5065 | 0 | ComputeCustomCommandRuleFileName(lg, lfbt, outputs[0])); |
5066 | | |
5067 | | // Check if the rule file already exists. |
5068 | 0 | file = mf->GetSource(outName, cmSourceFileLocationKind::Known); |
5069 | 0 | if (file && file->GetCustomCommand() && !replace) { |
5070 | | // The rule file already exists. |
5071 | 0 | if (commandLines != file->GetCustomCommand()->GetCommandLines()) { |
5072 | 0 | lg.GetCMakeInstance()->IssueMessage( |
5073 | 0 | MessageType::FATAL_ERROR, |
5074 | 0 | cmStrCat("Attempt to add a custom rule to output\n ", outName, |
5075 | 0 | "\nwhich already has a custom rule."), |
5076 | 0 | lfbt); |
5077 | 0 | } |
5078 | 0 | return file; |
5079 | 0 | } |
5080 | | |
5081 | | // Create a cmSourceFile for the rule file. |
5082 | 0 | if (!file) { |
5083 | 0 | file = mf->CreateSource(outName, true, cmSourceFileLocationKind::Known); |
5084 | 0 | } |
5085 | 0 | file->SetProperty("__CMAKE_RULE", "1"); |
5086 | 0 | } |
5087 | | |
5088 | | // Attach the custom command to the file. |
5089 | 0 | if (file) { |
5090 | 0 | cc->SetEscapeAllowMakeVars(true); |
5091 | |
|
5092 | 0 | lg.AddSourceOutputs(file, outputs, cmLocalGenerator::OutputRole::Primary, |
5093 | 0 | lfbt, origin); |
5094 | 0 | lg.AddSourceOutputs(file, byproducts, |
5095 | 0 | cmLocalGenerator::OutputRole::Byproduct, lfbt, origin); |
5096 | |
|
5097 | 0 | file->SetCustomCommand(std::move(cc)); |
5098 | 0 | } |
5099 | 0 | return file; |
5100 | 0 | } |
5101 | | |
5102 | | bool AnyOutputMatches(std::string const& name, |
5103 | | std::vector<std::string> const& outputs) |
5104 | 0 | { |
5105 | 0 | return std::any_of(outputs.begin(), outputs.end(), |
5106 | 0 | [&name](std::string const& output) -> bool { |
5107 | 0 | std::string::size_type pos = output.rfind(name); |
5108 | | // If the output matches exactly |
5109 | 0 | return (pos != std::string::npos && |
5110 | 0 | pos == output.size() - name.size() && |
5111 | 0 | (pos == 0 || output[pos - 1] == '/')); |
5112 | 0 | }); |
5113 | 0 | } |
5114 | | |
5115 | | bool AnyTargetCommandOutputMatches( |
5116 | | std::string const& name, std::vector<cmCustomCommand> const& commands) |
5117 | 0 | { |
5118 | 0 | return std::any_of(commands.begin(), commands.end(), |
5119 | 0 | [&name](cmCustomCommand const& command) -> bool { |
5120 | 0 | return AnyOutputMatches(name, command.GetByproducts()); |
5121 | 0 | }); |
5122 | 0 | } |
5123 | | } |
5124 | | |
5125 | | namespace detail { |
5126 | | void AddCustomCommandToTarget(cmLocalGenerator& lg, cmCommandOrigin origin, |
5127 | | cmTarget* target, cmCustomCommandType type, |
5128 | | std::unique_ptr<cmCustomCommand> cc) |
5129 | 0 | { |
5130 | | // Add the command to the appropriate build step for the target. |
5131 | 0 | cc->SetEscapeAllowMakeVars(true); |
5132 | 0 | cc->SetTarget(target->GetName()); |
5133 | |
|
5134 | 0 | lg.AddTargetByproducts(target, cc->GetByproducts(), cc->GetBacktrace(), |
5135 | 0 | origin); |
5136 | |
|
5137 | 0 | switch (type) { |
5138 | 0 | case cmCustomCommandType::PRE_BUILD: |
5139 | 0 | target->AddPreBuildCommand(std::move(*cc)); |
5140 | 0 | break; |
5141 | 0 | case cmCustomCommandType::PRE_LINK: |
5142 | 0 | target->AddPreLinkCommand(std::move(*cc)); |
5143 | 0 | break; |
5144 | 0 | case cmCustomCommandType::POST_BUILD: |
5145 | 0 | target->AddPostBuildCommand(std::move(*cc)); |
5146 | 0 | break; |
5147 | 0 | } |
5148 | | |
5149 | 0 | cc.reset(); |
5150 | 0 | } |
5151 | | |
5152 | | cmSourceFile* AddCustomCommandToOutput(cmLocalGenerator& lg, |
5153 | | cmCommandOrigin origin, |
5154 | | std::unique_ptr<cmCustomCommand> cc, |
5155 | | bool replace) |
5156 | 0 | { |
5157 | 0 | return AddCustomCommand(lg, origin, std::move(cc), replace); |
5158 | 0 | } |
5159 | | |
5160 | | void AppendCustomCommandToOutput(cmLocalGenerator& lg, |
5161 | | cmListFileBacktrace const& lfbt, |
5162 | | std::string const& output, |
5163 | | std::vector<std::string> const& depends, |
5164 | | cmImplicitDependsList const& implicit_depends, |
5165 | | cmCustomCommandLines const& commandLines) |
5166 | 0 | { |
5167 | | // Lookup an existing command. |
5168 | 0 | cmSourceFile* sf = nullptr; |
5169 | 0 | if (cmGeneratorExpression::Find(output) == std::string::npos) { |
5170 | 0 | sf = lg.GetSourceFileWithOutput(output); |
5171 | 0 | } else { |
5172 | | // This output path has a generator expression. Evaluate it to |
5173 | | // find the output for any configurations. |
5174 | 0 | for (std::string const& out : |
5175 | 0 | lg.ExpandCustomCommandOutputGenex(output, lfbt)) { |
5176 | 0 | sf = lg.GetSourceFileWithOutput(out); |
5177 | 0 | if (sf) { |
5178 | 0 | break; |
5179 | 0 | } |
5180 | 0 | } |
5181 | 0 | } |
5182 | |
|
5183 | 0 | if (sf) { |
5184 | 0 | if (cmCustomCommand* cc = sf->GetCustomCommand()) { |
5185 | 0 | cc->AppendCommands(commandLines); |
5186 | 0 | cc->AppendDepends(depends); |
5187 | 0 | if (cc->GetCodegen() && !implicit_depends.empty()) { |
5188 | 0 | lg.GetCMakeInstance()->IssueMessage( |
5189 | 0 | MessageType::FATAL_ERROR, |
5190 | 0 | "Cannot append IMPLICIT_DEPENDS to existing CODEGEN custom " |
5191 | 0 | "command."); |
5192 | 0 | } |
5193 | 0 | cc->AppendImplicitDepends(implicit_depends); |
5194 | 0 | return; |
5195 | 0 | } |
5196 | 0 | } |
5197 | | |
5198 | | // No existing command found. |
5199 | 0 | lg.GetCMakeInstance()->IssueMessage( |
5200 | 0 | MessageType::FATAL_ERROR, |
5201 | 0 | cmStrCat("Attempt to APPEND to custom command with output\n ", output, |
5202 | 0 | "\nwhich is not already a custom command output."), |
5203 | 0 | lfbt); |
5204 | 0 | } |
5205 | | |
5206 | | void AddUtilityCommand(cmLocalGenerator& lg, cmCommandOrigin origin, |
5207 | | cmTarget* target, std::unique_ptr<cmCustomCommand> cc) |
5208 | 0 | { |
5209 | | // They might be moved away |
5210 | 0 | auto byproducts = cc->GetByproducts(); |
5211 | 0 | auto lfbt = cc->GetBacktrace(); |
5212 | | |
5213 | | // Use an empty comment to avoid generation of default comment. |
5214 | 0 | if (!cc->GetComment()) { |
5215 | 0 | cc->SetComment(""); |
5216 | 0 | } |
5217 | | |
5218 | | // Create the generated symbolic output name of the utility target. |
5219 | 0 | std::string output = |
5220 | 0 | lg.CreateUtilityOutput(target->GetName(), byproducts, lfbt); |
5221 | 0 | cc->SetOutputs(output); |
5222 | |
|
5223 | 0 | cmSourceFile* rule = AddCustomCommand(lg, origin, std::move(cc), |
5224 | 0 | /*replace=*/false); |
5225 | 0 | if (rule) { |
5226 | 0 | lg.AddTargetByproducts(target, byproducts, lfbt, origin); |
5227 | 0 | } |
5228 | |
|
5229 | 0 | target->AddSource(output); |
5230 | 0 | } |
5231 | | |
5232 | | std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target) |
5233 | 0 | { |
5234 | 0 | cmValue const targetProperty = target->GetProperty("ISPC_INSTRUCTION_SETS"); |
5235 | 0 | cmList ispcTargets; |
5236 | |
|
5237 | 0 | if (!targetProperty.IsOff()) { |
5238 | 0 | ispcTargets.assign(targetProperty); |
5239 | 0 | for (auto& ispcTarget : ispcTargets) { |
5240 | | // transform targets into the suffixes |
5241 | 0 | auto pos = ispcTarget.find('-'); |
5242 | 0 | auto target_suffix = ispcTarget.substr(0, pos); |
5243 | | // ISPC uses underscores in output file suffixes where the target name |
5244 | | // has dots (e.g. "avx10.2dmr" produces files with "_avx10_2dmr" suffix) |
5245 | 0 | std::replace(target_suffix.begin(), target_suffix.end(), '.', '_'); |
5246 | 0 | if (target_suffix == |
5247 | 0 | "avx1") { // when targeting avx1 ISPC uses the 'avx' output string |
5248 | 0 | target_suffix = "avx"; |
5249 | 0 | } else if (target_suffix == "sse4_1" || target_suffix == "sse4_2") { |
5250 | | // when targeting sse4.1 or sse4.2 ISPC uses the 'sse4' output string |
5251 | 0 | target_suffix = "sse4"; |
5252 | 0 | } |
5253 | 0 | ispcTarget = target_suffix; |
5254 | 0 | } |
5255 | 0 | } |
5256 | 0 | return std::move(ispcTargets.data()); |
5257 | 0 | } |
5258 | | |
5259 | | std::vector<std::string> ComputeISPCExtraObjects( |
5260 | | std::string const& objectName, std::string const& buildDirectory, |
5261 | | std::vector<std::string> const& ispcSuffixes) |
5262 | 0 | { |
5263 | 0 | auto normalizedDir = cmSystemTools::CollapseFullPath(buildDirectory); |
5264 | 0 | std::vector<std::string> computedObjects; |
5265 | 0 | computedObjects.reserve(ispcSuffixes.size()); |
5266 | |
|
5267 | 0 | auto extension = cmSystemTools::GetFilenameLastExtensionView(objectName); |
5268 | | |
5269 | | // We can't use cmSystemTools::GetFilenameWithoutLastExtension as it |
5270 | | // drops any directories in objectName |
5271 | 0 | auto objNameNoExt = objectName; |
5272 | 0 | std::string::size_type dot_pos = objectName.rfind('.'); |
5273 | 0 | if (dot_pos != std::string::npos) { |
5274 | 0 | objNameNoExt.resize(dot_pos); |
5275 | 0 | } |
5276 | |
|
5277 | 0 | for (auto const& ispcTarget : ispcSuffixes) { |
5278 | 0 | computedObjects.emplace_back( |
5279 | 0 | cmStrCat(normalizedDir, '/', objNameNoExt, '_', ispcTarget, extension)); |
5280 | 0 | } |
5281 | |
|
5282 | 0 | return computedObjects; |
5283 | 0 | } |
5284 | | } |
5285 | | |
5286 | | cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput( |
5287 | | std::string const& name) const |
5288 | 0 | { |
5289 | | // Linear search? Also see GetSourceFileWithOutput for detail. |
5290 | 0 | if (!cmSystemTools::FileIsFullPath(name)) { |
5291 | 0 | cmSourcesWithOutput sources; |
5292 | 0 | sources.Target = this->LinearGetTargetWithOutput(name); |
5293 | 0 | sources.Source = this->LinearGetSourceFileWithOutput( |
5294 | 0 | name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct); |
5295 | 0 | return sources; |
5296 | 0 | } |
5297 | | // Otherwise we use an efficient lookup map. |
5298 | 0 | auto o = this->OutputToSource.find(name); |
5299 | 0 | if (o != this->OutputToSource.end()) { |
5300 | 0 | return o->second.Sources; |
5301 | 0 | } |
5302 | 0 | return {}; |
5303 | 0 | } |
5304 | | |
5305 | | cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput( |
5306 | | std::string const& name, cmSourceOutputKind kind) const |
5307 | 0 | { |
5308 | | // If the queried path is not absolute we use the backward compatible |
5309 | | // linear-time search for an output with a matching suffix. |
5310 | 0 | if (!cmSystemTools::FileIsFullPath(name)) { |
5311 | 0 | bool byproduct = false; |
5312 | 0 | return this->LinearGetSourceFileWithOutput(name, kind, byproduct); |
5313 | 0 | } |
5314 | | // Otherwise we use an efficient lookup map. |
5315 | 0 | auto o = this->OutputToSource.find(name); |
5316 | 0 | if (o != this->OutputToSource.end() && |
5317 | 0 | (!o->second.Sources.SourceIsByproduct || |
5318 | 0 | kind == cmSourceOutputKind::OutputOrByproduct)) { |
5319 | | // Source file could also be null pointer for example if we found the |
5320 | | // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD |
5321 | | // command of a target, or a not yet created custom command. |
5322 | 0 | return o->second.Sources.Source; |
5323 | 0 | } |
5324 | 0 | return nullptr; |
5325 | 0 | } |
5326 | | |
5327 | | std::string cmLocalGenerator::CreateUtilityOutput( |
5328 | | std::string const& targetName, std::vector<std::string> const&, |
5329 | | cmListFileBacktrace const&) |
5330 | 0 | { |
5331 | 0 | std::string force = |
5332 | 0 | cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", targetName); |
5333 | | // The output is not actually created so mark it symbolic. |
5334 | 0 | if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) { |
5335 | 0 | sf->SetProperty("SYMBOLIC", "1"); |
5336 | 0 | } else { |
5337 | 0 | cmSystemTools::Error("Could not get source file entry for " + force); |
5338 | 0 | } |
5339 | 0 | return force; |
5340 | 0 | } |
5341 | | |
5342 | | std::vector<cmCustomCommandGenerator> |
5343 | | cmLocalGenerator::MakeCustomCommandGenerators(cmCustomCommand const& cc, |
5344 | | std::string const& config) |
5345 | 0 | { |
5346 | 0 | std::vector<cmCustomCommandGenerator> ccgs; |
5347 | 0 | ccgs.emplace_back(cc, config, this); |
5348 | 0 | return ccgs; |
5349 | 0 | } |
5350 | | |
5351 | | std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths( |
5352 | | cmCompiledGeneratorExpression const& cge, std::string const& config) |
5353 | 0 | { |
5354 | 0 | cmList paths{ cge.Evaluate(this, config) }; |
5355 | 0 | for (std::string& p : paths) { |
5356 | 0 | p = cmSystemTools::CollapseFullPath(p, this->GetCurrentBinaryDirectory()); |
5357 | 0 | } |
5358 | 0 | return std::move(paths.data()); |
5359 | 0 | } |
5360 | | |
5361 | | std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex( |
5362 | | std::string const& o, cmListFileBacktrace const& bt) |
5363 | 0 | { |
5364 | 0 | std::vector<std::string> allConfigOutputs; |
5365 | 0 | cmGeneratorExpression ge(*this->GetCMakeInstance(), bt); |
5366 | 0 | std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o); |
5367 | 0 | std::vector<std::string> configs = |
5368 | 0 | this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
5369 | 0 | for (std::string const& config : configs) { |
5370 | 0 | std::vector<std::string> configOutputs = |
5371 | 0 | this->ExpandCustomCommandOutputPaths(*cge, config); |
5372 | 0 | allConfigOutputs.reserve(allConfigOutputs.size() + configOutputs.size()); |
5373 | 0 | std::move(configOutputs.begin(), configOutputs.end(), |
5374 | 0 | std::back_inserter(allConfigOutputs)); |
5375 | 0 | } |
5376 | 0 | auto endUnique = |
5377 | 0 | cmRemoveDuplicates(allConfigOutputs.begin(), allConfigOutputs.end()); |
5378 | 0 | allConfigOutputs.erase(endUnique, allConfigOutputs.end()); |
5379 | 0 | return allConfigOutputs; |
5380 | 0 | } |
5381 | | |
5382 | | void cmLocalGenerator::AddTargetByproducts( |
5383 | | cmTarget* target, std::vector<std::string> const& byproducts, |
5384 | | cmListFileBacktrace const& bt, cmCommandOrigin origin) |
5385 | 0 | { |
5386 | 0 | for (std::string const& o : byproducts) { |
5387 | 0 | if (cmGeneratorExpression::Find(o) == std::string::npos) { |
5388 | 0 | this->UpdateOutputToSourceMap(o, target, bt, origin); |
5389 | 0 | continue; |
5390 | 0 | } |
5391 | | |
5392 | | // This byproduct path has a generator expression. Evaluate it to |
5393 | | // register the byproducts for all configurations. |
5394 | 0 | for (std::string const& b : this->ExpandCustomCommandOutputGenex(o, bt)) { |
5395 | 0 | this->UpdateOutputToSourceMap(b, target, bt, cmCommandOrigin::Generator); |
5396 | 0 | } |
5397 | 0 | } |
5398 | 0 | } |
5399 | | |
5400 | | void cmLocalGenerator::AddSourceOutputs( |
5401 | | cmSourceFile* source, std::vector<std::string> const& outputs, |
5402 | | OutputRole role, cmListFileBacktrace const& bt, cmCommandOrigin origin) |
5403 | 0 | { |
5404 | 0 | for (std::string const& o : outputs) { |
5405 | 0 | if (cmGeneratorExpression::Find(o) == std::string::npos) { |
5406 | 0 | this->UpdateOutputToSourceMap(o, source, role, bt, origin); |
5407 | 0 | continue; |
5408 | 0 | } |
5409 | | |
5410 | | // This output path has a generator expression. Evaluate it to |
5411 | | // register the outputs for all configurations. |
5412 | 0 | for (std::string const& out : |
5413 | 0 | this->ExpandCustomCommandOutputGenex(o, bt)) { |
5414 | 0 | this->UpdateOutputToSourceMap(out, source, role, bt, |
5415 | 0 | cmCommandOrigin::Generator); |
5416 | 0 | } |
5417 | 0 | } |
5418 | 0 | } |
5419 | | |
5420 | | void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct, |
5421 | | cmTarget* target, |
5422 | | cmListFileBacktrace const& bt, |
5423 | | cmCommandOrigin origin) |
5424 | 0 | { |
5425 | 0 | SourceEntry entry; |
5426 | 0 | entry.Sources.Target = target; |
5427 | |
|
5428 | 0 | auto pr = this->OutputToSource.emplace(byproduct, entry); |
5429 | 0 | if (pr.second) { |
5430 | 0 | CreateGeneratedSource(*this, byproduct, OutputRole::Byproduct, origin, bt); |
5431 | 0 | } else { |
5432 | 0 | SourceEntry& current = pr.first->second; |
5433 | | // Has the target already been set? |
5434 | 0 | if (!current.Sources.Target) { |
5435 | 0 | current.Sources.Target = target; |
5436 | 0 | } else { |
5437 | | // Multiple custom commands/targets produce the same output (source file |
5438 | | // or target). See also comment in other UpdateOutputToSourceMap |
5439 | | // overload. |
5440 | | // |
5441 | | // TODO: Warn the user about this case. |
5442 | 0 | } |
5443 | 0 | } |
5444 | 0 | } |
5445 | | |
5446 | | void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output, |
5447 | | cmSourceFile* source, |
5448 | | OutputRole role, |
5449 | | cmListFileBacktrace const& bt, |
5450 | | cmCommandOrigin origin) |
5451 | 0 | { |
5452 | 0 | SourceEntry entry; |
5453 | 0 | entry.Sources.Source = source; |
5454 | 0 | entry.Sources.SourceIsByproduct = role == OutputRole::Byproduct; |
5455 | |
|
5456 | 0 | auto pr = this->OutputToSource.emplace(output, entry); |
5457 | 0 | if (pr.second) { |
5458 | 0 | CreateGeneratedSource(*this, output, role, origin, bt); |
5459 | 0 | } else { |
5460 | 0 | SourceEntry& current = pr.first->second; |
5461 | | // Outputs take precedence over byproducts |
5462 | 0 | if (!current.Sources.Source || |
5463 | 0 | (current.Sources.SourceIsByproduct && role == OutputRole::Primary)) { |
5464 | 0 | current.Sources.Source = source; |
5465 | 0 | current.Sources.SourceIsByproduct = false; |
5466 | 0 | } else { |
5467 | | // Multiple custom commands produce the same output but may |
5468 | | // be attached to a different source file (MAIN_DEPENDENCY). |
5469 | | // LinearGetSourceFileWithOutput would return the first one, |
5470 | | // so keep the mapping for the first one. |
5471 | | // |
5472 | | // TODO: Warn the user about this case. However, the VS 8 generator |
5473 | | // triggers it for separate generate.stamp rules in ZERO_CHECK and |
5474 | | // individual targets. |
5475 | 0 | } |
5476 | 0 | } |
5477 | 0 | } |
5478 | | |
5479 | | cmTarget* cmLocalGenerator::LinearGetTargetWithOutput( |
5480 | | std::string const& name) const |
5481 | 0 | { |
5482 | | // We go through the ordered vector of targets to get reproducible results |
5483 | | // should multiple names match. |
5484 | 0 | for (cmTarget* t : this->Makefile->GetOrderedTargets()) { |
5485 | | // Does the output of any command match the source file name? |
5486 | 0 | if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) { |
5487 | 0 | return t; |
5488 | 0 | } |
5489 | 0 | if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) { |
5490 | 0 | return t; |
5491 | 0 | } |
5492 | 0 | if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) { |
5493 | 0 | return t; |
5494 | 0 | } |
5495 | 0 | } |
5496 | 0 | return nullptr; |
5497 | 0 | } |
5498 | | |
5499 | | cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput( |
5500 | | std::string const& name, cmSourceOutputKind kind, bool& byproduct) const |
5501 | 0 | { |
5502 | | // Outputs take precedence over byproducts. |
5503 | 0 | byproduct = false; |
5504 | 0 | cmSourceFile* fallback = nullptr; |
5505 | | |
5506 | | // Look through all the source files that have custom commands and see if the |
5507 | | // custom command has the passed source file as an output. |
5508 | 0 | for (auto const& src : this->Makefile->GetSourceFiles()) { |
5509 | | // Does this source file have a custom command? |
5510 | 0 | if (src->GetCustomCommand()) { |
5511 | | // Does the output of the custom command match the source file name? |
5512 | 0 | if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) { |
5513 | | // Return the first matching output. |
5514 | 0 | return src.get(); |
5515 | 0 | } |
5516 | 0 | if (kind == cmSourceOutputKind::OutputOrByproduct) { |
5517 | 0 | if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) { |
5518 | | // Do not return the source yet as there might be a matching output. |
5519 | 0 | fallback = src.get(); |
5520 | 0 | } |
5521 | 0 | } |
5522 | 0 | } |
5523 | 0 | } |
5524 | | |
5525 | | // Did we find a byproduct? |
5526 | 0 | byproduct = fallback != nullptr; |
5527 | 0 | return fallback; |
5528 | 0 | } |