Coverage Report

Created: 2026-10-28 06:38

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