/src/CMake/Source/cmNinjaTargetGenerator.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 "cmNinjaTargetGenerator.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <array> |
7 | | #include <cassert> |
8 | | #include <functional> |
9 | | #include <iterator> |
10 | | #include <map> |
11 | | #include <ostream> |
12 | | #include <unordered_map> |
13 | | #include <unordered_set> |
14 | | #include <utility> |
15 | | |
16 | | #include <cm/memory> |
17 | | #include <cm/optional> |
18 | | #include <cm/string_view> |
19 | | #include <cmext/algorithm> |
20 | | #include <cmext/string_view> |
21 | | |
22 | | #include <cm3p/json/value.h> |
23 | | #include <cm3p/json/writer.h> |
24 | | |
25 | | #include "cmBuildDatabase.h" |
26 | | #include "cmComputeLinkInformation.h" |
27 | | #include "cmCustomCommand.h" |
28 | | #include "cmCustomCommandGenerator.h" |
29 | | #include "cmDyndepCollation.h" |
30 | | #include "cmFileSetMetadata.h" |
31 | | #include "cmGeneratedFileStream.h" |
32 | | #include "cmGeneratorExpression.h" |
33 | | #include "cmGeneratorFileSet.h" |
34 | | #include "cmGeneratorOptions.h" |
35 | | #include "cmGeneratorTarget.h" |
36 | | #include "cmGlobalCommonGenerator.h" |
37 | | #include "cmGlobalNinjaGenerator.h" |
38 | | #include "cmList.h" |
39 | | #include "cmListFileCache.h" |
40 | | #include "cmLocalGenerator.h" |
41 | | #include "cmLocalNinjaGenerator.h" |
42 | | #include "cmMakefile.h" |
43 | | #include "cmMessageType.h" |
44 | | #include "cmNinjaNormalTargetGenerator.h" |
45 | | #include "cmNinjaUtilityTargetGenerator.h" |
46 | | #include "cmOutputConverter.h" |
47 | | #include "cmPolicies.h" |
48 | | #include "cmRange.h" |
49 | | #include "cmRulePlaceholderExpander.h" |
50 | | #include "cmSourceFile.h" |
51 | | #include "cmState.h" |
52 | | #include "cmStateTypes.h" |
53 | | #include "cmStringAlgorithms.h" |
54 | | #include "cmSystemTools.h" |
55 | | #include "cmTarget.h" |
56 | | #include "cmTargetDepend.h" |
57 | | #include "cmValue.h" |
58 | | #include "cmake.h" |
59 | | |
60 | | std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New( |
61 | | cmGeneratorTarget* target) |
62 | 0 | { |
63 | 0 | switch (target->GetType()) { |
64 | 0 | case cmStateEnums::EXECUTABLE: |
65 | 0 | case cmStateEnums::SHARED_LIBRARY: |
66 | 0 | case cmStateEnums::STATIC_LIBRARY: |
67 | 0 | case cmStateEnums::MODULE_LIBRARY: |
68 | 0 | case cmStateEnums::OBJECT_LIBRARY: |
69 | 0 | return cm::make_unique<cmNinjaNormalTargetGenerator>(target); |
70 | | |
71 | 0 | case cmStateEnums::INTERFACE_LIBRARY: |
72 | 0 | if (target->HaveCxx20ModuleSources()) { |
73 | 0 | return cm::make_unique<cmNinjaNormalTargetGenerator>(target); |
74 | 0 | } |
75 | 0 | CM_FALLTHROUGH; |
76 | |
|
77 | 0 | case cmStateEnums::UTILITY: |
78 | 0 | case cmStateEnums::GLOBAL_TARGET: |
79 | 0 | return cm::make_unique<cmNinjaUtilityTargetGenerator>(target); |
80 | | |
81 | 0 | default: |
82 | 0 | return std::unique_ptr<cmNinjaTargetGenerator>(); |
83 | 0 | } |
84 | 0 | } |
85 | | |
86 | | cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target) |
87 | 0 | : cmCommonTargetGenerator(target) |
88 | 0 | , OSXBundleGenerator(nullptr) |
89 | | , LocalGenerator( |
90 | 0 | static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator())) |
91 | 0 | { |
92 | 0 | for (auto const& fileConfig : this->LocalGenerator->GetConfigNames()) { |
93 | 0 | this->Configs[fileConfig].MacOSXContentGenerator = |
94 | 0 | cm::make_unique<MacOSXContentGeneratorType>(this, fileConfig); |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | 0 | cmNinjaTargetGenerator::~cmNinjaTargetGenerator() = default; |
99 | | |
100 | | cmGeneratedFileStream& cmNinjaTargetGenerator::GetImplFileStream( |
101 | | std::string const& config) const |
102 | 0 | { |
103 | 0 | return *this->GetGlobalGenerator()->GetImplFileStream(config); |
104 | 0 | } |
105 | | |
106 | | cmGeneratedFileStream& cmNinjaTargetGenerator::GetCommonFileStream() const |
107 | 0 | { |
108 | 0 | return *this->GetGlobalGenerator()->GetCommonFileStream(); |
109 | 0 | } |
110 | | |
111 | | cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const |
112 | 0 | { |
113 | 0 | return *this->GetGlobalGenerator()->GetRulesFileStream(); |
114 | 0 | } |
115 | | |
116 | | cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const |
117 | 0 | { |
118 | 0 | return this->LocalGenerator->GetGlobalNinjaGenerator(); |
119 | 0 | } |
120 | | |
121 | | std::string cmNinjaTargetGenerator::LanguageCompilerRule( |
122 | | std::string const& lang, std::string const& config, |
123 | | WithScanning withScanning) const |
124 | 0 | { |
125 | 0 | return cmStrCat( |
126 | 0 | lang, "_COMPILER__", |
127 | 0 | cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), |
128 | 0 | withScanning == WithScanning::Yes ? "_scanned_" : "_unscanned_", config); |
129 | 0 | } |
130 | | |
131 | | std::string cmNinjaTargetGenerator::LanguagePreprocessAndScanRule( |
132 | | std::string const& lang, std::string const& config) const |
133 | 0 | { |
134 | 0 | return cmStrCat( |
135 | 0 | lang, "_PREPROCESS_SCAN__", |
136 | 0 | cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), |
137 | 0 | '_', config); |
138 | 0 | } |
139 | | |
140 | | std::string cmNinjaTargetGenerator::LanguageScanRule( |
141 | | std::string const& lang, std::string const& config) const |
142 | 0 | { |
143 | 0 | return cmStrCat( |
144 | 0 | lang, "_SCAN__", |
145 | 0 | cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), |
146 | 0 | '_', config); |
147 | 0 | } |
148 | | |
149 | | bool cmNinjaTargetGenerator::NeedExplicitPreprocessing( |
150 | | std::string const& lang) const |
151 | 0 | { |
152 | 0 | return lang == "Fortran" || lang == "Swift"; |
153 | 0 | } |
154 | | |
155 | | bool cmNinjaTargetGenerator::CompileWithDefines(std::string const& lang) const |
156 | 0 | { |
157 | 0 | return this->Makefile->IsOn( |
158 | 0 | cmStrCat("CMAKE_", lang, "_COMPILE_WITH_DEFINES")); |
159 | 0 | } |
160 | | |
161 | | std::string cmNinjaTargetGenerator::LanguageDyndepRule( |
162 | | std::string const& lang, std::string const& config) const |
163 | 0 | { |
164 | 0 | return cmStrCat( |
165 | 0 | lang, "_DYNDEP__", |
166 | 0 | cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), |
167 | 0 | '_', config); |
168 | 0 | } |
169 | | |
170 | | std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget( |
171 | | std::string const& config) |
172 | 0 | { |
173 | 0 | return this->GetGlobalGenerator()->OrderDependsTargetForTarget( |
174 | 0 | this->GeneratorTarget, config); |
175 | 0 | } |
176 | | |
177 | | std::string cmNinjaTargetGenerator::OrderDependsTargetForTargetPrivate( |
178 | | std::string const& config) |
179 | 0 | { |
180 | 0 | return this->GetGlobalGenerator()->OrderDependsTargetForTargetPrivate( |
181 | 0 | this->GeneratorTarget, config); |
182 | 0 | } |
183 | | |
184 | | // TODO: Most of the code is picked up from |
185 | | // void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink), |
186 | | // void cmMakefileTargetGenerator::WriteTargetLanguageFlags() |
187 | | // Refactor it. |
188 | | std::string cmNinjaTargetGenerator::ComputeFlagsForObject( |
189 | | cmSourceFile const* source, std::string const& language, |
190 | | std::string const& config, std::string const& objectFileName) |
191 | 0 | { |
192 | 0 | std::unordered_map<std::string, std::string> pchSources; |
193 | 0 | std::vector<std::string> pchArchs = |
194 | 0 | this->GeneratorTarget->GetPchArchs(config, language); |
195 | |
|
196 | 0 | std::string filterArch; |
197 | 0 | for (std::string const& arch : pchArchs) { |
198 | 0 | std::string const pchSource = |
199 | 0 | this->GeneratorTarget->GetPchSource(config, language, arch); |
200 | 0 | if (pchSource == source->GetFullPath()) { |
201 | 0 | filterArch = arch; |
202 | 0 | } |
203 | 0 | if (!pchSource.empty()) { |
204 | 0 | pchSources.insert(std::make_pair(pchSource, arch)); |
205 | 0 | } |
206 | 0 | } |
207 | |
|
208 | 0 | std::string flags; |
209 | | // Explicitly add the explicit language flag before any other flag |
210 | | // so user flags can override it. |
211 | 0 | this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source); |
212 | |
|
213 | 0 | if (!flags.empty()) { |
214 | 0 | flags += " "; |
215 | 0 | } |
216 | 0 | flags += this->GetFlags(language, config, filterArch); |
217 | | |
218 | | // Add Fortran format flags. |
219 | 0 | if (language == "Fortran") { |
220 | 0 | this->AppendFortranFormatFlags(flags, *source); |
221 | 0 | this->AppendFortranPreprocessFlags(flags, *source, |
222 | 0 | PreprocessFlagsRequired::NO); |
223 | 0 | } |
224 | | |
225 | | // Add source file specific flags. |
226 | 0 | cmGeneratorExpressionInterpreter genexInterpreter( |
227 | 0 | this->LocalGenerator, config, this->GeneratorTarget, language); |
228 | |
|
229 | 0 | std::string const COMPILE_FLAGS("COMPILE_FLAGS"); |
230 | 0 | if (cmValue cflags = source->GetProperty(COMPILE_FLAGS)) { |
231 | 0 | this->LocalGenerator->AppendFlags( |
232 | 0 | flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); |
233 | 0 | } |
234 | |
|
235 | 0 | std::string const COMPILE_OPTIONS("COMPILE_OPTIONS"); |
236 | 0 | if (cmValue coptions = source->GetProperty(COMPILE_OPTIONS)) { |
237 | 0 | this->LocalGenerator->AppendCompileOptions( |
238 | 0 | flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); |
239 | 0 | } |
240 | | |
241 | | // Add precompile headers compile options. |
242 | 0 | if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { |
243 | 0 | std::string pchOptions; |
244 | 0 | auto pchIt = pchSources.find(source->GetFullPath()); |
245 | 0 | if (pchIt != pchSources.end()) { |
246 | 0 | pchOptions = this->GeneratorTarget->GetPchCreateCompileOptions( |
247 | 0 | config, language, pchIt->second); |
248 | 0 | } else { |
249 | 0 | pchOptions = |
250 | 0 | this->GeneratorTarget->GetPchUseCompileOptions(config, language); |
251 | 0 | } |
252 | |
|
253 | 0 | this->LocalGenerator->AppendCompileOptions( |
254 | 0 | flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS)); |
255 | 0 | } |
256 | |
|
257 | 0 | auto const* fs = this->GeneratorTarget->GetFileSetForSource(config, source); |
258 | 0 | if (fs && fs->GetType() == cm::FileSetMetadata::CXX_MODULES) { |
259 | 0 | if (source->GetLanguage() != "CXX"_s) { |
260 | 0 | this->GetMakefile()->IssueMessage( |
261 | 0 | MessageType::FATAL_ERROR, |
262 | 0 | cmStrCat("Target \"", this->GeneratorTarget->Target->GetName(), |
263 | 0 | "\" contains the source\n ", source->GetFullPath(), |
264 | 0 | "\nin a file set of type \"", fs->GetType(), |
265 | 0 | R"(" but the source is not classified as a "CXX" source.)")); |
266 | 0 | } |
267 | |
|
268 | 0 | if (!this->GeneratorTarget->Target->IsNormal()) { |
269 | 0 | auto flag = this->GetMakefile()->GetSafeDefinition( |
270 | 0 | "CMAKE_CXX_MODULE_BMI_ONLY_FLAG"); |
271 | 0 | cmRulePlaceholderExpander::RuleVariables compileObjectVars; |
272 | 0 | compileObjectVars.Object = objectFileName.c_str(); |
273 | 0 | auto rulePlaceholderExpander = |
274 | 0 | this->GetLocalGenerator()->CreateRulePlaceholderExpander(); |
275 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), |
276 | 0 | flag, compileObjectVars); |
277 | 0 | this->LocalGenerator->AppendCompileOptions(flags, flag); |
278 | 0 | } |
279 | 0 | } |
280 | |
|
281 | 0 | return flags; |
282 | 0 | } |
283 | | |
284 | | void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags, |
285 | | std::string const& language, |
286 | | std::string const& config) |
287 | 0 | { |
288 | 0 | std::vector<std::string> includes; |
289 | 0 | this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, |
290 | 0 | language, config); |
291 | | // Add include directory flags. |
292 | 0 | std::string includeFlags = this->LocalGenerator->GetIncludeFlags( |
293 | 0 | includes, this->GeneratorTarget, language, config, false); |
294 | 0 | if (this->GetGlobalGenerator()->IsGCCOnWindows()) { |
295 | 0 | std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/'); |
296 | 0 | } |
297 | |
|
298 | 0 | this->LocalGenerator->AppendFlags(languageFlags, includeFlags); |
299 | 0 | } |
300 | | |
301 | | // TODO: Refactor with |
302 | | // void cmMakefileTargetGenerator::WriteTargetLanguageFlags(). |
303 | | std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, |
304 | | std::string const& language, |
305 | | std::string const& config) |
306 | 0 | { |
307 | 0 | std::set<std::string> defines; |
308 | 0 | cmGeneratorExpressionInterpreter genexInterpreter( |
309 | 0 | this->LocalGenerator, config, this->GeneratorTarget, language); |
310 | | |
311 | | // Seriously?? |
312 | 0 | if (this->GetGlobalGenerator()->IsMultiConfig()) { |
313 | 0 | defines.insert(cmStrCat("CMAKE_INTDIR=\"", config, '"')); |
314 | 0 | } |
315 | |
|
316 | 0 | std::string const COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); |
317 | 0 | if (cmValue compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { |
318 | 0 | this->LocalGenerator->AppendDefines( |
319 | 0 | defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS)); |
320 | 0 | } |
321 | |
|
322 | 0 | std::string defPropName = |
323 | 0 | cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config)); |
324 | 0 | if (cmValue config_compile_defs = source->GetProperty(defPropName)) { |
325 | 0 | this->LocalGenerator->AppendDefines( |
326 | 0 | defines, |
327 | 0 | genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS)); |
328 | 0 | } |
329 | |
|
330 | 0 | std::string definesString = this->GetDefines(language, config); |
331 | 0 | this->LocalGenerator->JoinDefines(defines, definesString, language); |
332 | |
|
333 | 0 | return definesString; |
334 | 0 | } |
335 | | |
336 | | std::string cmNinjaTargetGenerator::ComputeIncludes( |
337 | | cmSourceFile const* source, std::string const& language, |
338 | | std::string const& config) |
339 | 0 | { |
340 | 0 | std::vector<std::string> includes; |
341 | 0 | cmGeneratorExpressionInterpreter genexInterpreter( |
342 | 0 | this->LocalGenerator, config, this->GeneratorTarget, language); |
343 | |
|
344 | 0 | std::string const INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); |
345 | 0 | if (cmValue cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) { |
346 | 0 | this->LocalGenerator->AppendIncludeDirectories( |
347 | 0 | includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES), |
348 | 0 | *source); |
349 | 0 | } |
350 | |
|
351 | 0 | std::string includesString = this->LocalGenerator->GetIncludeFlags( |
352 | 0 | includes, this->GeneratorTarget, language, config, false); |
353 | 0 | this->LocalGenerator->AppendFlags(includesString, |
354 | 0 | this->GetIncludes(language, config)); |
355 | |
|
356 | 0 | return includesString; |
357 | 0 | } |
358 | | |
359 | | cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( |
360 | | std::string const& linkLanguage, std::string const& config, |
361 | | bool ignoreType) const |
362 | 0 | { |
363 | | // Static libraries never depend on other targets for linking. |
364 | 0 | if (!ignoreType && |
365 | 0 | (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || |
366 | 0 | this->GeneratorTarget->GetType() == cmStateEnums::OBJECT_LIBRARY)) { |
367 | 0 | return cmNinjaDeps(); |
368 | 0 | } |
369 | | |
370 | 0 | cmComputeLinkInformation* cli = |
371 | 0 | this->GeneratorTarget->GetLinkInformation(config); |
372 | 0 | if (!cli) { |
373 | 0 | return cmNinjaDeps(); |
374 | 0 | } |
375 | | |
376 | 0 | std::vector<std::string> const& deps = cli->GetDepends(); |
377 | 0 | cmNinjaDeps result(deps.size()); |
378 | 0 | std::transform(deps.begin(), deps.end(), result.begin(), |
379 | 0 | this->MapToNinjaPath()); |
380 | | |
381 | | // Add a dependency on the link definitions file, if any. |
382 | 0 | if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi = |
383 | 0 | this->GeneratorTarget->GetModuleDefinitionInfo(config)) { |
384 | 0 | for (cmSourceFile const* src : mdi->Sources) { |
385 | 0 | result.push_back(this->ConvertToNinjaPath(src->GetFullPath())); |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | | // Add a dependency on user-specified manifest files, if any. |
390 | 0 | std::vector<cmSourceFile const*> manifest_srcs; |
391 | 0 | this->GeneratorTarget->GetManifests(manifest_srcs, config); |
392 | 0 | for (cmSourceFile const* manifest_src : manifest_srcs) { |
393 | 0 | result.push_back(this->ConvertToNinjaPath(manifest_src->GetFullPath())); |
394 | 0 | } |
395 | | |
396 | | // Add user-specified dependencies. |
397 | 0 | std::vector<std::string> linkDeps; |
398 | 0 | this->GeneratorTarget->GetLinkDepends(linkDeps, config, linkLanguage); |
399 | 0 | std::transform(linkDeps.begin(), linkDeps.end(), std::back_inserter(result), |
400 | 0 | this->MapToNinjaPath()); |
401 | |
|
402 | 0 | return result; |
403 | 0 | } |
404 | | |
405 | | std::string cmNinjaTargetGenerator::GetCompiledSourceNinjaPath( |
406 | | cmSourceFile const* source) const |
407 | 0 | { |
408 | | // Pass source files to the compiler by absolute path. |
409 | 0 | return this->ConvertToNinjaAbsPath(source->GetFullPath()); |
410 | 0 | } |
411 | | |
412 | | std::string cmNinjaTargetGenerator::GetObjectFileDir( |
413 | | std::string const& config) const |
414 | 0 | { |
415 | 0 | return this->LocalGenerator->MaybeRelativeToTopBinDir( |
416 | 0 | cmStrCat(this->GeneratorTarget->GetSupportDirectory(), |
417 | 0 | this->GetGlobalGenerator()->GetConfigDirectory(config))); |
418 | 0 | } |
419 | | |
420 | | std::string cmNinjaTargetGenerator::GetObjectFilePath( |
421 | | cmSourceFile const* source, std::string const& config) const |
422 | 0 | { |
423 | 0 | std::string const& objectName = this->GeneratorTarget->GetObjectName(source); |
424 | 0 | return cmStrCat(this->GetObjectFileDir(config), '/', objectName); |
425 | 0 | } |
426 | | |
427 | | std::string cmNinjaTargetGenerator::GetBmiFilePath( |
428 | | cmSourceFile const* source, std::string const& config) const |
429 | 0 | { |
430 | 0 | auto& importedConfigInfo = this->Configs.at(config).ImportedCxxModules; |
431 | 0 | if (!importedConfigInfo.Initialized()) { |
432 | 0 | std::string configUpper = cmSystemTools::UpperCase(config); |
433 | 0 | std::string propName = cmStrCat("IMPORTED_CXX_MODULES_", configUpper); |
434 | 0 | auto value = this->GeneratorTarget->GetSafeProperty(propName); |
435 | 0 | importedConfigInfo.Initialize(value); |
436 | 0 | } |
437 | |
|
438 | 0 | std::string bmiName = |
439 | 0 | importedConfigInfo.BmiNameForSource(source->GetFullPath()); |
440 | |
|
441 | 0 | return cmStrCat(this->GetObjectFileDir(config), '/', bmiName); |
442 | 0 | } |
443 | | |
444 | | std::string cmNinjaTargetGenerator::GetClangTidyReplacementsFilePath( |
445 | | std::string const& directory, cmSourceFile const& source, |
446 | | std::string const& config) const |
447 | 0 | { |
448 | 0 | auto const& objectName = this->GeneratorTarget->GetObjectName(&source); |
449 | 0 | return cmStrCat(directory, '/', |
450 | 0 | this->LocalGenerator->CreateSafeObjectFileName( |
451 | 0 | this->GetObjectFileDir(config)), |
452 | 0 | '/', objectName, ".yaml"); |
453 | 0 | } |
454 | | |
455 | | std::string cmNinjaTargetGenerator::GetPreprocessedFilePath( |
456 | | cmSourceFile const* source, std::string const& config) const |
457 | 0 | { |
458 | | // Choose an extension to compile already-preprocessed source. |
459 | 0 | std::string ppExt = source->GetExtension(); |
460 | 0 | if (cmHasPrefix(ppExt, 'F')) { |
461 | | // Some Fortran compilers automatically enable preprocessing for |
462 | | // upper-case extensions. Since the source is already preprocessed, |
463 | | // use a lower-case extension. |
464 | 0 | ppExt = cmSystemTools::LowerCase(ppExt); |
465 | 0 | } |
466 | 0 | if (ppExt == "fpp") { |
467 | | // Some Fortran compilers automatically enable preprocessing for |
468 | | // the ".fpp" extension. Since the source is already preprocessed, |
469 | | // use the ".f" extension. |
470 | 0 | ppExt = "f"; |
471 | 0 | } |
472 | | |
473 | | // Take the object file name and replace the extension. |
474 | 0 | std::string const& objName = this->GeneratorTarget->GetObjectName(source); |
475 | 0 | std::string const& objExt = |
476 | 0 | this->GetGlobalGenerator()->GetLanguageOutputExtension(*source); |
477 | 0 | assert(objName.size() >= objExt.size()); |
478 | 0 | std::string const ppName = |
479 | 0 | cmStrCat(objName.substr(0, objName.size() - objExt.size()), "-pp.", ppExt); |
480 | |
|
481 | 0 | return cmStrCat(this->GetObjectFileDir(config), '/', ppName); |
482 | 0 | } |
483 | | |
484 | | std::string cmNinjaTargetGenerator::GetDyndepFilePath( |
485 | | std::string const& lang, std::string const& config) const |
486 | 0 | { |
487 | 0 | return cmStrCat(this->GetObjectFileDir(config), '/', lang, ".dd"); |
488 | 0 | } |
489 | | |
490 | | std::string cmNinjaTargetGenerator::GetTargetDependInfoPath( |
491 | | std::string const& lang, std::string const& config) const |
492 | 0 | { |
493 | 0 | return cmStrCat(this->GeneratorTarget->GetSupportDirectory(), |
494 | 0 | this->GetGlobalGenerator()->ConfigDirectory(config), '/', |
495 | 0 | lang, "DependInfo.json"); |
496 | 0 | } |
497 | | |
498 | | std::string cmNinjaTargetGenerator::GetTargetOutputDir( |
499 | | std::string const& config) const |
500 | 0 | { |
501 | 0 | std::string dir = this->GeneratorTarget->GetDirectory(config); |
502 | 0 | return this->ConvertToNinjaPath(dir); |
503 | 0 | } |
504 | | |
505 | | std::string cmNinjaTargetGenerator::GetTargetFilePath( |
506 | | std::string const& name, std::string const& config) const |
507 | 0 | { |
508 | 0 | std::string path = this->GetTargetOutputDir(config); |
509 | 0 | if (path.empty() || path == ".") { |
510 | 0 | return name; |
511 | 0 | } |
512 | 0 | path += cmStrCat('/', name); |
513 | 0 | return path; |
514 | 0 | } |
515 | | |
516 | | std::string cmNinjaTargetGenerator::GetTargetName() const |
517 | 0 | { |
518 | 0 | return this->GeneratorTarget->GetName(); |
519 | 0 | } |
520 | | |
521 | | std::string cmNinjaTargetGenerator::ConvertToOutputFormatForShell( |
522 | | cm::string_view path) const |
523 | 0 | { |
524 | 0 | return this->LocalGenerator->ConvertToOutputFormat(path, |
525 | 0 | cmOutputConverter::SHELL); |
526 | 0 | } |
527 | | |
528 | | bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable( |
529 | | cmNinjaVars& vars, std::string const& config) const |
530 | 0 | { |
531 | 0 | cmMakefile* mf = this->GetMakefile(); |
532 | 0 | if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") || |
533 | 0 | mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") || |
534 | 0 | mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) { |
535 | 0 | std::string pdbPath; |
536 | 0 | std::string compilePdbPath = this->ComputeTargetCompilePDB(config); |
537 | 0 | if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE || |
538 | 0 | this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || |
539 | 0 | this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || |
540 | 0 | this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) { |
541 | 0 | pdbPath = cmStrCat(this->GeneratorTarget->GetPDBDirectory(config), '/', |
542 | 0 | this->GeneratorTarget->GetPDBName(config)); |
543 | 0 | } |
544 | |
|
545 | 0 | vars["TARGET_PDB"] = |
546 | 0 | this->ConvertToOutputFormatForShell(this->ConvertToNinjaPath(pdbPath)); |
547 | 0 | vars["TARGET_COMPILE_PDB"] = this->ConvertToOutputFormatForShell( |
548 | 0 | this->ConvertToNinjaPath(compilePdbPath)); |
549 | |
|
550 | 0 | this->EnsureParentDirectoryExists(pdbPath); |
551 | 0 | this->EnsureParentDirectoryExists(compilePdbPath); |
552 | 0 | return true; |
553 | 0 | } |
554 | 0 | return false; |
555 | 0 | } |
556 | | |
557 | | void cmNinjaTargetGenerator::WriteLanguageRules(std::string const& language, |
558 | | std::string const& config) |
559 | 0 | { |
560 | | #ifdef NINJA_GEN_VERBOSE_FILES |
561 | | this->GetRulesFileStream() << "# Rules for language " << language << "\n\n"; |
562 | | #endif |
563 | 0 | this->WriteCompileRule(language, config); |
564 | 0 | } |
565 | | |
566 | | namespace { |
567 | | // Create the command to run the dependency scanner |
568 | | std::string GetScanCommand( |
569 | | cm::string_view cmakeCmd, cm::string_view tdi, cm::string_view lang, |
570 | | cm::string_view srcFile, cm::string_view ddiFile, |
571 | | cm::optional<cm::string_view> srcOrigFile = cm::nullopt) |
572 | 0 | { |
573 | 0 | return cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, |
574 | 0 | " --lang=", lang, " --src=", srcFile, |
575 | 0 | " --out=$out" |
576 | 0 | " --dep=$DEP_FILE --obj=$OBJ_FILE --ddi=", |
577 | 0 | ddiFile, |
578 | 0 | srcOrigFile ? cmStrCat(" --src-orig=", *srcOrigFile) : ""); |
579 | 0 | } |
580 | | |
581 | | // Helper function to create dependency scanning rule that may or may |
582 | | // not perform explicit preprocessing too. |
583 | | cmNinjaRule GetScanRule( |
584 | | std::string const& ruleName, std::string const& ppFileName, |
585 | | std::string const& deptype, |
586 | | cmRulePlaceholderExpander::RuleVariables const& vars, |
587 | | std::string const& responseFlag, std::string const& flags, |
588 | | cmRulePlaceholderExpander* const rulePlaceholderExpander, |
589 | | cmLocalNinjaGenerator* generator, std::vector<std::string> scanCmds, |
590 | | std::string const& outputConfig) |
591 | 0 | { |
592 | 0 | cmNinjaRule rule(ruleName); |
593 | | // Scanning always uses a depfile for preprocessor dependencies. |
594 | 0 | if (deptype == "msvc"_s) { |
595 | 0 | rule.DepType = deptype; |
596 | 0 | rule.DepFile.clear(); |
597 | 0 | } else { |
598 | 0 | rule.DepType.clear(); // no deps= for multiple outputs |
599 | 0 | rule.DepFile = "$DEP_FILE"; |
600 | 0 | } |
601 | |
|
602 | 0 | cmRulePlaceholderExpander::RuleVariables scanVars; |
603 | 0 | scanVars.CMTargetName = vars.CMTargetName; |
604 | 0 | scanVars.CMTargetType = vars.CMTargetType; |
605 | 0 | scanVars.Language = vars.Language; |
606 | 0 | scanVars.Object = "$OBJ_FILE"; |
607 | 0 | scanVars.PreprocessedSource = ppFileName.c_str(); |
608 | 0 | scanVars.DynDepFile = "$DYNDEP_INTERMEDIATE_FILE"; |
609 | 0 | scanVars.DependencyFile = rule.DepFile.c_str(); |
610 | 0 | scanVars.DependencyTarget = "$out"; |
611 | 0 | scanVars.Config = vars.Config; |
612 | | |
613 | | // Scanning needs the same preprocessor settings as direct compilation would. |
614 | 0 | scanVars.Source = vars.Source; |
615 | 0 | scanVars.Defines = vars.Defines; |
616 | 0 | scanVars.Includes = vars.Includes; |
617 | | |
618 | | // Scanning needs the compilation flags too. |
619 | 0 | std::string scanFlags = flags; |
620 | | |
621 | | // If using a response file, move defines, includes, and flags into it. |
622 | 0 | if (!responseFlag.empty()) { |
623 | 0 | rule.RspFile = "$RSP_FILE"; |
624 | 0 | rule.RspContent = |
625 | 0 | cmStrCat(' ', scanVars.Defines, ' ', scanVars.Includes, ' ', scanFlags); |
626 | 0 | scanFlags = cmStrCat(responseFlag, rule.RspFile); |
627 | 0 | scanVars.Defines = ""; |
628 | 0 | scanVars.Includes = ""; |
629 | 0 | } |
630 | |
|
631 | 0 | scanVars.Flags = scanFlags.c_str(); |
632 | | |
633 | | // Rule for scanning a source file. |
634 | 0 | for (std::string& scanCmd : scanCmds) { |
635 | 0 | rulePlaceholderExpander->ExpandRuleVariables(generator, scanCmd, scanVars); |
636 | 0 | } |
637 | 0 | rule.Command = |
638 | 0 | generator->BuildCommandLine(scanCmds, outputConfig, outputConfig); |
639 | |
|
640 | 0 | return rule; |
641 | 0 | } |
642 | | } |
643 | | |
644 | | void cmNinjaTargetGenerator::WriteCompileRule(std::string const& lang, |
645 | | std::string const& config) |
646 | 0 | { |
647 | | // For some cases we scan to dynamically discover dependencies. |
648 | 0 | bool const needDyndep = this->GetGeneratorTarget()->NeedDyndep(lang, config); |
649 | |
|
650 | 0 | if (needDyndep) { |
651 | 0 | this->WriteCompileRule(lang, config, WithScanning::Yes); |
652 | 0 | } |
653 | 0 | this->WriteCompileRule(lang, config, WithScanning::No); |
654 | 0 | } |
655 | | |
656 | | void cmNinjaTargetGenerator::WriteCompileRule(std::string const& lang, |
657 | | std::string const& config, |
658 | | WithScanning withScanning) |
659 | 0 | { |
660 | 0 | cmRulePlaceholderExpander::RuleVariables vars; |
661 | 0 | vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); |
662 | 0 | vars.CMTargetType = |
663 | 0 | cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str(); |
664 | 0 | vars.Language = lang.c_str(); |
665 | 0 | vars.Source = "$in"; |
666 | 0 | vars.Object = "$out"; |
667 | 0 | vars.Defines = "$DEFINES"; |
668 | 0 | vars.Includes = "$INCLUDES"; |
669 | 0 | vars.TargetPDB = "$TARGET_PDB"; |
670 | 0 | vars.TargetCompilePDB = "$TARGET_COMPILE_PDB"; |
671 | 0 | vars.ObjectDir = "$OBJECT_DIR"; |
672 | 0 | vars.TargetSupportDir = "$TARGET_SUPPORT_DIR"; |
673 | 0 | vars.ObjectFileDir = "$OBJECT_FILE_DIR"; |
674 | 0 | vars.CudaCompileMode = "$CUDA_COMPILE_MODE"; |
675 | 0 | vars.ISPCHeader = "$ISPC_HEADER_FILE"; |
676 | 0 | vars.Config = "$CONFIG"; |
677 | |
|
678 | 0 | cmMakefile* mf = this->GetMakefile(); |
679 | | |
680 | | // For some cases we scan to dynamically discover dependencies. |
681 | 0 | bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang); |
682 | |
|
683 | 0 | std::string flags = "$FLAGS"; |
684 | |
|
685 | 0 | std::string responseFlag; |
686 | 0 | bool const lang_supports_response = lang != "RC"; |
687 | 0 | if (lang_supports_response && this->ForceResponseFile()) { |
688 | 0 | std::string const responseFlagVar = |
689 | 0 | cmStrCat("CMAKE_", lang, "_RESPONSE_FILE_FLAG"); |
690 | 0 | responseFlag = this->Makefile->GetSafeDefinition(responseFlagVar); |
691 | 0 | if (responseFlag.empty() && lang != "CUDA") { |
692 | 0 | responseFlag = "@"; |
693 | 0 | } |
694 | 0 | } |
695 | 0 | std::string const modmapFormatVar = |
696 | 0 | cmStrCat("CMAKE_", lang, "_MODULE_MAP_FORMAT"); |
697 | 0 | std::string const modmapFormat = |
698 | 0 | this->Makefile->GetSafeDefinition(modmapFormatVar); |
699 | |
|
700 | 0 | auto rulePlaceholderExpander = |
701 | 0 | this->GetLocalGenerator()->CreateRulePlaceholderExpander(); |
702 | |
|
703 | 0 | std::string const tdi = this->ConvertToOutputFormatForShell( |
704 | 0 | this->ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config))); |
705 | |
|
706 | 0 | std::string launcher; |
707 | 0 | std::string val = this->GetLocalGenerator()->GetRuleLauncher( |
708 | 0 | this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE", config); |
709 | 0 | if (cmNonempty(val)) { |
710 | 0 | launcher = cmStrCat(val, ' '); |
711 | 0 | } |
712 | |
|
713 | 0 | std::string const cmakeCmd = |
714 | 0 | this->ConvertToOutputFormatForShell(cmSystemTools::GetCMakeCommand()); |
715 | |
|
716 | 0 | if (withScanning == WithScanning::Yes) { |
717 | 0 | auto const& scanDepType = this->GetMakefile()->GetSafeDefinition( |
718 | 0 | cmStrCat("CMAKE_", lang, "_SCANDEP_DEPFILE_FORMAT")); |
719 | | |
720 | | // Rule to scan dependencies of sources that need preprocessing. |
721 | 0 | { |
722 | 0 | cmList scanCommands; |
723 | 0 | std::string scanRuleName; |
724 | 0 | std::string ppFileName; |
725 | 0 | if (compilationPreprocesses) { |
726 | 0 | scanRuleName = this->LanguageScanRule(lang, config); |
727 | 0 | ppFileName = "$PREPROCESSED_OUTPUT_FILE"; |
728 | 0 | std::string const& scanCommand = mf->GetRequiredDefinition( |
729 | 0 | cmStrCat("CMAKE_", lang, "_SCANDEP_SOURCE")); |
730 | 0 | scanCommands.assign(scanCommand); |
731 | 0 | for (auto& i : scanCommands) { |
732 | 0 | i = cmStrCat(launcher, i); |
733 | 0 | } |
734 | 0 | } else { |
735 | 0 | scanRuleName = this->LanguagePreprocessAndScanRule(lang, config); |
736 | 0 | ppFileName = "$out"; |
737 | 0 | std::string const& ppCommand = mf->GetRequiredDefinition( |
738 | 0 | cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE")); |
739 | 0 | scanCommands.assign(ppCommand); |
740 | 0 | for (auto& i : scanCommands) { |
741 | 0 | i = cmStrCat(launcher, i); |
742 | 0 | } |
743 | 0 | scanCommands.emplace_back(GetScanCommand( |
744 | 0 | cmakeCmd, tdi, lang, "$out", "$DYNDEP_INTERMEDIATE_FILE", "$in")); |
745 | 0 | } |
746 | |
|
747 | 0 | auto scanRule = GetScanRule( |
748 | 0 | scanRuleName, ppFileName, scanDepType, vars, responseFlag, flags, |
749 | 0 | rulePlaceholderExpander.get(), this->GetLocalGenerator(), |
750 | 0 | std::move(scanCommands), config); |
751 | |
|
752 | 0 | scanRule.Comment = |
753 | 0 | cmStrCat("Rule for generating ", lang, " dependencies."); |
754 | 0 | if (compilationPreprocesses) { |
755 | 0 | scanRule.Description = |
756 | 0 | cmStrCat("Scanning $in for ", lang, " dependencies"); |
757 | 0 | } else { |
758 | 0 | scanRule.Description = |
759 | 0 | cmStrCat("Building ", lang, " preprocessed $out"); |
760 | 0 | } |
761 | |
|
762 | 0 | this->GetGlobalGenerator()->AddRule(scanRule); |
763 | 0 | } |
764 | |
|
765 | 0 | if (!compilationPreprocesses) { |
766 | | // Compilation will not preprocess, so it does not need the defines |
767 | | // unless the compiler wants them for some other purpose. |
768 | 0 | if (!this->CompileWithDefines(lang)) { |
769 | 0 | vars.Defines = ""; |
770 | 0 | } |
771 | | |
772 | | // Rule to scan dependencies of sources that do not need preprocessing. |
773 | 0 | std::string const& scanRuleName = this->LanguageScanRule(lang, config); |
774 | 0 | std::vector<std::string> scanCommands; |
775 | 0 | scanCommands.emplace_back( |
776 | 0 | GetScanCommand(cmakeCmd, tdi, lang, "$in", "$out")); |
777 | |
|
778 | 0 | auto scanRule = |
779 | 0 | GetScanRule(scanRuleName, "", scanDepType, vars, "", flags, |
780 | 0 | rulePlaceholderExpander.get(), this->GetLocalGenerator(), |
781 | 0 | std::move(scanCommands), config); |
782 | | |
783 | | // Write the rule for generating dependencies for the given language. |
784 | 0 | scanRule.Comment = cmStrCat("Rule for generating ", lang, |
785 | 0 | " dependencies on non-preprocessed files."); |
786 | 0 | scanRule.Description = |
787 | 0 | cmStrCat("Generating ", lang, " dependencies for $in"); |
788 | |
|
789 | 0 | this->GetGlobalGenerator()->AddRule(scanRule); |
790 | 0 | } |
791 | | |
792 | | // Write the rule for ninja dyndep file generation. |
793 | 0 | cmNinjaRule rule(this->LanguageDyndepRule(lang, config)); |
794 | | // Command line length is almost always limited -> use response file for |
795 | | // dyndep rules |
796 | 0 | rule.RspFile = "$out.rsp"; |
797 | 0 | rule.RspContent = "$in"; |
798 | | // Ninja's collator writes all outputs using `cmGeneratedFileStream`, so |
799 | | // they are only updated if contents actually change. Avoid running |
800 | | // dependent jobs if the contents don't change by telling `ninja` to check |
801 | | // the timestamp again. |
802 | 0 | rule.Restat = "1"; |
803 | | |
804 | | // Run CMake dependency scanner on the source file (using the preprocessed |
805 | | // source if that was performed). |
806 | 0 | std::string ddModmapArg; |
807 | 0 | if (!modmapFormat.empty()) { |
808 | 0 | ddModmapArg += cmStrCat(" --modmapfmt=", modmapFormat); |
809 | 0 | } |
810 | 0 | { |
811 | 0 | std::vector<std::string> ddCmds; |
812 | 0 | { |
813 | 0 | std::string ccmd = cmStrCat( |
814 | 0 | cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi, " --lang=", lang, |
815 | 0 | ddModmapArg, " --dd=$out @", rule.RspFile); |
816 | 0 | ddCmds.emplace_back(std::move(ccmd)); |
817 | 0 | } |
818 | 0 | rule.Command = |
819 | 0 | this->GetLocalGenerator()->BuildCommandLine(ddCmds, config, config); |
820 | 0 | } |
821 | 0 | rule.Comment = |
822 | 0 | cmStrCat("Rule to generate ninja dyndep files for ", lang, '.'); |
823 | 0 | rule.Description = cmStrCat("Generating ", lang, " dyndep file $out"); |
824 | 0 | this->GetGlobalGenerator()->AddRule(rule); |
825 | 0 | } |
826 | |
|
827 | 0 | cmNinjaRule rule(this->LanguageCompilerRule(lang, config, withScanning)); |
828 | | // If using a response file, move defines, includes, and flags into it. |
829 | 0 | if (!responseFlag.empty()) { |
830 | 0 | rule.RspFile = "$RSP_FILE"; |
831 | 0 | rule.RspContent = |
832 | 0 | cmStrCat(' ', vars.Defines, ' ', vars.Includes, ' ', flags); |
833 | 0 | flags = cmStrCat(responseFlag, rule.RspFile); |
834 | 0 | vars.Defines = ""; |
835 | 0 | vars.Includes = ""; |
836 | | |
837 | | // Swift consumes all source files in a module at once, which reaches |
838 | | // command line length limits pretty quickly. Inject source files into the |
839 | | // response file in this case as well. |
840 | 0 | if (lang == "Swift") { |
841 | 0 | rule.RspContent = cmStrCat(rule.RspContent, ' ', vars.Source); |
842 | 0 | vars.Source = ""; |
843 | 0 | } |
844 | 0 | } |
845 | | |
846 | | // Tell ninja dependency format so all deps can be loaded into a database |
847 | 0 | std::string cldeps; |
848 | 0 | if (!compilationPreprocesses) { |
849 | | // The compiler will not do preprocessing, so it has no such dependencies. |
850 | 0 | } else if (mf->IsOn(cmStrCat("CMAKE_NINJA_CMCLDEPS_", lang))) { |
851 | | // For the MS resource compiler we need cmcldeps, but skip dependencies |
852 | | // for source-file try_compile cases because they are always fresh. |
853 | 0 | if (!mf->GetIsSourceFileTryCompile()) { |
854 | 0 | rule.DepType = "gcc"; |
855 | 0 | rule.DepFile = "$DEP_FILE"; |
856 | 0 | cmValue d = mf->GetDefinition("CMAKE_C_COMPILER"); |
857 | 0 | std::string const cl = |
858 | 0 | d ? *d : mf->GetSafeDefinition("CMAKE_CXX_COMPILER"); |
859 | 0 | std::string cmcldepsPath; |
860 | 0 | cmSystemTools::GetShortPath(cmSystemTools::GetCMClDepsCommand(), |
861 | 0 | cmcldepsPath); |
862 | 0 | cldeps = cmStrCat(cmcldepsPath, ' ', lang, ' ', vars.Source, |
863 | 0 | " $DEP_FILE $out \"", |
864 | 0 | mf->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX"), |
865 | 0 | "\" \"", cl, "\" "); |
866 | 0 | } |
867 | 0 | } else { |
868 | 0 | auto const& depType = this->GetMakefile()->GetSafeDefinition( |
869 | 0 | cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT")); |
870 | 0 | if (depType == "msvc"_s) { |
871 | 0 | rule.DepType = "msvc"; |
872 | 0 | rule.DepFile.clear(); |
873 | 0 | } else { |
874 | 0 | rule.DepType = "gcc"; |
875 | 0 | rule.DepFile = "$DEP_FILE"; |
876 | 0 | } |
877 | 0 | vars.DependencyFile = rule.DepFile.c_str(); |
878 | 0 | vars.DependencyTarget = "$out"; |
879 | |
|
880 | 0 | std::string const flagsName = cmStrCat("CMAKE_DEPFILE_FLAGS_", lang); |
881 | 0 | std::string depfileFlags = mf->GetSafeDefinition(flagsName); |
882 | 0 | if (!depfileFlags.empty()) { |
883 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), |
884 | 0 | depfileFlags, vars); |
885 | 0 | flags += cmStrCat(' ', depfileFlags); |
886 | 0 | } |
887 | 0 | } |
888 | |
|
889 | 0 | if (withScanning == WithScanning::Yes && !modmapFormat.empty()) { |
890 | 0 | std::string modmapFlags = |
891 | 0 | mf->GetRequiredDefinition(cmStrCat("CMAKE_", lang, "_MODULE_MAP_FLAG")); |
892 | 0 | cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>", |
893 | 0 | "$DYNDEP_MODULE_MAP_FILE"); |
894 | 0 | flags += cmStrCat(' ', modmapFlags); |
895 | 0 | } |
896 | |
|
897 | 0 | vars.Flags = flags.c_str(); |
898 | 0 | vars.DependencyFile = rule.DepFile.c_str(); |
899 | |
|
900 | 0 | std::string cudaCompileMode; |
901 | 0 | if (lang == "CUDA") { |
902 | 0 | if (this->GeneratorTarget->GetPropertyAsBool( |
903 | 0 | "CUDA_SEPARABLE_COMPILATION")) { |
904 | 0 | std::string const& rdcFlag = |
905 | 0 | this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG"); |
906 | 0 | cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, ' '); |
907 | 0 | } |
908 | 0 | static std::array<cm::string_view, 4> const compileModes{ |
909 | 0 | { "PTX"_s, "CUBIN"_s, "FATBIN"_s, "OPTIX"_s } |
910 | 0 | }; |
911 | 0 | bool useNormalCompileMode = true; |
912 | 0 | for (cm::string_view mode : compileModes) { |
913 | 0 | auto propName = cmStrCat("CUDA_", mode, "_COMPILATION"); |
914 | 0 | auto defName = cmStrCat("_CMAKE_CUDA_", mode, "_FLAG"); |
915 | 0 | if (this->GeneratorTarget->GetPropertyAsBool(propName)) { |
916 | 0 | std::string const& flag = |
917 | 0 | this->Makefile->GetRequiredDefinition(defName); |
918 | 0 | cudaCompileMode = cmStrCat(cudaCompileMode, flag); |
919 | 0 | useNormalCompileMode = false; |
920 | 0 | break; |
921 | 0 | } |
922 | 0 | } |
923 | 0 | if (useNormalCompileMode) { |
924 | 0 | std::string const& wholeFlag = |
925 | 0 | this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG"); |
926 | 0 | cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag); |
927 | 0 | } |
928 | 0 | vars.CudaCompileMode = cudaCompileMode.c_str(); |
929 | 0 | } |
930 | | |
931 | | // Rule for compiling object file. |
932 | 0 | std::string const cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT"); |
933 | 0 | std::string const& compileCmd = mf->GetRequiredDefinition(cmdVar); |
934 | 0 | cmList compileCmds(compileCmd); |
935 | |
|
936 | 0 | if (!compileCmds.empty()) { |
937 | 0 | compileCmds.front().insert(0, "${CODE_CHECK}"); |
938 | 0 | compileCmds.front().insert(0, "${LAUNCHER}"); |
939 | 0 | } |
940 | |
|
941 | 0 | if (!compileCmds.empty()) { |
942 | 0 | compileCmds.front().insert(0, cldeps); |
943 | 0 | } |
944 | |
|
945 | 0 | auto const& extraCommands = this->GetMakefile()->GetSafeDefinition( |
946 | 0 | cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS")); |
947 | 0 | if (!extraCommands.empty()) { |
948 | 0 | compileCmds.append(extraCommands); |
949 | 0 | } |
950 | |
|
951 | 0 | for (auto& i : compileCmds) { |
952 | 0 | i = cmStrCat(launcher, i); |
953 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i, |
954 | 0 | vars); |
955 | 0 | } |
956 | |
|
957 | 0 | rule.Command = |
958 | 0 | this->GetLocalGenerator()->BuildCommandLine(compileCmds, config, config); |
959 | | |
960 | | // Write the rule for compiling file of the given language. |
961 | 0 | rule.Comment = cmStrCat("Rule for compiling ", lang, " files."); |
962 | 0 | rule.Description = cmStrCat("Building ", lang, " object $out"); |
963 | 0 | this->GetGlobalGenerator()->AddRule(rule); |
964 | 0 | } |
965 | | |
966 | | void cmNinjaTargetGenerator::WriteObjectBuildStatements( |
967 | | std::string const& config, std::string const& fileConfig, |
968 | | bool firstForConfig) |
969 | 0 | { |
970 | 0 | this->GeneratorTarget->CheckCxxModuleStatus(config); |
971 | | |
972 | | // Write comments. |
973 | 0 | cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig)); |
974 | 0 | this->GetImplFileStream(fileConfig) |
975 | 0 | << "# Object build statements for " |
976 | 0 | << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) |
977 | 0 | << " target " << this->GetTargetName() << "\n\n"; |
978 | |
|
979 | 0 | std::vector<cmCustomCommand const*> customCommands; |
980 | 0 | { |
981 | 0 | std::vector<cmSourceFile const*> customCommandSources; |
982 | 0 | this->GeneratorTarget->GetCustomCommands(customCommandSources, config); |
983 | 0 | for (cmSourceFile const* sf : customCommandSources) { |
984 | 0 | cmCustomCommand const* cc = sf->GetCustomCommand(); |
985 | 0 | this->GetLocalGenerator()->AddCustomCommandTarget( |
986 | 0 | cc, this->GetGeneratorTarget()); |
987 | 0 | customCommands.push_back(cc); |
988 | 0 | } |
989 | 0 | } |
990 | 0 | { |
991 | 0 | std::vector<cmSourceFile const*> headerSources; |
992 | 0 | this->GeneratorTarget->GetHeaderSources(headerSources, config); |
993 | 0 | this->OSXBundleGenerator->GenerateMacOSXContentStatements( |
994 | 0 | headerSources, this->Configs[fileConfig].MacOSXContentGenerator.get(), |
995 | 0 | config); |
996 | 0 | } |
997 | 0 | { |
998 | 0 | std::vector<cmSourceFile const*> extraSources; |
999 | 0 | this->GeneratorTarget->GetExtraSources(extraSources, config); |
1000 | 0 | this->OSXBundleGenerator->GenerateMacOSXContentStatements( |
1001 | 0 | extraSources, this->Configs[fileConfig].MacOSXContentGenerator.get(), |
1002 | 0 | config); |
1003 | 0 | } |
1004 | 0 | if (firstForConfig) { |
1005 | 0 | cmValue pchExtension = |
1006 | 0 | this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION"); |
1007 | |
|
1008 | 0 | std::vector<cmSourceFile const*> externalObjects; |
1009 | 0 | this->GeneratorTarget->GetExternalObjects(externalObjects, config); |
1010 | 0 | for (cmSourceFile const* sf : externalObjects) { |
1011 | 0 | auto objectFileName = this->GetGlobalGenerator()->ExpandCFGIntDir( |
1012 | 0 | this->ConvertToNinjaPath(sf->GetFullPath()), config); |
1013 | 0 | if (!cmHasSuffix(objectFileName, pchExtension)) { |
1014 | 0 | this->Configs[config].Objects.push_back(objectFileName); |
1015 | 0 | } |
1016 | 0 | } |
1017 | 0 | } |
1018 | |
|
1019 | 0 | if (!this->GetGlobalGenerator()->SupportsCWDDepend()) { |
1020 | | // Ensure that the object directory exists. If there are no objects in the |
1021 | | // target (e.g., an empty `OBJECT` library), the directory is still listed |
1022 | | // as an order-only depends in the build files. Alternate `ninja` |
1023 | | // implementations may not allow this (such as `samu`). See #25526. |
1024 | 0 | auto const objectDir = this->GetObjectFileDir(config); |
1025 | 0 | this->EnsureDirectoryExists(objectDir); |
1026 | 0 | } |
1027 | |
|
1028 | 0 | { |
1029 | 0 | cmNinjaBuild build("phony"); |
1030 | 0 | build.Comment = |
1031 | 0 | cmStrCat("Order-only phony target for ", this->GetTargetName()); |
1032 | 0 | build.Outputs.push_back(this->OrderDependsTargetForTarget(config)); |
1033 | | |
1034 | | // Gather order-only dependencies on custom command outputs. |
1035 | 0 | std::vector<std::string> ccouts; |
1036 | 0 | std::vector<std::string> ccouts_private; |
1037 | 0 | bool usePrivateGeneratedSources = false; |
1038 | 0 | if (this->GeneratorTarget->HasFileSets()) { |
1039 | 0 | switch (this->GetGeneratorTarget()->GetPolicyStatusCMP0154()) { |
1040 | 0 | case cmPolicies::WARN: |
1041 | 0 | case cmPolicies::OLD: |
1042 | 0 | break; |
1043 | 0 | case cmPolicies::NEW: |
1044 | 0 | usePrivateGeneratedSources = true; |
1045 | 0 | break; |
1046 | 0 | } |
1047 | 0 | } |
1048 | 0 | for (cmCustomCommand const* cc : customCommands) { |
1049 | 0 | cmCustomCommandGenerator ccg(*cc, config, this->GetLocalGenerator()); |
1050 | 0 | std::vector<std::string> const& ccoutputs = ccg.GetOutputs(); |
1051 | 0 | std::vector<std::string> const& ccbyproducts = ccg.GetByproducts(); |
1052 | 0 | auto const nPreviousOutputs = ccouts.size(); |
1053 | 0 | ccouts.insert(ccouts.end(), ccoutputs.begin(), ccoutputs.end()); |
1054 | 0 | ccouts.insert(ccouts.end(), ccbyproducts.begin(), ccbyproducts.end()); |
1055 | 0 | if (usePrivateGeneratedSources) { |
1056 | 0 | auto it = ccouts.begin(); |
1057 | | // Skip over outputs that were already detected. |
1058 | 0 | std::advance(it, nPreviousOutputs); |
1059 | 0 | while (it != ccouts.end()) { |
1060 | 0 | cmGeneratorFileSet const* fileset = |
1061 | 0 | this->GeneratorTarget->GetFileSetForSource( |
1062 | 0 | config, this->Makefile->GetOrCreateGeneratedSource(*it)); |
1063 | 0 | bool isVisible = fileset && fileset->IsForInterface(); |
1064 | 0 | bool isIncludeable = !fileset || fileset->CanBeIncluded(); |
1065 | 0 | if (fileset && isVisible && isIncludeable) { |
1066 | 0 | ++it; |
1067 | 0 | continue; |
1068 | 0 | } |
1069 | 0 | if (!fileset || isIncludeable) { |
1070 | 0 | ccouts_private.push_back(*it); |
1071 | 0 | } |
1072 | 0 | it = ccouts.erase(it); |
1073 | 0 | } |
1074 | 0 | } |
1075 | 0 | } |
1076 | |
|
1077 | 0 | cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps; |
1078 | 0 | this->GetLocalGenerator()->AppendTargetDepends( |
1079 | 0 | this->GeneratorTarget, orderOnlyDeps, config, fileConfig, |
1080 | 0 | DependOnTargetOrdering); |
1081 | | |
1082 | | // Add order-only dependencies on other files associated with the target. |
1083 | 0 | cm::append(orderOnlyDeps, this->Configs[config].ExtraFiles); |
1084 | | |
1085 | | // Add order-only dependencies on custom command outputs. |
1086 | 0 | std::transform(ccouts.begin(), ccouts.end(), |
1087 | 0 | std::back_inserter(orderOnlyDeps), this->MapToNinjaPath()); |
1088 | |
|
1089 | 0 | std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end()); |
1090 | 0 | orderOnlyDeps.erase( |
1091 | 0 | std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()), |
1092 | 0 | orderOnlyDeps.end()); |
1093 | | |
1094 | | // The phony target must depend on at least one input or ninja will explain |
1095 | | // that "output ... of phony edge with no inputs doesn't exist" and |
1096 | | // consider the phony output "dirty". |
1097 | 0 | if (orderOnlyDeps.empty()) { |
1098 | 0 | std::string tgtDir; |
1099 | 0 | if (this->GetGlobalGenerator()->SupportsCWDDepend()) { |
1100 | 0 | tgtDir = "."; |
1101 | 0 | } else { |
1102 | | // Any path that always exists will work here. |
1103 | 0 | tgtDir = this->GetObjectFileDir(config); |
1104 | 0 | } |
1105 | 0 | orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir)); |
1106 | 0 | } |
1107 | |
|
1108 | 0 | this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), |
1109 | 0 | build); |
1110 | | |
1111 | | // Add order-only dependencies on custom command outputs that are |
1112 | | // private to this target. |
1113 | 0 | this->HasPrivateGeneratedSources = !ccouts_private.empty(); |
1114 | 0 | if (this->HasPrivateGeneratedSources) { |
1115 | 0 | cmNinjaBuild buildPrivate("phony"); |
1116 | 0 | cmNinjaDeps& orderOnlyDepsPrivate = buildPrivate.OrderOnlyDeps; |
1117 | 0 | orderOnlyDepsPrivate.push_back( |
1118 | 0 | this->OrderDependsTargetForTarget(config)); |
1119 | |
|
1120 | 0 | buildPrivate.Outputs.push_back( |
1121 | 0 | this->OrderDependsTargetForTargetPrivate(config)); |
1122 | |
|
1123 | 0 | std::transform(ccouts_private.begin(), ccouts_private.end(), |
1124 | 0 | std::back_inserter(orderOnlyDepsPrivate), |
1125 | 0 | this->MapToNinjaPath()); |
1126 | |
|
1127 | 0 | std::sort(orderOnlyDepsPrivate.begin(), orderOnlyDepsPrivate.end()); |
1128 | 0 | orderOnlyDepsPrivate.erase( |
1129 | 0 | std::unique(orderOnlyDepsPrivate.begin(), orderOnlyDepsPrivate.end()), |
1130 | 0 | orderOnlyDepsPrivate.end()); |
1131 | |
|
1132 | 0 | this->GetGlobalGenerator()->WriteBuild( |
1133 | 0 | this->GetImplFileStream(fileConfig), buildPrivate); |
1134 | 0 | } |
1135 | 0 | } |
1136 | 0 | { |
1137 | 0 | std::vector<cmSourceFile const*> objectSources; |
1138 | 0 | this->GeneratorTarget->GetObjectSources(objectSources, config); |
1139 | |
|
1140 | 0 | std::vector<cmSourceFile const*> swiftSources; |
1141 | |
|
1142 | 0 | for (cmSourceFile const* sf : objectSources) { |
1143 | 0 | if (this->GetLocalGenerator()->IsSplitSwiftBuild() && |
1144 | 0 | sf->GetLanguage() == "Swift") { |
1145 | 0 | swiftSources.push_back(sf); |
1146 | 0 | } else { |
1147 | 0 | this->WriteObjectBuildStatement(sf, config, fileConfig, |
1148 | 0 | firstForConfig); |
1149 | 0 | } |
1150 | 0 | } |
1151 | 0 | WriteSwiftObjectBuildStatement(swiftSources, config, fileConfig, |
1152 | 0 | firstForConfig); |
1153 | 0 | } |
1154 | |
|
1155 | 0 | { |
1156 | 0 | std::vector<cmSourceFile const*> bmiOnlySources; |
1157 | 0 | this->GeneratorTarget->GetCxxModuleSources(bmiOnlySources, config); |
1158 | |
|
1159 | 0 | for (cmSourceFile const* sf : bmiOnlySources) { |
1160 | 0 | this->WriteCxxModuleBmiBuildStatement(sf, config, fileConfig, |
1161 | 0 | firstForConfig); |
1162 | 0 | } |
1163 | 0 | } |
1164 | | |
1165 | | // Detect sources in `CXX_MODULES` which are not compiled. |
1166 | 0 | { |
1167 | 0 | std::vector<cmSourceFile*> sources; |
1168 | 0 | this->GeneratorTarget->GetSourceFiles(sources, config); |
1169 | 0 | for (cmSourceFile const* sf : sources) { |
1170 | 0 | cmGeneratorFileSet const* fs = |
1171 | 0 | this->GeneratorTarget->GetFileSetForSource(config, sf); |
1172 | 0 | if (!fs) { |
1173 | 0 | continue; |
1174 | 0 | } |
1175 | 0 | if (fs->GetType() != cm::FileSetMetadata::CXX_MODULES) { |
1176 | 0 | continue; |
1177 | 0 | } |
1178 | 0 | if (sf->GetLanguage().empty()) { |
1179 | 0 | this->GeneratorTarget->Makefile->IssueMessage( |
1180 | 0 | MessageType::FATAL_ERROR, |
1181 | 0 | cmStrCat("Target \"", this->GeneratorTarget->GetName(), |
1182 | 0 | "\" has source file\n ", sf->GetFullPath(), |
1183 | 0 | "\nin a \"FILE_SET TYPE ", cm::FileSetMetadata::CXX_MODULES, |
1184 | 0 | "\" but it is not scheduled for compilation.")); |
1185 | 0 | } |
1186 | 0 | } |
1187 | 0 | } |
1188 | | |
1189 | | // Check if there are Fortran objects which need to participate in forwarding |
1190 | | // module requirements. |
1191 | 0 | if (this->GeneratorTarget->HaveFortranSources(config) && |
1192 | 0 | !this->Configs[config].ScanningInfo.count("Fortran")) { |
1193 | 0 | ScanningFiles files; |
1194 | 0 | this->Configs[config].ScanningInfo["Fortran"].emplace_back(files); |
1195 | 0 | this->WriteCompileRule("Fortran", config, WithScanning::Yes); |
1196 | 0 | } |
1197 | |
|
1198 | 0 | for (auto const& langScanningFiles : this->Configs[config].ScanningInfo) { |
1199 | 0 | std::string const& language = langScanningFiles.first; |
1200 | 0 | std::vector<ScanningFiles> const& scanningFiles = langScanningFiles.second; |
1201 | |
|
1202 | 0 | cmNinjaBuild build(this->LanguageDyndepRule(language, config)); |
1203 | 0 | build.Outputs.push_back(this->GetDyndepFilePath(language, config)); |
1204 | 0 | build.ImplicitOuts.emplace_back( |
1205 | 0 | cmStrCat(this->GetObjectFileDir(config), '/', language, "Modules.json")); |
1206 | 0 | build.ImplicitDeps.emplace_back( |
1207 | 0 | this->GetTargetDependInfoPath(language, config)); |
1208 | 0 | { |
1209 | 0 | auto bdb_path = |
1210 | 0 | this->GeneratorTarget->BuildDatabasePath(language, config); |
1211 | 0 | if (!bdb_path.empty()) { |
1212 | 0 | build.ImplicitOuts.emplace_back(this->ConvertToNinjaPath(bdb_path)); |
1213 | 0 | } |
1214 | 0 | } |
1215 | 0 | auto bdb_path = this->GeneratorTarget->BuildDatabasePath(language, config); |
1216 | 0 | if (!bdb_path.empty()) { |
1217 | 0 | auto db = cmBuildDatabase::ForTarget(this->GeneratorTarget, config); |
1218 | 0 | auto mcdb_template_path = cmStrCat(bdb_path, ".in"); |
1219 | 0 | db.Write(mcdb_template_path); |
1220 | 0 | build.ImplicitDeps.emplace_back(std::move(mcdb_template_path)); |
1221 | 0 | build.ImplicitOuts.emplace_back(std::move(bdb_path)); |
1222 | 0 | } |
1223 | 0 | for (auto const& scanFiles : scanningFiles) { |
1224 | 0 | if (!scanFiles.ScanningOutput.empty()) { |
1225 | 0 | build.ExplicitDeps.push_back(scanFiles.ScanningOutput); |
1226 | 0 | } |
1227 | 0 | if (!scanFiles.ModuleMapFile.empty()) { |
1228 | 0 | build.ImplicitOuts.push_back(scanFiles.ModuleMapFile); |
1229 | 0 | } |
1230 | 0 | } |
1231 | |
|
1232 | 0 | this->WriteTargetDependInfo(language, config); |
1233 | | |
1234 | | // Non-imported synthetic targets read module info from their native target |
1235 | | // Add as implicit dependency. |
1236 | 0 | if (this->GeneratorTarget->IsSynthetic()) { |
1237 | 0 | if (cmGeneratorTarget const* native_gt = |
1238 | 0 | this->LocalGenerator->FindGeneratorTargetToUse( |
1239 | 0 | this->GeneratorTarget->Target->GetTemplateName())) { |
1240 | 0 | if (!native_gt->IsImported()) { |
1241 | 0 | std::string native_dir = native_gt->GetSupportDirectory(); |
1242 | 0 | if (this->GetGlobalGenerator()->IsMultiConfig()) { |
1243 | 0 | native_dir = cmStrCat(native_dir, '/', config); |
1244 | 0 | } |
1245 | 0 | build.ImplicitDeps.emplace_back(this->ConvertToNinjaPath( |
1246 | 0 | cmStrCat(native_dir, '/', language, "Modules.json"))); |
1247 | 0 | } |
1248 | 0 | } |
1249 | 0 | } |
1250 | |
|
1251 | 0 | auto const linked_directories = |
1252 | 0 | this->GetLinkedTargetDirectories(language, config); |
1253 | 0 | for (std::string const& l : linked_directories.Direct) { |
1254 | 0 | build.ImplicitDeps.emplace_back( |
1255 | 0 | this->ConvertToNinjaPath(cmStrCat(l, '/', language, "Modules.json"))); |
1256 | 0 | } |
1257 | 0 | for (std::string const& l : linked_directories.Forward) { |
1258 | 0 | build.ImplicitDeps.emplace_back( |
1259 | 0 | this->ConvertToNinjaPath(cmStrCat(l, '/', language, "Modules.json"))); |
1260 | 0 | } |
1261 | |
|
1262 | 0 | this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), |
1263 | 0 | build); |
1264 | 0 | } |
1265 | |
|
1266 | 0 | this->GetImplFileStream(fileConfig) << '\n'; |
1267 | 0 | } |
1268 | | |
1269 | | void cmNinjaTargetGenerator::GenerateSwiftOutputFileMap( |
1270 | | std::string const& config, std::string& flags) |
1271 | 0 | { |
1272 | 0 | if (this->Configs[config].SwiftOutputMap.empty()) { |
1273 | 0 | return; |
1274 | 0 | } |
1275 | | |
1276 | 0 | std::string const targetSwiftDepsPath = [this, config]() -> std::string { |
1277 | 0 | cmGeneratorTarget const* target = this->GeneratorTarget; |
1278 | 0 | if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { |
1279 | 0 | return *name; |
1280 | 0 | } |
1281 | 0 | return this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(), |
1282 | 0 | '/', config, '/', |
1283 | 0 | target->GetName(), ".swiftdeps")); |
1284 | 0 | }(); |
1285 | |
|
1286 | 0 | std::string mapFilePath = |
1287 | 0 | cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, |
1288 | 0 | "/" |
1289 | 0 | "output-file-map.json"); |
1290 | | |
1291 | | // build the global target dependencies |
1292 | | // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps |
1293 | 0 | Json::Value deps(Json::objectValue); |
1294 | 0 | deps["swift-dependencies"] = targetSwiftDepsPath; |
1295 | 0 | this->Configs[config].SwiftOutputMap[""] = deps; |
1296 | |
|
1297 | 0 | cmGeneratedFileStream output(mapFilePath); |
1298 | 0 | output << this->Configs[config].SwiftOutputMap; |
1299 | | |
1300 | | // Add flag |
1301 | 0 | this->LocalGenerator->AppendFlags(flags, "-output-file-map"); |
1302 | 0 | this->LocalGenerator->AppendFlags( |
1303 | 0 | flags, |
1304 | 0 | this->ConvertToOutputFormatForShell(ConvertToNinjaPath(mapFilePath))); |
1305 | 0 | } |
1306 | | |
1307 | | namespace { |
1308 | | cmNinjaBuild GetScanBuildStatement(std::string const& ruleName, |
1309 | | std::string const& ppFileName, |
1310 | | bool compilePP, bool compilePPWithDefines, |
1311 | | bool compilationPreprocesses, |
1312 | | cmNinjaBuild& objBuild, cmNinjaVars& vars, |
1313 | | std::string const& objectFileName, |
1314 | | cmNinjaTargetGenerator* tg) |
1315 | 0 | { |
1316 | 0 | cmNinjaBuild scanBuild(ruleName); |
1317 | |
|
1318 | 0 | if (compilePP) { |
1319 | | // Move compilation dependencies to the scan/preprocessing build statement. |
1320 | 0 | std::swap(scanBuild.ExplicitDeps, objBuild.ExplicitDeps); |
1321 | 0 | std::swap(scanBuild.ImplicitDeps, objBuild.ImplicitDeps); |
1322 | 0 | std::swap(scanBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps); |
1323 | 0 | std::swap(scanBuild.Variables["IN_ABS"], vars["IN_ABS"]); |
1324 | | |
1325 | | // The actual compilation will now use the preprocessed source. |
1326 | 0 | objBuild.ExplicitDeps.push_back(ppFileName); |
1327 | 0 | } else { |
1328 | | // Copy compilation dependencies to the scan/preprocessing build statement. |
1329 | 0 | scanBuild.ExplicitDeps = objBuild.ExplicitDeps; |
1330 | 0 | scanBuild.ImplicitDeps = objBuild.ImplicitDeps; |
1331 | 0 | scanBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps; |
1332 | 0 | scanBuild.Variables["IN_ABS"] = vars["IN_ABS"]; |
1333 | 0 | } |
1334 | | |
1335 | | // Scanning and compilation generally use the same flags. |
1336 | 0 | scanBuild.Variables["FLAGS"] = vars["FLAGS"]; |
1337 | |
|
1338 | 0 | if (compilePP && !compilePPWithDefines) { |
1339 | | // Move preprocessor definitions to the scan/preprocessor build statement. |
1340 | 0 | std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]); |
1341 | 0 | } else { |
1342 | | // Copy preprocessor definitions to the scan/preprocessor build statement. |
1343 | 0 | scanBuild.Variables["DEFINES"] = vars["DEFINES"]; |
1344 | 0 | } |
1345 | | |
1346 | | // Copy include directories to the preprocessor build statement. The |
1347 | | // Fortran compilation build statement still needs them for the INCLUDE |
1348 | | // directive. |
1349 | 0 | scanBuild.Variables["INCLUDES"] = vars["INCLUDES"]; |
1350 | | |
1351 | | // Tell dependency scanner the object file that will result from |
1352 | | // compiling the source. |
1353 | 0 | scanBuild.Variables["OBJ_FILE"] = |
1354 | 0 | tg->ConvertToOutputFormatForShell(objectFileName); |
1355 | | |
1356 | | // Tell dependency scanner where to store dyndep intermediate results. |
1357 | 0 | std::string ddiFileName = cmStrCat(objectFileName, ".ddi"); |
1358 | 0 | scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = |
1359 | 0 | tg->ConvertToOutputFormatForShell(ddiFileName); |
1360 | 0 | scanBuild.RspFile = cmStrCat(ddiFileName, ".rsp"); |
1361 | | |
1362 | | // Outputs of the scan/preprocessor build statement. |
1363 | 0 | if (compilePP) { |
1364 | 0 | scanBuild.Outputs.push_back(ppFileName); |
1365 | 0 | scanBuild.ImplicitOuts.push_back(ddiFileName); |
1366 | 0 | } else { |
1367 | 0 | scanBuild.Outputs.push_back(ddiFileName); |
1368 | 0 | scanBuild.Variables["PREPROCESSED_OUTPUT_FILE"] = |
1369 | 0 | tg->ConvertToOutputFormatForShell(ppFileName); |
1370 | 0 | if (!compilationPreprocesses) { |
1371 | | // Compilation does not preprocess and we are not compiling an |
1372 | | // already-preprocessed source. Make compilation depend on the scan |
1373 | | // results to honor implicit dependencies discovered during scanning |
1374 | | // (such as Fortran INCLUDE directives). |
1375 | 0 | objBuild.ImplicitDeps.emplace_back(ddiFileName); |
1376 | 0 | } |
1377 | 0 | } |
1378 | | |
1379 | | // Scanning always provides a depfile for preprocessor dependencies. This |
1380 | | // variable is unused in `msvc`-deptype scanners. |
1381 | 0 | tg->AddDepfileBinding(scanBuild.Variables, |
1382 | 0 | cmStrCat(scanBuild.Outputs.front(), ".d")); |
1383 | 0 | if (compilePP) { |
1384 | | // The actual compilation does not need a depfile because it |
1385 | | // depends on the already-preprocessed source. |
1386 | 0 | tg->RemoveDepfileBinding(vars); |
1387 | 0 | } |
1388 | |
|
1389 | 0 | return scanBuild; |
1390 | 0 | } |
1391 | | } |
1392 | | |
1393 | | void cmNinjaTargetGenerator::WriteObjectBuildStatement( |
1394 | | cmSourceFile const* source, std::string const& config, |
1395 | | std::string const& fileConfig, bool firstForConfig) |
1396 | 0 | { |
1397 | 0 | std::string const language = source->GetLanguage(); |
1398 | 0 | std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(source); |
1399 | 0 | std::string const targetSupportDir = |
1400 | 0 | this->ConvertToNinjaPath(this->GeneratorTarget->GetCMFSupportDirectory()); |
1401 | 0 | std::string const objectDir = |
1402 | 0 | this->ConvertToNinjaPath(this->GetObjectFileDir(config)); |
1403 | 0 | std::string const objectFileName = |
1404 | 0 | this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)); |
1405 | 0 | std::string const objectFileDir = |
1406 | 0 | cmSystemTools::GetFilenamePath(objectFileName); |
1407 | |
|
1408 | 0 | std::string cmakeVarLang = cmStrCat("CMAKE_", language); |
1409 | | |
1410 | | // build response file name |
1411 | 0 | std::string cmakeLinkVar = cmStrCat(cmakeVarLang, "_RESPONSE_FILE_FLAG"); |
1412 | |
|
1413 | 0 | cmValue flag = this->GetMakefile()->GetDefinition(cmakeLinkVar); |
1414 | |
|
1415 | 0 | bool const lang_supports_response = |
1416 | 0 | !(language == "RC" || (language == "CUDA" && !flag)); |
1417 | 0 | int const commandLineLengthLimit = |
1418 | 0 | ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0; |
1419 | 0 | cmValue pchExtension = |
1420 | 0 | this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION"); |
1421 | 0 | bool const isPch = cmHasSuffix(objectFileName, pchExtension); |
1422 | 0 | bool const needDyndep = !isPch && |
1423 | 0 | this->GeneratorTarget->NeedDyndepForSource(language, config, source); |
1424 | |
|
1425 | 0 | WithScanning withScanning = |
1426 | 0 | needDyndep ? WithScanning::Yes : WithScanning::No; |
1427 | 0 | cmNinjaBuild objBuild( |
1428 | 0 | this->LanguageCompilerRule(language, config, withScanning)); |
1429 | 0 | cmNinjaVars& vars = objBuild.Variables; |
1430 | 0 | vars["FLAGS"] = |
1431 | 0 | this->ComputeFlagsForObject(source, language, config, objectFileName); |
1432 | 0 | vars["DEFINES"] = this->ComputeDefines(source, language, config); |
1433 | 0 | vars["INCLUDES"] = this->ComputeIncludes(source, language, config); |
1434 | 0 | vars["CONFIG"] = config; |
1435 | 0 | if (this->GetGeneratorTarget()->GetUseShortObjectNames()) { |
1436 | 0 | vars.emplace( |
1437 | 0 | "description", |
1438 | 0 | cmStrCat("Compiling object ", objectFileName, " from source ", |
1439 | 0 | this->GetLocalGenerator()->GetRelativeSourceFileName(*source))); |
1440 | 0 | } |
1441 | |
|
1442 | 0 | auto compilerLauncher = this->GetCompilerLauncher(language, config); |
1443 | |
|
1444 | 0 | cmValue const srcSkipCodeCheckVal = source->GetProperty("SKIP_LINTING"); |
1445 | 0 | bool const skipCodeCheck = srcSkipCodeCheckVal.IsSet() |
1446 | 0 | ? srcSkipCodeCheckVal.IsOn() |
1447 | 0 | : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING"); |
1448 | |
|
1449 | 0 | if (!skipCodeCheck) { |
1450 | 0 | auto const cmakeCmd = |
1451 | 0 | this->ConvertToOutputFormatForShell(cmSystemTools::GetCMakeCommand()); |
1452 | 0 | vars["CODE_CHECK"] = |
1453 | 0 | this->GenerateCodeCheckRules(*source, compilerLauncher, cmakeCmd, config, |
1454 | 0 | [this](std::string const& path) { |
1455 | 0 | return this->ConvertToNinjaPath(path); |
1456 | 0 | }); |
1457 | 0 | } |
1458 | | |
1459 | | // If compiler launcher was specified and not consumed above, it |
1460 | | // goes to the beginning of the command line. |
1461 | 0 | if (!compilerLauncher.empty()) { |
1462 | 0 | cmList args{ compilerLauncher, cmList::EmptyElements::Yes }; |
1463 | 0 | if (!args.empty()) { |
1464 | 0 | args[0] = this->LocalGenerator->ConvertToOutputFormat( |
1465 | 0 | args[0], cmOutputConverter::SHELL); |
1466 | 0 | for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) { |
1467 | 0 | i = this->LocalGenerator->EscapeForShell(i); |
1468 | 0 | } |
1469 | 0 | vars["LAUNCHER"] = args.join(" ") + " "; |
1470 | 0 | } |
1471 | 0 | } |
1472 | |
|
1473 | 0 | if (this->GetMakefile()->GetSafeDefinition( |
1474 | 0 | cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT")) != "msvc"_s) { |
1475 | 0 | bool replaceExt = false; |
1476 | 0 | if (!language.empty()) { |
1477 | 0 | std::string repVar = |
1478 | 0 | cmStrCat("CMAKE_", language, "_DEPFILE_EXTENSION_REPLACE"); |
1479 | 0 | replaceExt = this->Makefile->IsOn(repVar); |
1480 | 0 | } |
1481 | 0 | this->AddDepfileBinding( |
1482 | 0 | vars, |
1483 | 0 | replaceExt ? cmStrCat(objectFileDir, '/', |
1484 | 0 | cmSystemTools::GetFilenameWithoutLastExtension( |
1485 | 0 | objectFileName), |
1486 | 0 | ".d") |
1487 | 0 | : cmStrCat(objectFileName, ".d")); |
1488 | 0 | } |
1489 | |
|
1490 | 0 | this->SetMsvcTargetPdbVariable(vars, config); |
1491 | |
|
1492 | 0 | if (firstForConfig) { |
1493 | 0 | this->ExportObjectCompileCommand( |
1494 | 0 | language, sourceFilePath, objectDir, targetSupportDir, objectFileName, |
1495 | 0 | objectFileDir, vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], |
1496 | 0 | vars["TARGET_COMPILE_PDB"], vars["TARGET_PDB"], config, withScanning); |
1497 | 0 | } |
1498 | |
|
1499 | 0 | objBuild.Outputs.push_back(objectFileName); |
1500 | 0 | if (firstForConfig && !isPch) { |
1501 | | // Add this object to the list of object files. |
1502 | 0 | this->Configs[config].Objects.push_back(objectFileName); |
1503 | 0 | } |
1504 | |
|
1505 | 0 | objBuild.ExplicitDeps.push_back(sourceFilePath); |
1506 | | |
1507 | | // Add precompile headers dependencies |
1508 | 0 | std::vector<std::string> depList; |
1509 | |
|
1510 | 0 | std::vector<std::string> pchArchs = |
1511 | 0 | this->GeneratorTarget->GetPchArchs(config, language); |
1512 | |
|
1513 | 0 | std::unordered_set<std::string> pchSources; |
1514 | 0 | for (std::string const& arch : pchArchs) { |
1515 | 0 | std::string const pchSource = |
1516 | 0 | this->GeneratorTarget->GetPchSource(config, language, arch); |
1517 | |
|
1518 | 0 | if (!pchSource.empty()) { |
1519 | 0 | pchSources.insert(pchSource); |
1520 | 0 | } |
1521 | 0 | } |
1522 | |
|
1523 | 0 | if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { |
1524 | 0 | for (std::string const& arch : pchArchs) { |
1525 | 0 | depList.push_back( |
1526 | 0 | this->GeneratorTarget->GetPchHeader(config, language, arch)); |
1527 | 0 | if (pchSources.find(source->GetFullPath()) == pchSources.end()) { |
1528 | 0 | depList.push_back( |
1529 | 0 | this->GeneratorTarget->GetPchFile(config, language, arch)); |
1530 | 0 | } |
1531 | 0 | } |
1532 | 0 | } |
1533 | |
|
1534 | 0 | if (cmValue objectDeps = source->GetProperty("OBJECT_DEPENDS")) { |
1535 | 0 | cmList objDepList{ *objectDeps }; |
1536 | 0 | std::copy(objDepList.begin(), objDepList.end(), |
1537 | 0 | std::back_inserter(depList)); |
1538 | 0 | } |
1539 | |
|
1540 | 0 | if (!depList.empty()) { |
1541 | 0 | for (std::string& odi : depList) { |
1542 | 0 | if (cmSystemTools::FileIsFullPath(odi)) { |
1543 | 0 | odi = cmSystemTools::CollapseFullPath(odi); |
1544 | 0 | } |
1545 | 0 | } |
1546 | 0 | std::transform(depList.begin(), depList.end(), |
1547 | 0 | std::back_inserter(objBuild.ImplicitDeps), |
1548 | 0 | this->MapToNinjaPath()); |
1549 | 0 | } |
1550 | |
|
1551 | 0 | if (this->HasPrivateGeneratedSources) { |
1552 | 0 | objBuild.OrderOnlyDeps.push_back( |
1553 | 0 | this->OrderDependsTargetForTargetPrivate(config)); |
1554 | 0 | } else { |
1555 | 0 | objBuild.OrderOnlyDeps.push_back( |
1556 | 0 | this->OrderDependsTargetForTarget(config)); |
1557 | 0 | } |
1558 | | |
1559 | | // If the source file is GENERATED and does not have a custom command |
1560 | | // (either attached to this source file or another one), assume that one of |
1561 | | // the target dependencies, OBJECT_DEPENDS or header file custom commands |
1562 | | // will rebuild the file. |
1563 | 0 | if (source->GetIsGenerated() && |
1564 | 0 | !source->GetPropertyAsBool("__CMAKE_GENERATED_BY_CMAKE") && |
1565 | 0 | !source->GetCustomCommand() && |
1566 | 0 | !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFilePath)) { |
1567 | 0 | this->GetGlobalGenerator()->AddAssumedSourceDependencies( |
1568 | 0 | sourceFilePath, objBuild.OrderOnlyDeps); |
1569 | 0 | } |
1570 | | |
1571 | | // For some cases we scan to dynamically discover dependencies. |
1572 | 0 | bool const compilationPreprocesses = |
1573 | 0 | !this->NeedExplicitPreprocessing(language); |
1574 | |
|
1575 | 0 | std::string modmapFormat; |
1576 | 0 | if (needDyndep) { |
1577 | 0 | std::string const modmapFormatVar = |
1578 | 0 | cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT"); |
1579 | 0 | modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); |
1580 | 0 | } |
1581 | |
|
1582 | 0 | if (needDyndep) { |
1583 | | // If source/target has preprocessing turned off, we still need to |
1584 | | // generate an explicit dependency step |
1585 | 0 | auto const srcpp = source->GetSafeProperty("Fortran_PREPROCESS"); |
1586 | 0 | cmOutputConverter::FortranPreprocess preprocess = |
1587 | 0 | cmOutputConverter::GetFortranPreprocess(srcpp); |
1588 | 0 | if (preprocess == cmOutputConverter::FortranPreprocess::Unset) { |
1589 | 0 | auto const& tgtpp = |
1590 | 0 | this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS"); |
1591 | 0 | preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp); |
1592 | 0 | } |
1593 | |
|
1594 | 0 | bool const compilePP = !compilationPreprocesses && |
1595 | 0 | (preprocess != cmOutputConverter::FortranPreprocess::NotNeeded); |
1596 | 0 | bool const compilePPWithDefines = |
1597 | 0 | compilePP && this->CompileWithDefines(language); |
1598 | |
|
1599 | 0 | std::string scanRuleName; |
1600 | 0 | std::string ppFileName; |
1601 | 0 | if (compilePP) { |
1602 | 0 | scanRuleName = this->LanguagePreprocessAndScanRule(language, config); |
1603 | 0 | ppFileName = this->ConvertToNinjaPath( |
1604 | 0 | this->GetPreprocessedFilePath(source, config)); |
1605 | 0 | } else { |
1606 | 0 | scanRuleName = this->LanguageScanRule(language, config); |
1607 | 0 | ppFileName = cmStrCat(objectFileName, ".ddi.i"); |
1608 | 0 | } |
1609 | |
|
1610 | 0 | cmNinjaBuild ppBuild = GetScanBuildStatement( |
1611 | 0 | scanRuleName, ppFileName, compilePP, compilePPWithDefines, |
1612 | 0 | compilationPreprocesses, objBuild, vars, objectFileName, this); |
1613 | |
|
1614 | 0 | if (compilePP) { |
1615 | | // In case compilation requires flags that are incompatible with |
1616 | | // preprocessing, include them here. |
1617 | 0 | std::string const& postFlag = this->Makefile->GetSafeDefinition( |
1618 | 0 | cmStrCat("CMAKE_", language, "_POSTPROCESS_FLAG")); |
1619 | 0 | this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag); |
1620 | | |
1621 | | // Prepend source file's original directory as an include directory |
1622 | | // so e.g. Fortran INCLUDE statements can look for files in it. |
1623 | 0 | std::vector<std::string> sourceDirectory; |
1624 | 0 | sourceDirectory.push_back( |
1625 | 0 | cmSystemTools::GetParentDirectory(source->GetFullPath())); |
1626 | |
|
1627 | 0 | std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags( |
1628 | 0 | sourceDirectory, this->GeneratorTarget, language, config, false); |
1629 | |
|
1630 | 0 | vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]); |
1631 | 0 | } |
1632 | |
|
1633 | 0 | ScanningFiles scanningFiles; |
1634 | |
|
1635 | 0 | if (firstForConfig) { |
1636 | 0 | scanningFiles.ScanningOutput = cmStrCat(objectFileName, ".ddi"); |
1637 | 0 | } |
1638 | |
|
1639 | 0 | this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), |
1640 | 0 | source, ppBuild.Variables); |
1641 | |
|
1642 | 0 | this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), |
1643 | 0 | ppBuild, commandLineLengthLimit); |
1644 | |
|
1645 | 0 | std::string const dyndep = this->GetDyndepFilePath(language, config); |
1646 | 0 | objBuild.OrderOnlyDeps.push_back(dyndep); |
1647 | 0 | vars["dyndep"] = dyndep; |
1648 | |
|
1649 | 0 | if (!modmapFormat.empty()) { |
1650 | | // XXX(modmap): If changing this path construction, change |
1651 | | // `cmGlobalNinjaGenerator::WriteDyndep` and |
1652 | | // `cmNinjaTargetGenerator::ExportObjectCompileCommand` to expect the |
1653 | | // corresponding file path. |
1654 | 0 | std::string ddModmapFile = cmStrCat(objectFileName, ".modmap"); |
1655 | 0 | vars["DYNDEP_MODULE_MAP_FILE"] = |
1656 | 0 | this->ConvertToOutputFormatForShell(ddModmapFile); |
1657 | 0 | objBuild.ImplicitDeps.push_back(ddModmapFile); |
1658 | 0 | scanningFiles.ModuleMapFile = std::move(ddModmapFile); |
1659 | 0 | } |
1660 | |
|
1661 | 0 | if (!scanningFiles.IsEmpty()) { |
1662 | 0 | this->Configs[config].ScanningInfo[language].emplace_back(scanningFiles); |
1663 | 0 | } |
1664 | 0 | } |
1665 | |
|
1666 | 0 | this->EnsureParentDirectoryExists(objectFileName); |
1667 | |
|
1668 | 0 | vars["OBJECT_DIR"] = this->ConvertToOutputFormatForShell(objectDir); |
1669 | 0 | vars["TARGET_SUPPORT_DIR"] = |
1670 | 0 | this->ConvertToOutputFormatForShell(targetSupportDir); |
1671 | 0 | vars["OBJECT_FILE_DIR"] = this->ConvertToOutputFormatForShell(objectFileDir); |
1672 | |
|
1673 | 0 | this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), |
1674 | 0 | source, vars); |
1675 | |
|
1676 | 0 | if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { |
1677 | 0 | auto pchIt = pchSources.find(source->GetFullPath()); |
1678 | 0 | if (pchIt != pchSources.end()) { |
1679 | 0 | this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER", |
1680 | 0 | this->GetGeneratorTarget(), nullptr, vars); |
1681 | 0 | } |
1682 | 0 | } |
1683 | |
|
1684 | 0 | objBuild.RspFile = cmStrCat(objectFileName, ".rsp"); |
1685 | |
|
1686 | 0 | if (language == "ISPC") { |
1687 | 0 | std::string const& objectName = |
1688 | 0 | this->GeneratorTarget->GetObjectName(source); |
1689 | 0 | std::string ispcSource = |
1690 | 0 | cmSystemTools::GetFilenameWithoutLastExtension(objectName); |
1691 | 0 | ispcSource = cmSystemTools::GetFilenameWithoutLastExtension(ispcSource); |
1692 | |
|
1693 | 0 | cmValue ispcSuffixProp = |
1694 | 0 | this->GeneratorTarget->GetProperty("ISPC_HEADER_SUFFIX"); |
1695 | 0 | assert(ispcSuffixProp); |
1696 | |
|
1697 | 0 | std::string ispcHeaderDirectory = |
1698 | 0 | this->GeneratorTarget->GetObjectDirectory(config); |
1699 | 0 | if (cmValue prop = |
1700 | 0 | this->GeneratorTarget->GetProperty("ISPC_HEADER_DIRECTORY")) { |
1701 | 0 | ispcHeaderDirectory = |
1702 | 0 | cmStrCat(this->LocalGenerator->GetBinaryDirectory(), '/', *prop); |
1703 | 0 | } |
1704 | |
|
1705 | 0 | std::string ispcHeader = |
1706 | 0 | cmStrCat(ispcHeaderDirectory, '/', ispcSource, *ispcSuffixProp); |
1707 | 0 | ispcHeader = this->ConvertToNinjaPath(ispcHeader); |
1708 | | |
1709 | | // Make sure ninja knows what command generates the header |
1710 | 0 | objBuild.ImplicitOuts.push_back(ispcHeader); |
1711 | | |
1712 | | // Make sure ninja knows how to clean the generated header |
1713 | 0 | this->GetGlobalGenerator()->AddAdditionalCleanFile(ispcHeader, config); |
1714 | |
|
1715 | 0 | auto ispcSuffixes = |
1716 | 0 | detail::ComputeISPCObjectSuffixes(this->GeneratorTarget); |
1717 | 0 | if (ispcSuffixes.size() > 1) { |
1718 | 0 | std::string rootObjectDir = |
1719 | 0 | this->GeneratorTarget->GetObjectDirectory(config); |
1720 | 0 | auto ispcSideEffectObjects = detail::ComputeISPCExtraObjects( |
1721 | 0 | objectName, rootObjectDir, ispcSuffixes); |
1722 | |
|
1723 | 0 | for (auto sideEffect : ispcSideEffectObjects) { |
1724 | 0 | sideEffect = this->ConvertToNinjaPath(sideEffect); |
1725 | 0 | objBuild.ImplicitOuts.emplace_back(sideEffect); |
1726 | 0 | this->GetGlobalGenerator()->AddAdditionalCleanFile(sideEffect, config); |
1727 | 0 | } |
1728 | 0 | } |
1729 | |
|
1730 | 0 | vars["ISPC_HEADER_FILE"] = this->ConvertToOutputFormatForShell(ispcHeader); |
1731 | 0 | } else { |
1732 | 0 | auto headers = this->GeneratorTarget->GetGeneratedISPCHeaders(config); |
1733 | 0 | if (!headers.empty()) { |
1734 | 0 | std::transform(headers.begin(), headers.end(), headers.begin(), |
1735 | 0 | this->MapToNinjaPath()); |
1736 | 0 | objBuild.OrderOnlyDeps.insert(objBuild.OrderOnlyDeps.end(), |
1737 | 0 | headers.begin(), headers.end()); |
1738 | 0 | } |
1739 | 0 | } |
1740 | |
|
1741 | 0 | if (language == "Swift") { |
1742 | 0 | this->EmitSwiftDependencyInfo(source, config); |
1743 | 0 | } else { |
1744 | 0 | this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), |
1745 | 0 | objBuild, commandLineLengthLimit); |
1746 | 0 | } |
1747 | |
|
1748 | 0 | if (cmValue objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { |
1749 | 0 | std::string evaluatedObjectOutputs = cmGeneratorExpression::Evaluate( |
1750 | 0 | *objectOutputs, this->LocalGenerator, config); |
1751 | |
|
1752 | 0 | if (!evaluatedObjectOutputs.empty()) { |
1753 | 0 | cmNinjaBuild build("phony"); |
1754 | 0 | build.Comment = "Additional output files."; |
1755 | 0 | build.Outputs = cmList{ evaluatedObjectOutputs }.data(); |
1756 | 0 | std::transform(build.Outputs.begin(), build.Outputs.end(), |
1757 | 0 | build.Outputs.begin(), this->MapToNinjaPath()); |
1758 | 0 | build.ExplicitDeps = objBuild.Outputs; |
1759 | 0 | this->GetGlobalGenerator()->WriteBuild( |
1760 | 0 | this->GetImplFileStream(fileConfig), build); |
1761 | 0 | } |
1762 | 0 | } |
1763 | 0 | } |
1764 | | |
1765 | | void cmNinjaTargetGenerator::WriteCxxModuleBmiBuildStatement( |
1766 | | cmSourceFile const* source, std::string const& config, |
1767 | | std::string const& fileConfig, bool firstForConfig) |
1768 | 0 | { |
1769 | 0 | std::string const language = source->GetLanguage(); |
1770 | 0 | if (language != "CXX"_s) { |
1771 | 0 | this->GetMakefile()->IssueMessage( |
1772 | 0 | MessageType::FATAL_ERROR, |
1773 | 0 | cmStrCat("Source file '", source->GetFullPath(), "' of target '", |
1774 | 0 | this->GetTargetName(), "' is a '", language, |
1775 | 0 | "' source but must be 'CXX' in order to have a BMI build " |
1776 | 0 | "statement generated.")); |
1777 | 0 | return; |
1778 | 0 | } |
1779 | | |
1780 | 0 | std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(source); |
1781 | 0 | std::string const targetSupportDir = |
1782 | 0 | this->ConvertToNinjaPath(this->GeneratorTarget->GetCMFSupportDirectory()); |
1783 | 0 | std::string const bmiDir = this->ConvertToNinjaPath( |
1784 | 0 | cmStrCat(this->GeneratorTarget->GetSupportDirectory(), |
1785 | 0 | this->GetGlobalGenerator()->ConfigDirectory(config))); |
1786 | 0 | std::string const bmiFileName = |
1787 | 0 | this->ConvertToNinjaPath(this->GetBmiFilePath(source, config)); |
1788 | 0 | std::string const bmiFileDir = cmSystemTools::GetFilenamePath(bmiFileName); |
1789 | |
|
1790 | 0 | int const commandLineLengthLimit = this->ForceResponseFile() ? -1 : 0; |
1791 | |
|
1792 | 0 | cmNinjaBuild bmiBuild( |
1793 | 0 | this->LanguageCompilerRule(language, config, WithScanning::Yes)); |
1794 | 0 | cmNinjaVars& vars = bmiBuild.Variables; |
1795 | 0 | vars["FLAGS"] = |
1796 | 0 | this->ComputeFlagsForObject(source, language, config, bmiFileName); |
1797 | 0 | vars["DEFINES"] = this->ComputeDefines(source, language, config); |
1798 | 0 | vars["INCLUDES"] = this->ComputeIncludes(source, language, config); |
1799 | 0 | vars["CONFIG"] = config; |
1800 | |
|
1801 | 0 | if (this->GetMakefile()->GetSafeDefinition( |
1802 | 0 | cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT")) != "msvc"_s) { |
1803 | 0 | bool replaceExt = false; |
1804 | 0 | if (!language.empty()) { |
1805 | 0 | std::string repVar = |
1806 | 0 | cmStrCat("CMAKE_", language, "_DEPFILE_EXTENSION_REPLACE"); |
1807 | 0 | replaceExt = this->Makefile->IsOn(repVar); |
1808 | 0 | } |
1809 | 0 | this->AddDepfileBinding( |
1810 | 0 | vars, |
1811 | 0 | replaceExt |
1812 | 0 | ? cmStrCat(bmiFileDir, '/', |
1813 | 0 | cmSystemTools::GetFilenameWithoutLastExtension(bmiFileName), |
1814 | 0 | ".d") |
1815 | 0 | : cmStrCat(bmiFileName, ".d")); |
1816 | 0 | } |
1817 | |
|
1818 | 0 | std::string d = |
1819 | 0 | this->GeneratorTarget->GetClangTidyExportFixesDirectory(language); |
1820 | 0 | if (!d.empty()) { |
1821 | 0 | this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d); |
1822 | 0 | std::string fixesFile = |
1823 | 0 | this->GetClangTidyReplacementsFilePath(d, *source, config); |
1824 | 0 | this->GlobalCommonGenerator->AddClangTidyExportFixesFile(fixesFile); |
1825 | 0 | cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(fixesFile)); |
1826 | 0 | fixesFile = this->ConvertToNinjaPath(fixesFile); |
1827 | 0 | vars["CLANG_TIDY_EXPORT_FIXES"] = fixesFile; |
1828 | 0 | } |
1829 | |
|
1830 | 0 | this->SetMsvcTargetPdbVariable(vars, config); |
1831 | |
|
1832 | 0 | if (firstForConfig) { |
1833 | 0 | this->ExportObjectCompileCommand( |
1834 | 0 | language, sourceFilePath, bmiDir, targetSupportDir, bmiFileName, |
1835 | 0 | bmiFileDir, vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], |
1836 | 0 | vars["TARGET_COMPILE_PDB"], vars["TARGET_PDB"], config, |
1837 | 0 | WithScanning::Yes); |
1838 | 0 | } |
1839 | |
|
1840 | 0 | bmiBuild.Outputs.push_back(bmiFileName); |
1841 | 0 | bmiBuild.ExplicitDeps.push_back(sourceFilePath); |
1842 | |
|
1843 | 0 | std::vector<std::string> depList; |
1844 | |
|
1845 | 0 | bmiBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config)); |
1846 | | |
1847 | | // For some cases we scan to dynamically discover dependencies. |
1848 | 0 | std::string modmapFormat; |
1849 | 0 | if (true) { |
1850 | 0 | std::string const modmapFormatVar = |
1851 | 0 | cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT"); |
1852 | 0 | modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); |
1853 | 0 | } |
1854 | |
|
1855 | 0 | { |
1856 | 0 | bool const compilePPWithDefines = this->CompileWithDefines(language); |
1857 | |
|
1858 | 0 | std::string scanRuleName = this->LanguageScanRule(language, config); |
1859 | 0 | std::string ppFileName = cmStrCat(bmiFileName, ".ddi.i"); |
1860 | |
|
1861 | 0 | cmNinjaBuild ppBuild = GetScanBuildStatement( |
1862 | 0 | scanRuleName, ppFileName, false, compilePPWithDefines, true, bmiBuild, |
1863 | 0 | vars, bmiFileName, this); |
1864 | |
|
1865 | 0 | ScanningFiles scanningFiles; |
1866 | |
|
1867 | 0 | if (firstForConfig) { |
1868 | 0 | scanningFiles.ScanningOutput = cmStrCat(bmiFileName, ".ddi"); |
1869 | 0 | } |
1870 | |
|
1871 | 0 | this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), |
1872 | 0 | source, ppBuild.Variables); |
1873 | |
|
1874 | 0 | this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), |
1875 | 0 | ppBuild, commandLineLengthLimit); |
1876 | |
|
1877 | 0 | std::string const dyndep = this->GetDyndepFilePath(language, config); |
1878 | 0 | bmiBuild.OrderOnlyDeps.push_back(dyndep); |
1879 | 0 | vars["dyndep"] = dyndep; |
1880 | |
|
1881 | 0 | if (!modmapFormat.empty()) { |
1882 | 0 | std::string ddModmapFile = cmStrCat(bmiFileName, ".modmap"); |
1883 | 0 | vars["DYNDEP_MODULE_MAP_FILE"] = |
1884 | 0 | this->ConvertToOutputFormatForShell(ddModmapFile); |
1885 | 0 | scanningFiles.ModuleMapFile = std::move(ddModmapFile); |
1886 | 0 | } |
1887 | |
|
1888 | 0 | if (!scanningFiles.IsEmpty()) { |
1889 | 0 | this->Configs[config].ScanningInfo[language].emplace_back(scanningFiles); |
1890 | 0 | } |
1891 | 0 | } |
1892 | |
|
1893 | 0 | this->EnsureParentDirectoryExists(bmiFileName); |
1894 | |
|
1895 | 0 | vars["OBJECT_DIR"] = this->ConvertToOutputFormatForShell(bmiDir); |
1896 | 0 | vars["TARGET_SUPPORT_DIR"] = |
1897 | 0 | this->ConvertToOutputFormatForShell(targetSupportDir); |
1898 | 0 | vars["OBJECT_FILE_DIR"] = this->ConvertToOutputFormatForShell(bmiFileDir); |
1899 | |
|
1900 | 0 | this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), |
1901 | 0 | source, vars); |
1902 | |
|
1903 | 0 | bmiBuild.RspFile = cmStrCat(bmiFileName, ".rsp"); |
1904 | |
|
1905 | 0 | this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), |
1906 | 0 | bmiBuild, commandLineLengthLimit); |
1907 | 0 | } |
1908 | | |
1909 | | void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement( |
1910 | | std::vector<cmSourceFile const*> const& sources, std::string const& config, |
1911 | | std::string const& fileConfig, bool firstForConfig) |
1912 | 0 | { |
1913 | | // Swift sources are compiled as a module, not individually like with C/C++. |
1914 | | // Flags, header search paths, and definitions are passed to the entire |
1915 | | // module build, but we still need to emit compile-commands for each source |
1916 | | // file in order to support CMAKE_EXPORT_COMPILE_COMMANDS. |
1917 | | // In whole-module mode, with a single thread, the Swift compiler will |
1918 | | // only emit a single object file, but if more than one thread is specified, |
1919 | | // or building in other modes, the compiler will emit multiple object files. |
1920 | | // When building a single-output, we do not provide an output-file-map (OFM), |
1921 | | // and instead pass `-o` to tell the compiler where to write the object. |
1922 | | // When building multiple outputs, we provide an OFM to tell the compiler |
1923 | | // where to put each object. |
1924 | | // |
1925 | | // |
1926 | | // Per-Target (module): |
1927 | | // - Flags |
1928 | | // - Definitions |
1929 | | // - Include paths |
1930 | | // - (single-output) output object filename |
1931 | | // - Swiftmodule |
1932 | | // |
1933 | | // Per-File: |
1934 | | // - compile-command |
1935 | | // - (multi-output) OFM data |
1936 | | // - (multi-output) output object filename |
1937 | | // |
1938 | | // Note: Due to the differences in the build models, we are only able to |
1939 | | // build the object build-graph if we know what mode the target is built in. |
1940 | | // For that, we need the "NEW" behavior for CMP0157. Otherwise, we have to |
1941 | | // fall back on the old "linker" build. Otherwise, this should be |
1942 | | // indistinguishable from the old behavior. |
1943 | |
|
1944 | 0 | if (sources.empty()) { |
1945 | 0 | return; |
1946 | 0 | } |
1947 | | |
1948 | 0 | cmSwiftCompileMode compileMode; |
1949 | 0 | if (cm::optional<cmSwiftCompileMode> optionalCompileMode = |
1950 | 0 | this->LocalGenerator->GetSwiftCompileMode(this->GeneratorTarget, |
1951 | 0 | config)) { |
1952 | 0 | compileMode = *optionalCompileMode; |
1953 | 0 | } else { |
1954 | | // CMP0157 is not NEW, bailing early! |
1955 | 0 | return; |
1956 | 0 | } |
1957 | | |
1958 | 0 | std::string const language = "Swift"; |
1959 | 0 | std::string const objectDir = this->ConvertToNinjaPath( |
1960 | 0 | cmStrCat(this->GeneratorTarget->GetSupportDirectory(), |
1961 | 0 | this->GetGlobalGenerator()->ConfigDirectory(config))); |
1962 | |
|
1963 | 0 | cmGeneratorTarget const& target = *this->GeneratorTarget; |
1964 | 0 | cmNinjaBuild objBuild( |
1965 | 0 | this->LanguageCompilerRule(language, config, WithScanning::No)); |
1966 | 0 | cmNinjaVars& vars = objBuild.Variables; |
1967 | | |
1968 | | // The swift toolchain leaves outputs untouched if there are no meaningful |
1969 | | // changes to input files (e.g. addition of a comment). |
1970 | 0 | vars.emplace("restat", "1"); |
1971 | |
|
1972 | 0 | std::string const moduleName = target.GetSwiftModuleName(); |
1973 | 0 | std::string const moduleFilepath = |
1974 | 0 | this->ConvertToNinjaPath(target.GetSwiftModulePath(config)); |
1975 | |
|
1976 | 0 | vars.emplace("description", |
1977 | 0 | cmStrCat("Building Swift Module '", moduleName, "' with ", |
1978 | 0 | sources.size(), |
1979 | 0 | sources.size() == 1 ? " source" : " sources")); |
1980 | |
|
1981 | 0 | bool const isSingleOutput = [this, compileMode]() -> bool { |
1982 | 0 | bool isMultiThread = false; |
1983 | 0 | if (cmValue numThreadStr = |
1984 | 0 | this->GetMakefile()->GetDefinition("CMAKE_Swift_NUM_THREADS")) { |
1985 | 0 | unsigned long numThreads; |
1986 | 0 | cmStrToULong(*numThreadStr, &numThreads); |
1987 | | // numThreads == 1 is multi-threaded according to swiftc |
1988 | 0 | isMultiThread = numThreads > 0; |
1989 | 0 | } |
1990 | 0 | return !isMultiThread && compileMode == cmSwiftCompileMode::Wholemodule; |
1991 | 0 | }(); |
1992 | | |
1993 | | // Without `-emit-library` or `-emit-executable`, targets with a single |
1994 | | // source file parse as a Swift script instead of like normal source. For |
1995 | | // non-executable targets, append this to ensure that they are parsed like a |
1996 | | // normal source. |
1997 | 0 | if (target.GetType() != cmStateEnums::EXECUTABLE) { |
1998 | 0 | this->LocalGenerator->AppendFlags(vars["FLAGS"], "-parse-as-library"); |
1999 | 0 | } |
2000 | |
|
2001 | 0 | if (target.GetType() == cmStateEnums::STATIC_LIBRARY) { |
2002 | 0 | this->LocalGenerator->AppendFlags(vars["FLAGS"], "-static"); |
2003 | 0 | } |
2004 | | |
2005 | | // Does this swift target emit a module file for importing into other |
2006 | | // targets? |
2007 | 0 | auto isImportableTarget = [](cmGeneratorTarget const& tgt) -> bool { |
2008 | | // Everything except for executables that don't export anything should emit |
2009 | | // some way to import them. |
2010 | 0 | if (tgt.GetType() == cmStateEnums::EXECUTABLE) { |
2011 | 0 | return tgt.IsExecutableWithExports(); |
2012 | 0 | } |
2013 | 0 | return true; |
2014 | 0 | }; |
2015 | | |
2016 | | // Swift modules only make sense to emit from things that can be imported. |
2017 | | // Executables that don't export symbols can't be imported, so don't try to |
2018 | | // emit a swiftmodule for them. It will break. |
2019 | 0 | if (isImportableTarget(target)) { |
2020 | 0 | std::string const emitModuleFlag = "-emit-module"; |
2021 | 0 | std::string const modulePathFlag = "-emit-module-path"; |
2022 | 0 | this->LocalGenerator->AppendFlags( |
2023 | 0 | vars["FLAGS"], |
2024 | 0 | { emitModuleFlag, modulePathFlag, |
2025 | 0 | this->LocalGenerator->ConvertToOutputFormat( |
2026 | 0 | moduleFilepath, cmOutputConverter::SHELL) }); |
2027 | 0 | objBuild.Outputs.push_back(moduleFilepath); |
2028 | 0 | } |
2029 | 0 | this->LocalGenerator->AppendFlags(vars["FLAGS"], |
2030 | 0 | cmStrCat("-module-name ", moduleName)); |
2031 | |
|
2032 | 0 | if (target.GetType() != cmStateEnums::EXECUTABLE) { |
2033 | 0 | std::string const libraryLinkNameFlag = "-module-link-name"; |
2034 | 0 | std::string const libraryLinkName = |
2035 | 0 | this->GetGeneratorTarget()->GetLibraryNames(config).Base; |
2036 | 0 | this->LocalGenerator->AppendFlags( |
2037 | 0 | vars["FLAGS"], cmStrCat(libraryLinkNameFlag, ' ', libraryLinkName)); |
2038 | 0 | } |
2039 | |
|
2040 | 0 | this->LocalGenerator->AppendFlags(vars["FLAGS"], |
2041 | 0 | this->GetFlags(language, config)); |
2042 | 0 | vars["DEFINES"] = this->GetDefines(language, config); |
2043 | 0 | vars["INCLUDES"] = this->GetIncludes(language, config); |
2044 | 0 | vars["CONFIG"] = config; |
2045 | | |
2046 | | // target-level object filename |
2047 | 0 | std::string const targetObjectFilename = this->ConvertToNinjaPath(cmStrCat( |
2048 | 0 | objectDir, '/', moduleName, |
2049 | 0 | this->GetGlobalGenerator()->GetLanguageOutputExtension(language))); |
2050 | 0 | objBuild.RspFile = cmStrCat(targetObjectFilename, ".swift.rsp"); |
2051 | |
|
2052 | 0 | if (isSingleOutput) { |
2053 | 0 | this->LocalGenerator->AppendFlags(vars["FLAGS"], |
2054 | 0 | cmStrCat("-o ", targetObjectFilename)); |
2055 | 0 | objBuild.Outputs.push_back(targetObjectFilename); |
2056 | 0 | this->Configs[config].Objects.push_back(targetObjectFilename); |
2057 | 0 | } |
2058 | |
|
2059 | 0 | for (cmSourceFile const* sf : sources) { |
2060 | | // Add dependency to object build on each source file |
2061 | 0 | std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(sf); |
2062 | 0 | objBuild.ExplicitDeps.push_back(sourceFilePath); |
2063 | |
|
2064 | 0 | if (!isSingleOutput) { |
2065 | | // Object outputs |
2066 | 0 | std::string const objectFilepath = |
2067 | 0 | this->ConvertToNinjaPath(this->GetObjectFilePath(sf, config)); |
2068 | 0 | this->EnsureParentDirectoryExists(objectFilepath); |
2069 | 0 | objBuild.Outputs.push_back(objectFilepath); |
2070 | 0 | this->Configs[config].Objects.push_back(objectFilepath); |
2071 | | |
2072 | | // Add OFM data |
2073 | 0 | this->EmitSwiftDependencyInfo(sf, config); |
2074 | 0 | } |
2075 | 0 | } |
2076 | |
|
2077 | 0 | if (!isSingleOutput) { |
2078 | 0 | this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]); |
2079 | 0 | } |
2080 | |
|
2081 | 0 | if (firstForConfig) { |
2082 | 0 | this->ExportSwiftObjectCompileCommand( |
2083 | 0 | sources, targetObjectFilename, vars["FLAGS"], vars["DEFINES"], |
2084 | 0 | vars["INCLUDES"], config, isSingleOutput); |
2085 | 0 | } |
2086 | |
|
2087 | 0 | for (cmTargetDepend const& dep : |
2088 | 0 | this->GetGlobalGenerator()->GetTargetDirectDepends(&target)) { |
2089 | 0 | if (!dep->IsLanguageUsed("Swift", config)) { |
2090 | 0 | continue; |
2091 | 0 | } |
2092 | | |
2093 | | // If the dependency emits a swiftmodule, add a dependency edge on that |
2094 | | // swiftmodule to the ninja build graph. |
2095 | 0 | if (isImportableTarget(*dep)) { |
2096 | 0 | std::string const depModuleFilepath = |
2097 | 0 | this->ConvertToNinjaPath(dep->GetSwiftModulePath(config)); |
2098 | 0 | objBuild.ImplicitDeps.push_back(depModuleFilepath); |
2099 | 0 | } |
2100 | 0 | } |
2101 | |
|
2102 | 0 | objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config)); |
2103 | | |
2104 | | // Write object build |
2105 | 0 | this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), |
2106 | 0 | objBuild, |
2107 | 0 | this->ForceResponseFile() ? -1 : 0); |
2108 | 0 | } |
2109 | | |
2110 | | void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, |
2111 | | std::string const& config) |
2112 | 0 | { |
2113 | 0 | Json::Value tdi(Json::objectValue); |
2114 | 0 | tdi["language"] = lang; |
2115 | 0 | tdi["compiler-id"] = this->Makefile->GetSafeDefinition( |
2116 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_ID")); |
2117 | 0 | tdi["compiler-simulate-id"] = this->Makefile->GetSafeDefinition( |
2118 | 0 | cmStrCat("CMAKE_", lang, "_SIMULATE_ID")); |
2119 | 0 | tdi["compiler-frontend-variant"] = this->Makefile->GetSafeDefinition( |
2120 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_FRONTEND_VARIANT")); |
2121 | |
|
2122 | 0 | std::string mod_dir; |
2123 | 0 | if (lang == "Fortran") { |
2124 | 0 | mod_dir = this->GeneratorTarget->GetFortranModuleDirectory( |
2125 | 0 | this->Makefile->GetHomeOutputDirectory()); |
2126 | 0 | } else if (lang == "CXX") { |
2127 | 0 | mod_dir = this->GetGlobalGenerator()->ExpandCFGIntDir( |
2128 | 0 | cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory), |
2129 | 0 | config); |
2130 | 0 | } |
2131 | 0 | if (mod_dir.empty()) { |
2132 | 0 | mod_dir = this->Makefile->GetCurrentBinaryDirectory(); |
2133 | 0 | } |
2134 | 0 | tdi["module-dir"] = mod_dir; |
2135 | |
|
2136 | 0 | if (lang == "Fortran") { |
2137 | 0 | tdi["submodule-sep"] = |
2138 | 0 | this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP"); |
2139 | 0 | tdi["submodule-ext"] = |
2140 | 0 | this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT"); |
2141 | 0 | } else if (lang == "CXX") { |
2142 | | // No extra information necessary. |
2143 | 0 | } |
2144 | |
|
2145 | 0 | tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory(); |
2146 | 0 | tdi["dir-cur-src"] = this->Makefile->GetCurrentSourceDirectory(); |
2147 | 0 | tdi["dir-top-bld"] = this->Makefile->GetHomeOutputDirectory(); |
2148 | 0 | tdi["dir-top-src"] = this->Makefile->GetHomeDirectory(); |
2149 | |
|
2150 | 0 | Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue; |
2151 | 0 | std::vector<std::string> includes; |
2152 | 0 | this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, |
2153 | 0 | lang, config); |
2154 | 0 | for (std::string const& i : includes) { |
2155 | | // Convert the include directories the same way we do for -I flags. |
2156 | | // See upstream ninja issue 1251. |
2157 | 0 | tdi_include_dirs.append(this->ConvertToNinjaPath(i)); |
2158 | 0 | } |
2159 | |
|
2160 | 0 | Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] = |
2161 | 0 | Json::arrayValue; |
2162 | 0 | auto const linked_directories = |
2163 | 0 | this->GetLinkedTargetDirectories(lang, config); |
2164 | 0 | for (std::string const& l : linked_directories.Direct) { |
2165 | 0 | tdi_linked_target_dirs.append(l); |
2166 | 0 | } |
2167 | |
|
2168 | 0 | Json::Value& tdi_forward_modules_from_target_dirs = |
2169 | 0 | tdi["forward-modules-from-target-dirs"] = Json::arrayValue; |
2170 | 0 | for (std::string const& l : linked_directories.Forward) { |
2171 | 0 | tdi_forward_modules_from_target_dirs.append(l); |
2172 | 0 | } |
2173 | | |
2174 | | // Record the native target support directory for non-imported synthetic |
2175 | | // targets |
2176 | 0 | if (this->GeneratorTarget->IsSynthetic()) { |
2177 | 0 | if (cmGeneratorTarget* nativeGT = |
2178 | 0 | this->LocalGenerator->FindGeneratorTargetToUse( |
2179 | 0 | this->GeneratorTarget->Target->GetTemplateName())) { |
2180 | 0 | if (!nativeGT->IsImported()) { |
2181 | 0 | std::string nativeDir = nativeGT->GetSupportDirectory(); |
2182 | 0 | if (this->GetGlobalGenerator()->IsMultiConfig()) { |
2183 | 0 | nativeDir = cmStrCat(nativeDir, '/', config); |
2184 | 0 | } |
2185 | 0 | tdi["native-target-dir"] = nativeDir; |
2186 | 0 | } |
2187 | 0 | } |
2188 | 0 | } |
2189 | |
|
2190 | 0 | cmDyndepGeneratorCallbacks cb; |
2191 | 0 | cb.ObjectFilePath = [this](cmSourceFile const* sf, std::string const& cnf) { |
2192 | 0 | return this->GetObjectFilePath(sf, cnf); |
2193 | 0 | }; |
2194 | 0 | cb.BmiFilePath = [this](cmSourceFile const* sf, std::string const& cnf) { |
2195 | 0 | return this->GetBmiFilePath(sf, cnf); |
2196 | 0 | }; |
2197 | |
|
2198 | 0 | #if !defined(CMAKE_BOOTSTRAP) |
2199 | 0 | cmDyndepCollation::AddCollationInformation(tdi, this->GeneratorTarget, |
2200 | 0 | config, cb); |
2201 | 0 | #endif |
2202 | |
|
2203 | 0 | std::string const tdin = this->GetTargetDependInfoPath(lang, config); |
2204 | 0 | cmGeneratedFileStream tdif(tdin); |
2205 | 0 | tdif << tdi; |
2206 | 0 | } |
2207 | | |
2208 | | void cmNinjaTargetGenerator::EmitSwiftDependencyInfo( |
2209 | | cmSourceFile const* source, std::string const& config) |
2210 | 0 | { |
2211 | 0 | std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(source); |
2212 | 0 | std::string const objectFilePath = |
2213 | 0 | this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)); |
2214 | 0 | std::string const swiftDepsPath = [source, objectFilePath]() -> std::string { |
2215 | 0 | if (cmValue name = source->GetProperty("Swift_DEPENDENCIES_FILE")) { |
2216 | 0 | return *name; |
2217 | 0 | } |
2218 | 0 | return cmStrCat(objectFilePath, ".swiftdeps"); |
2219 | 0 | }(); |
2220 | 0 | std::string const swiftDiaPath = [source, objectFilePath]() -> std::string { |
2221 | 0 | if (cmValue name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) { |
2222 | 0 | return *name; |
2223 | 0 | } |
2224 | 0 | return cmStrCat(objectFilePath, ".dia"); |
2225 | 0 | }(); |
2226 | 0 | std::string const makeDepsPath = [this, source, config]() -> std::string { |
2227 | 0 | cmLocalNinjaGenerator const* local = this->GetLocalGenerator(); |
2228 | 0 | std::string const objectFileName = |
2229 | 0 | this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)); |
2230 | 0 | std::string const objectFileDir = |
2231 | 0 | cmSystemTools::GetFilenamePath(objectFileName); |
2232 | |
|
2233 | 0 | if (this->Makefile->IsOn("CMAKE_Swift_DEPFLE_EXTNSION_REPLACE")) { |
2234 | 0 | std::string dependFileName = cmStrCat( |
2235 | 0 | cmSystemTools::GetFilenameWithoutLastExtension(objectFileName), ".d"); |
2236 | 0 | return local->ConvertToOutputFormat( |
2237 | 0 | cmStrCat(objectFileDir, '/', dependFileName), |
2238 | 0 | cmOutputConverter::SHELL); |
2239 | 0 | } |
2240 | 0 | return local->ConvertToOutputFormat(cmStrCat(objectFileName, ".d"), |
2241 | 0 | cmOutputConverter::SHELL); |
2242 | 0 | }(); |
2243 | | |
2244 | | // build the source file mapping |
2245 | | // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps |
2246 | 0 | Json::Value entry = Json::Value(Json::objectValue); |
2247 | 0 | entry["object"] = objectFilePath; |
2248 | 0 | entry["dependencies"] = makeDepsPath; |
2249 | 0 | entry["swift-dependencies"] = swiftDepsPath; |
2250 | 0 | entry["diagnostics"] = swiftDiaPath; |
2251 | 0 | this->Configs[config].SwiftOutputMap[sourceFilePath] = entry; |
2252 | 0 | } |
2253 | | |
2254 | | void cmNinjaTargetGenerator::ExportObjectCompileCommand( |
2255 | | std::string const& language, std::string const& sourceFileName, |
2256 | | std::string const& objectDir, std::string const& targetSupportDir, |
2257 | | std::string const& objectFileName, std::string const& objectFileDir, |
2258 | | std::string const& flags, std::string const& defines, |
2259 | | std::string const& includes, std::string const& targetCompilePdb, |
2260 | | std::string const& targetPdb, std::string const& outputConfig, |
2261 | | WithScanning withScanning) |
2262 | 0 | { |
2263 | 0 | if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) { |
2264 | 0 | return; |
2265 | 0 | } |
2266 | | |
2267 | 0 | cmRulePlaceholderExpander::RuleVariables compileObjectVars; |
2268 | 0 | compileObjectVars.Language = language.c_str(); |
2269 | |
|
2270 | 0 | std::string escapedSourceFileName = sourceFileName; |
2271 | |
|
2272 | 0 | if (!cmSystemTools::FileIsFullPath(sourceFileName)) { |
2273 | 0 | escapedSourceFileName = |
2274 | 0 | cmSystemTools::CollapseFullPath(escapedSourceFileName, |
2275 | 0 | this->GetGlobalGenerator() |
2276 | 0 | ->GetCMakeInstance() |
2277 | 0 | ->GetHomeOutputDirectory()); |
2278 | 0 | } |
2279 | |
|
2280 | 0 | escapedSourceFileName = this->LocalGenerator->ConvertToOutputFormat( |
2281 | 0 | escapedSourceFileName, cmOutputConverter::SHELL); |
2282 | |
|
2283 | 0 | std::string fullFlags = flags; |
2284 | 0 | if (withScanning == WithScanning::Yes) { |
2285 | 0 | std::string const modmapFormatVar = |
2286 | 0 | cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT"); |
2287 | 0 | std::string const modmapFormat = |
2288 | 0 | this->Makefile->GetSafeDefinition(modmapFormatVar); |
2289 | 0 | if (!modmapFormat.empty()) { |
2290 | 0 | std::string modmapFlags = this->GetMakefile()->GetRequiredDefinition( |
2291 | 0 | cmStrCat("CMAKE_", language, "_MODULE_MAP_FLAG")); |
2292 | | // XXX(modmap): If changing this path construction, change |
2293 | | // `cmGlobalNinjaGenerator::WriteDyndep` and |
2294 | | // `cmNinjaTargetGenerator::WriteObjectBuildStatement` to expect the |
2295 | | // corresponding file path. |
2296 | 0 | cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>", |
2297 | 0 | cmStrCat(objectFileName, ".modmap")); |
2298 | 0 | fullFlags += cmStrCat(' ', modmapFlags); |
2299 | 0 | } |
2300 | 0 | } |
2301 | |
|
2302 | 0 | compileObjectVars.Source = escapedSourceFileName.c_str(); |
2303 | 0 | std::string escapedObjectFileName = |
2304 | 0 | this->LocalGenerator->ConvertToOutputFormat(objectFileName, |
2305 | 0 | cmOutputConverter::SHELL); |
2306 | 0 | compileObjectVars.Object = escapedObjectFileName.c_str(); |
2307 | 0 | compileObjectVars.ObjectDir = objectDir.c_str(); |
2308 | 0 | compileObjectVars.TargetSupportDir = targetSupportDir.c_str(); |
2309 | 0 | compileObjectVars.ObjectFileDir = objectFileDir.c_str(); |
2310 | 0 | compileObjectVars.Flags = fullFlags.c_str(); |
2311 | 0 | compileObjectVars.Defines = defines.c_str(); |
2312 | 0 | compileObjectVars.Includes = includes.c_str(); |
2313 | 0 | compileObjectVars.TargetCompilePDB = targetCompilePdb.c_str(); |
2314 | 0 | compileObjectVars.TargetPDB = targetPdb.c_str(); |
2315 | | |
2316 | | // Rule for compiling object file. |
2317 | 0 | std::string cudaCompileMode; |
2318 | 0 | if (language == "CUDA") { |
2319 | 0 | if (this->GeneratorTarget->GetPropertyAsBool( |
2320 | 0 | "CUDA_SEPARABLE_COMPILATION")) { |
2321 | 0 | std::string const& rdcFlag = |
2322 | 0 | this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG"); |
2323 | 0 | cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, ' '); |
2324 | 0 | } |
2325 | 0 | static std::array<cm::string_view, 4> const compileModes{ |
2326 | 0 | { "PTX"_s, "CUBIN"_s, "FATBIN"_s, "OPTIX"_s } |
2327 | 0 | }; |
2328 | 0 | bool useNormalCompileMode = true; |
2329 | 0 | for (cm::string_view mode : compileModes) { |
2330 | 0 | auto propName = cmStrCat("CUDA_", mode, "_COMPILATION"); |
2331 | 0 | auto defName = cmStrCat("_CMAKE_CUDA_", mode, "_FLAG"); |
2332 | 0 | if (this->GeneratorTarget->GetPropertyAsBool(propName)) { |
2333 | 0 | std::string const& flag = |
2334 | 0 | this->Makefile->GetRequiredDefinition(defName); |
2335 | 0 | cudaCompileMode = cmStrCat(cudaCompileMode, flag); |
2336 | 0 | useNormalCompileMode = false; |
2337 | 0 | break; |
2338 | 0 | } |
2339 | 0 | } |
2340 | 0 | if (useNormalCompileMode) { |
2341 | 0 | std::string const& wholeFlag = |
2342 | 0 | this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG"); |
2343 | 0 | cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag); |
2344 | 0 | } |
2345 | 0 | compileObjectVars.CudaCompileMode = cudaCompileMode.c_str(); |
2346 | 0 | } |
2347 | |
|
2348 | 0 | std::string const cmdVar = cmStrCat("CMAKE_", language, "_COMPILE_OBJECT"); |
2349 | 0 | std::string const& compileCmd = |
2350 | 0 | this->Makefile->GetRequiredDefinition(cmdVar); |
2351 | 0 | cmList compileCmds(compileCmd); |
2352 | |
|
2353 | 0 | auto rulePlaceholderExpander = |
2354 | 0 | this->GetLocalGenerator()->CreateRulePlaceholderExpander(); |
2355 | |
|
2356 | 0 | for (auto& i : compileCmds) { |
2357 | | // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS |
2358 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i, |
2359 | 0 | compileObjectVars); |
2360 | 0 | } |
2361 | |
|
2362 | 0 | std::string cmdLine = this->GetLocalGenerator()->BuildCommandLine( |
2363 | 0 | compileCmds, outputConfig, outputConfig); |
2364 | |
|
2365 | 0 | this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName, |
2366 | 0 | objectFileName); |
2367 | 0 | } |
2368 | | |
2369 | | void cmNinjaTargetGenerator::ExportSwiftObjectCompileCommand( |
2370 | | std::vector<cmSourceFile const*> const& moduleSourceFiles, |
2371 | | std::string const& moduleObjectFilename, std::string const& flags, |
2372 | | std::string const& defines, std::string const& includes, |
2373 | | std::string const& outputConfig, bool singleOutput) |
2374 | 0 | { |
2375 | 0 | if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) { |
2376 | 0 | return; |
2377 | 0 | } |
2378 | | |
2379 | 0 | auto escapeSourceFileName = [this](std::string srcFilename) -> std::string { |
2380 | 0 | if (!cmSystemTools::FileIsFullPath(srcFilename)) { |
2381 | 0 | srcFilename = |
2382 | 0 | cmSystemTools::CollapseFullPath(srcFilename, |
2383 | 0 | this->GetGlobalGenerator() |
2384 | 0 | ->GetCMakeInstance() |
2385 | 0 | ->GetHomeOutputDirectory()); |
2386 | 0 | } |
2387 | |
|
2388 | 0 | return this->LocalGenerator->ConvertToOutputFormat( |
2389 | 0 | srcFilename, cmOutputConverter::SHELL); |
2390 | 0 | }; |
2391 | 0 | auto escapedModuleObjectFilename = |
2392 | 0 | this->ConvertToNinjaPath(moduleObjectFilename); |
2393 | |
|
2394 | 0 | cmRulePlaceholderExpander::RuleVariables compileObjectVars; |
2395 | 0 | compileObjectVars.Language = "Swift"; |
2396 | 0 | compileObjectVars.Flags = flags.c_str(); |
2397 | 0 | compileObjectVars.Defines = defines.c_str(); |
2398 | 0 | compileObjectVars.Includes = includes.c_str(); |
2399 | | |
2400 | | // Build up the list of source files in the module |
2401 | 0 | std::vector<std::string> filenames; |
2402 | 0 | filenames.reserve(moduleSourceFiles.size()); |
2403 | 0 | for (cmSourceFile const* sf : moduleSourceFiles) { |
2404 | 0 | filenames.emplace_back( |
2405 | 0 | escapeSourceFileName(this->GetCompiledSourceNinjaPath(sf))); |
2406 | 0 | } |
2407 | | // Note that `escapedSourceFilenames` must remain alive until the |
2408 | | // compileObjectVars is consumed or Source will be a dangling pointer. |
2409 | 0 | std::string const escapedSourceFilenames = cmJoin(filenames, " "); |
2410 | 0 | compileObjectVars.Source = escapedSourceFilenames.c_str(); |
2411 | |
|
2412 | 0 | std::string const& compileCommand = |
2413 | 0 | this->Makefile->GetRequiredDefinition("CMAKE_Swift_COMPILE_OBJECT"); |
2414 | 0 | cmList compileCmds(compileCommand); |
2415 | |
|
2416 | 0 | auto rulePlaceholderExpander = |
2417 | 0 | this->GetLocalGenerator()->CreateRulePlaceholderExpander(); |
2418 | |
|
2419 | 0 | for (cmSourceFile const* sf : moduleSourceFiles) { |
2420 | 0 | std::string const sourceFilename = this->GetCompiledSourceNinjaPath(sf); |
2421 | 0 | std::string objectFilename = escapedModuleObjectFilename; |
2422 | |
|
2423 | 0 | if (!singleOutput) { |
2424 | | // If it's not single-output, each source file gets a separate object |
2425 | 0 | objectFilename = |
2426 | 0 | this->ConvertToNinjaPath(this->GetObjectFilePath(sf, outputConfig)); |
2427 | 0 | } |
2428 | 0 | compileObjectVars.Objects = objectFilename.c_str(); |
2429 | |
|
2430 | 0 | for (std::string& cmd : compileCmds) { |
2431 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), |
2432 | 0 | cmd, compileObjectVars); |
2433 | 0 | } |
2434 | |
|
2435 | 0 | std::string commandLine = this->GetLocalGenerator()->BuildCommandLine( |
2436 | 0 | compileCmds, outputConfig, outputConfig); |
2437 | |
|
2438 | 0 | this->GetGlobalGenerator()->AddCXXCompileCommand( |
2439 | 0 | commandLine, sourceFilename, objectFilename); |
2440 | 0 | } |
2441 | 0 | } |
2442 | | |
2443 | | void cmNinjaTargetGenerator::AdditionalCleanFiles(std::string const& config) |
2444 | 0 | { |
2445 | 0 | if (cmValue prop_value = |
2446 | 0 | this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) { |
2447 | 0 | cmLocalNinjaGenerator* lg = this->LocalGenerator; |
2448 | 0 | cmList cleanFiles(cmGeneratorExpression::Evaluate(*prop_value, lg, config, |
2449 | 0 | this->GeneratorTarget)); |
2450 | 0 | std::string const& binaryDir = lg->GetCurrentBinaryDirectory(); |
2451 | 0 | cmGlobalNinjaGenerator* gg = lg->GetGlobalNinjaGenerator(); |
2452 | 0 | for (auto const& cleanFile : cleanFiles) { |
2453 | | // Support relative paths |
2454 | 0 | gg->AddAdditionalCleanFile( |
2455 | 0 | cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config); |
2456 | 0 | } |
2457 | 0 | } |
2458 | 0 | } |
2459 | | |
2460 | | cmNinjaDeps cmNinjaTargetGenerator::GetObjects(std::string const& config) const |
2461 | 0 | { |
2462 | 0 | auto const it = this->Configs.find(config); |
2463 | 0 | if (it != this->Configs.end()) { |
2464 | 0 | return it->second.Objects; |
2465 | 0 | } |
2466 | 0 | return {}; |
2467 | 0 | } |
2468 | | |
2469 | | void cmNinjaTargetGenerator::EnsureDirectoryExists( |
2470 | | std::string const& path) const |
2471 | 0 | { |
2472 | 0 | if (cmSystemTools::FileIsFullPath(path)) { |
2473 | 0 | cmSystemTools::MakeDirectory(path); |
2474 | 0 | } else { |
2475 | 0 | cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator(); |
2476 | 0 | std::string fullPath = gg->GetCMakeInstance()->GetHomeOutputDirectory(); |
2477 | | // Also ensures there is a trailing slash. |
2478 | 0 | gg->StripNinjaOutputPathPrefixAsSuffix(fullPath); |
2479 | 0 | fullPath += path; |
2480 | 0 | cmSystemTools::MakeDirectory(fullPath); |
2481 | 0 | } |
2482 | 0 | } |
2483 | | |
2484 | | void cmNinjaTargetGenerator::EnsureParentDirectoryExists( |
2485 | | std::string const& path) const |
2486 | 0 | { |
2487 | 0 | this->EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path)); |
2488 | 0 | } |
2489 | | |
2490 | | void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( |
2491 | | cmSourceFile const& source, char const* pkgloc, std::string const& config) |
2492 | 0 | { |
2493 | | // Skip OS X content when not building a Framework or Bundle. |
2494 | 0 | if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) { |
2495 | 0 | return; |
2496 | 0 | } |
2497 | | |
2498 | 0 | std::string macdir = |
2499 | 0 | this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc, |
2500 | 0 | config); |
2501 | | |
2502 | | // Reject files that collide with files from the Ninja file's native config. |
2503 | 0 | if (config != this->FileConfig) { |
2504 | 0 | std::string nativeMacdir = |
2505 | 0 | this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory( |
2506 | 0 | pkgloc, this->FileConfig); |
2507 | 0 | if (macdir == nativeMacdir) { |
2508 | 0 | return; |
2509 | 0 | } |
2510 | 0 | } |
2511 | | |
2512 | | // Get the input file location. |
2513 | 0 | std::string input = source.GetFullPath(); |
2514 | 0 | input = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(input); |
2515 | | |
2516 | | // Get the output file location. |
2517 | 0 | std::string output = |
2518 | 0 | cmStrCat(macdir, '/', cmSystemTools::GetFilenameName(input)); |
2519 | 0 | output = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(output); |
2520 | | |
2521 | | // Write a build statement to copy the content into the bundle. |
2522 | 0 | this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild( |
2523 | 0 | input, output, this->FileConfig); |
2524 | | |
2525 | | // Add as a dependency to the target so that it gets called. |
2526 | 0 | this->Generator->Configs[config].ExtraFiles.push_back(std::move(output)); |
2527 | 0 | } |
2528 | | |
2529 | | void cmNinjaTargetGenerator::AddDepfileBinding(cmNinjaVars& vars, |
2530 | | std::string depfile) const |
2531 | 0 | { |
2532 | 0 | std::string depfileForShell = this->ConvertToOutputFormatForShell(depfile); |
2533 | 0 | if (depfile != depfileForShell) { |
2534 | 0 | vars["depfile"] = std::move(depfile); |
2535 | 0 | } |
2536 | 0 | vars["DEP_FILE"] = std::move(depfileForShell); |
2537 | 0 | } |
2538 | | |
2539 | | void cmNinjaTargetGenerator::RemoveDepfileBinding(cmNinjaVars& vars) const |
2540 | 0 | { |
2541 | 0 | vars.erase("DEP_FILE"); |
2542 | 0 | vars.erase("depfile"); |
2543 | 0 | } |
2544 | | |
2545 | | void cmNinjaTargetGenerator::addPoolNinjaVariable( |
2546 | | std::string const& pool_property, cmGeneratorTarget* target, |
2547 | | cmSourceFile const* source, cmNinjaVars& vars) |
2548 | 0 | { |
2549 | | // First check the current source properties, then if not found, its target |
2550 | | // ones. Allows to override a target-wide compile pool with a source-specific |
2551 | | // one. |
2552 | 0 | cmValue pool = {}; |
2553 | 0 | if (source) { |
2554 | 0 | pool = source->GetProperty(pool_property); |
2555 | 0 | } |
2556 | 0 | if (!pool) { |
2557 | 0 | pool = target->GetProperty(pool_property); |
2558 | 0 | } |
2559 | 0 | if (pool) { |
2560 | 0 | vars["pool"] = *pool; |
2561 | 0 | } |
2562 | 0 | } |
2563 | | |
2564 | | bool cmNinjaTargetGenerator::ForceResponseFile() |
2565 | 0 | { |
2566 | 0 | static std::string const forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE"; |
2567 | 0 | return (this->GetMakefile()->IsDefinitionSet(forceRspFile) || |
2568 | 0 | cmSystemTools::HasEnv(forceRspFile)); |
2569 | 0 | } |