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