Coverage Report

Created: 2026-07-30 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmCommonTargetGenerator.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 "cmCommonTargetGenerator.h"
4
5
#include <algorithm>
6
#include <sstream>
7
#include <utility>
8
9
#include <cm/filesystem>
10
#include <cm/string_view>
11
#include <cmext/string_view>
12
13
#include "cmComputeLinkInformation.h"
14
#include "cmGenExContext.h"
15
#include "cmGeneratorExpression.h"
16
#include "cmGeneratorExpressionDAGChecker.h"
17
#include "cmGeneratorTarget.h"
18
#include "cmGlobalCommonGenerator.h"
19
#include "cmGlobalGenerator.h"
20
#include "cmList.h"
21
#include "cmLocalCommonGenerator.h"
22
#include "cmLocalGenerator.h"
23
#include "cmMakefile.h"
24
#include "cmMessageType.h"
25
#include "cmOutputConverter.h"
26
#include "cmRange.h"
27
#include "cmSourceFile.h"
28
#include "cmState.h"
29
#include "cmStringAlgorithms.h"
30
#include "cmSystemTools.h"
31
#include "cmTargetTypes.h"
32
#include "cmValue.h"
33
34
cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
35
0
  : GeneratorTarget(gt)
36
0
  , Makefile(gt->Makefile)
37
  , LocalCommonGenerator(
38
0
      static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
39
0
  , GlobalCommonGenerator(static_cast<cmGlobalCommonGenerator*>(
40
0
      gt->LocalGenerator->GetGlobalGenerator()))
41
0
  , ConfigNames(this->LocalCommonGenerator->GetConfigNames())
42
0
{
43
0
}
44
45
0
cmCommonTargetGenerator::~cmCommonTargetGenerator() = default;
46
47
std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const
48
0
{
49
0
  return this->ConfigNames;
50
0
}
51
52
cmValue cmCommonTargetGenerator::GetFeature(std::string const& feature,
53
                                            std::string const& config)
54
0
{
55
0
  return this->GeneratorTarget->GetFeature(feature, config);
56
0
}
57
58
void cmCommonTargetGenerator::AppendFortranFormatFlags(
59
  std::string& flags, cmSourceFile const& source)
60
0
{
61
0
  std::string const srcfmt = source.GetSafeProperty("Fortran_FORMAT");
62
0
  cmOutputConverter::FortranFormat format =
63
0
    cmOutputConverter::GetFortranFormat(srcfmt);
64
0
  if (format == cmOutputConverter::FortranFormatNone) {
65
0
    std::string const& tgtfmt =
66
0
      this->GeneratorTarget->GetSafeProperty("Fortran_FORMAT");
67
0
    format = cmOutputConverter::GetFortranFormat(tgtfmt);
68
0
  }
69
0
  char const* var = nullptr;
70
0
  switch (format) {
71
0
    case cmOutputConverter::FortranFormatFixed:
72
0
      var = "CMAKE_Fortran_FORMAT_FIXED_FLAG";
73
0
      break;
74
0
    case cmOutputConverter::FortranFormatFree:
75
0
      var = "CMAKE_Fortran_FORMAT_FREE_FLAG";
76
0
      break;
77
0
    default:
78
0
      break;
79
0
  }
80
0
  if (var) {
81
0
    this->LocalCommonGenerator->AppendFlags(
82
0
      flags, this->Makefile->GetSafeDefinition(var));
83
0
  }
84
0
}
85
86
void cmCommonTargetGenerator::AppendFortranPreprocessFlags(
87
  std::string& flags, cmSourceFile const& source,
88
  PreprocessFlagsRequired requires_pp)
89
0
{
90
0
  std::string const srcpp = source.GetSafeProperty("Fortran_PREPROCESS");
91
0
  cmOutputConverter::FortranPreprocess preprocess =
92
0
    cmOutputConverter::GetFortranPreprocess(srcpp);
93
0
  if (preprocess == cmOutputConverter::FortranPreprocess::Unset) {
94
0
    std::string const& tgtpp =
95
0
      this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS");
96
0
    preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
97
0
  }
98
0
  char const* var = nullptr;
99
0
  switch (preprocess) {
100
0
    case cmOutputConverter::FortranPreprocess::Needed:
101
0
      if (requires_pp == PreprocessFlagsRequired::YES) {
102
0
        var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON";
103
0
      }
104
0
      break;
105
0
    case cmOutputConverter::FortranPreprocess::NotNeeded:
106
0
      var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF";
107
0
      break;
108
0
    default:
109
0
      break;
110
0
  }
111
0
  if (var) {
112
0
    this->LocalCommonGenerator->AppendCompileOptions(
113
0
      flags, this->Makefile->GetSafeDefinition(var));
114
0
  }
115
0
}
116
117
std::string cmCommonTargetGenerator::GetFlags(std::string const& l,
118
                                              std::string const& config,
119
                                              std::string const& arch)
120
0
{
121
0
  std::string const key = config + arch;
122
123
0
  auto i = this->Configs[key].FlagsByLanguage.find(l);
124
0
  if (i == this->Configs[key].FlagsByLanguage.end()) {
125
0
    std::string flags;
126
127
0
    this->LocalCommonGenerator->GetTargetCompileFlags(this->GeneratorTarget,
128
0
                                                      config, l, flags, arch);
129
130
0
    ByLanguageMap::value_type entry(l, flags);
131
0
    i = this->Configs[key].FlagsByLanguage.insert(entry).first;
132
0
  }
133
0
  return i->second;
134
0
}
135
136
std::string cmCommonTargetGenerator::GetDefines(std::string const& l,
137
                                                std::string const& config)
138
0
{
139
0
  auto i = this->Configs[config].DefinesByLanguage.find(l);
140
0
  if (i == this->Configs[config].DefinesByLanguage.end()) {
141
0
    std::set<std::string> defines;
142
0
    this->LocalCommonGenerator->GetTargetDefines(this->GeneratorTarget, config,
143
0
                                                 l, defines);
144
145
0
    std::string definesString;
146
0
    this->LocalCommonGenerator->JoinDefines(defines, definesString, l);
147
148
0
    ByLanguageMap::value_type entry(l, definesString);
149
0
    i = this->Configs[config].DefinesByLanguage.insert(entry).first;
150
0
  }
151
0
  return i->second;
152
0
}
153
154
std::string cmCommonTargetGenerator::GetIncludes(std::string const& l,
155
                                                 std::string const& config)
156
0
{
157
0
  auto i = this->Configs[config].IncludesByLanguage.find(l);
158
0
  if (i == this->Configs[config].IncludesByLanguage.end()) {
159
0
    std::string includes;
160
0
    this->AddIncludeFlags(includes, l, config);
161
0
    ByLanguageMap::value_type entry(l, includes);
162
0
    i = this->Configs[config].IncludesByLanguage.insert(entry).first;
163
0
  }
164
0
  return i->second;
165
0
}
166
167
cmCommonTargetGenerator::LinkedTargetDirs
168
cmCommonTargetGenerator::GetLinkedTargetDirectories(
169
  std::string const& lang, std::string const& config) const
170
0
{
171
0
  LinkedTargetDirs dirs;
172
0
  std::set<cmGeneratorTarget const*> forward_emitted;
173
0
  std::set<cmGeneratorTarget const*> direct_emitted;
174
0
  cmGlobalCommonGenerator* const gg = this->GlobalCommonGenerator;
175
176
0
  enum class Forwarding
177
0
  {
178
0
    Yes,
179
0
    No
180
0
  };
181
182
0
  if (cmComputeLinkInformation* cli =
183
0
        this->GeneratorTarget->GetLinkInformation(config)) {
184
185
0
    auto findSyntheticTarget =
186
0
      [this, &config,
187
0
       cli](cmGeneratorTarget const* linkee) -> cmGeneratorTarget const* {
188
0
      if (!linkee) {
189
0
        return nullptr;
190
0
      }
191
192
      // Check the map of direct synthetic dependencies for a substitute
193
0
      auto const& synthDeps = this->GeneratorTarget->GetSyntheticDeps(config);
194
0
      auto it = synthDeps.find(linkee);
195
0
      if (it != synthDeps.end() && !it->second.empty()) {
196
0
        return *it->second.begin();
197
0
      }
198
199
      // Check linked targets to find synthetic targets for transitive deps
200
0
      std::vector<cmGeneratorTarget const*> pending;
201
0
      std::set<cmGeneratorTarget const*> visited;
202
0
      for (auto const& dep : synthDeps) {
203
0
        for (auto const* synth : dep.second) {
204
0
          if (synth && visited.insert(synth).second) {
205
0
            pending.push_back(synth);
206
0
          }
207
0
        }
208
0
      }
209
210
      // Also seed the search from direct linked targets that have
211
      // CXX20 module sources, in case they hold synthetic deps for
212
      // transitive dependencies that we need to inherit. Skip targets
213
      // that already have synthetic substitutes in our own synthDeps
214
      // (their transitive deps will be explored via the substitute).
215
0
      for (auto const& item : cli->GetItems()) {
216
0
        if (item.Target && item.Target->HaveCxx20ModuleSources() &&
217
0
            synthDeps.find(item.Target) == synthDeps.end() &&
218
0
            visited.insert(item.Target).second) {
219
0
          pending.push_back(item.Target);
220
0
        }
221
0
      }
222
223
0
      while (!pending.empty()) {
224
0
        auto const* current = pending.back();
225
0
        pending.pop_back();
226
0
        auto const& transitiveSynthDeps = current->GetSyntheticDeps(config);
227
0
        auto itLinkeeSynth = transitiveSynthDeps.find(linkee);
228
0
        if (itLinkeeSynth != transitiveSynthDeps.end() &&
229
0
            !itLinkeeSynth->second.empty()) {
230
0
          return *itLinkeeSynth->second.begin();
231
0
        }
232
0
        for (auto const& entry : transitiveSynthDeps) {
233
0
          for (auto const* synth : entry.second) {
234
0
            if (synth && visited.insert(synth).second) {
235
0
              pending.push_back(synth);
236
0
            }
237
0
          }
238
0
        }
239
0
      }
240
241
0
      return nullptr;
242
0
    };
243
244
0
    auto addLinkedTarget = [this, &lang, &config, &dirs, &direct_emitted,
245
0
                            &forward_emitted, &findSyntheticTarget,
246
0
                            gg](cmGeneratorTarget const* linkee,
247
0
                                Forwarding forward) {
248
      // Check if the linkee has a synthetic target to use for importing
249
0
      cmGeneratorTarget const* mappedLinkee = linkee;
250
0
      if (auto const* synth = findSyntheticTarget(linkee)) {
251
0
        mappedLinkee = synth;
252
0
      }
253
254
0
      if (mappedLinkee &&
255
0
          !mappedLinkee->IsImported()
256
          // Skip targets that build after this one in a static lib cycle.
257
0
          && gg->TargetOrderIndexLess(mappedLinkee, this->GeneratorTarget)
258
          // We can ignore the INTERFACE_LIBRARY items because
259
          // Target->GetLinkInformation already processed their
260
          // link interface and they don't have any output themselves.
261
0
          && (mappedLinkee->GetType() != cm::TargetType::INTERFACE_LIBRARY
262
              // Synthesized targets may have relevant rules.
263
0
              || mappedLinkee->IsSynthetic()) &&
264
0
          ((lang == "CXX"_s && mappedLinkee->HaveCxx20ModuleSources()) ||
265
0
           (lang == "Fortran"_s &&
266
0
            mappedLinkee->HaveFortranSources(config)))) {
267
0
        cmLocalGenerator* lg = mappedLinkee->GetLocalGenerator();
268
0
        std::string di = mappedLinkee->GetSupportDirectory();
269
0
        if (lg->GetGlobalGenerator()->IsMultiConfig()) {
270
0
          di = cmStrCat(di, '/', config);
271
0
        }
272
0
        if (forward == Forwarding::Yes &&
273
0
            forward_emitted.insert(mappedLinkee).second) {
274
0
          dirs.Forward.push_back(di);
275
0
        }
276
0
        if (direct_emitted.insert(mappedLinkee).second) {
277
0
          dirs.Direct.emplace_back(di);
278
0
        }
279
0
      }
280
0
    };
281
0
    for (auto const& item : cli->GetItems()) {
282
0
      if (item.Target) {
283
0
        addLinkedTarget(item.Target, Forwarding::No);
284
0
      } else if (item.ObjectSource && lang == "Fortran"_s
285
                 /* Object source files do not have a language associated with
286
                    them. */
287
0
                 /* && item.ObjectSource->GetLanguage() == "Fortran"_s*/) {
288
        // Fortran modules provided by `$<TARGET_OBJECTS>` as linked items
289
        // should be collated for use in this target.
290
0
        addLinkedTarget(this->LocalCommonGenerator->FindGeneratorTargetToUse(
291
0
                          item.ObjectSource->GetObjectLibrary()),
292
0
                        Forwarding::Yes);
293
0
      }
294
0
    }
295
0
    for (cmGeneratorTarget const* target : cli->GetExternalObjectTargets()) {
296
0
      addLinkedTarget(target, Forwarding::No);
297
0
    }
298
0
    if (lang == "Fortran"_s) {
299
      // Fortran modules provided by `$<TARGET_OBJECTS>` as sources should be
300
      // collated for use in this target.
301
0
      for (cmGeneratorTarget const* target :
302
0
           this->GeneratorTarget->GetSourceObjectLibraries(config)) {
303
0
        addLinkedTarget(target, Forwarding::Yes);
304
0
      }
305
0
    }
306
0
  }
307
0
  return dirs;
308
0
}
309
310
std::string cmCommonTargetGenerator::ComputeTargetCompilePDB(
311
  std::string const& config) const
312
0
{
313
0
  std::string compilePdbPath;
314
0
  if (this->GeneratorTarget->GetType() > cm::TargetType::OBJECT_LIBRARY) {
315
0
    return compilePdbPath;
316
0
  }
317
318
0
  compilePdbPath = this->GeneratorTarget->GetCompilePDBPath(config);
319
0
  if (compilePdbPath.empty()) {
320
    // Match VS default: `$(IntDir)vc$(PlatformToolsetVersion).pdb`.
321
    // A trailing slash tells the toolchain to add its default file name.
322
0
    compilePdbPath = this->GeneratorTarget->GetSupportDirectory();
323
0
    if (this->GlobalCommonGenerator->IsMultiConfig()) {
324
0
      compilePdbPath += "/";
325
0
      compilePdbPath += config;
326
0
    }
327
0
    compilePdbPath += "/";
328
0
    if (this->GeneratorTarget->GetType() == cm::TargetType::STATIC_LIBRARY) {
329
      // Match VS default for static libs: `$(IntDir)$(ProjectName).pdb`.
330
0
      compilePdbPath += this->GeneratorTarget->GetName();
331
0
      compilePdbPath += ".pdb";
332
0
    }
333
0
  }
334
335
0
  return compilePdbPath;
336
0
}
337
338
std::string cmCommonTargetGenerator::GetManifests(std::string const& config)
339
0
{
340
0
  std::vector<cmSourceFile const*> manifest_srcs;
341
0
  this->GeneratorTarget->GetManifests(manifest_srcs, config);
342
343
0
  std::vector<std::string> manifests;
344
0
  manifests.reserve(manifest_srcs.size());
345
346
0
  std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
347
0
  std::string manifestFlag = this->Makefile->GetDefinition(
348
0
    cmStrCat("CMAKE_", lang, "_LINKER_MANIFEST_FLAG"));
349
0
  for (cmSourceFile const* manifest_src : manifest_srcs) {
350
0
    manifests.push_back(manifestFlag +
351
0
                        this->LocalCommonGenerator->ConvertToOutputFormat(
352
0
                          this->LocalCommonGenerator->MaybeRelativeToWorkDir(
353
0
                            manifest_src->GetFullPath()),
354
0
                          cmOutputConverter::SHELL));
355
0
  }
356
357
0
  return cmJoin(manifests, " ");
358
0
}
359
360
std::string cmCommonTargetGenerator::GetAIXExports(std::string const&)
361
0
{
362
0
  std::string aixExports;
363
0
  if (this->GeneratorTarget->IsAIX()) {
364
0
    if (cmValue exportAll =
365
0
          this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) {
366
0
      if (exportAll.IsOff()) {
367
0
        aixExports = "-n";
368
0
      }
369
0
    }
370
0
  }
371
0
  return aixExports;
372
0
}
373
374
void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
375
                                               std::string const& lang,
376
                                               char const* name, bool so)
377
0
{
378
  // Lookup the flag to specify the version.
379
0
  std::string fvar = cmStrCat("CMAKE_", lang, "_OSX_", name, "_VERSION_FLAG");
380
0
  cmValue flag = this->Makefile->GetDefinition(fvar);
381
382
  // Skip if no such flag.
383
0
  if (!flag) {
384
0
    return;
385
0
  }
386
387
  // Lookup the target version information.
388
0
  int major;
389
0
  int minor;
390
0
  int patch;
391
0
  std::string prop = cmStrCat("MACHO_", name, "_VERSION");
392
0
  std::string fallback_prop = so ? "SOVERSION" : "VERSION";
393
0
  this->GeneratorTarget->GetTargetVersionFallback(prop, fallback_prop, major,
394
0
                                                  minor, patch);
395
0
  if (major > 0 || minor > 0 || patch > 0) {
396
    // Append the flag since a non-zero version is specified.
397
0
    std::ostringstream vflag;
398
0
    vflag << *flag << major << "." << minor << "." << patch;
399
0
    this->LocalCommonGenerator->AppendFlags(flags, vflag.str());
400
0
  }
401
0
}
402
403
std::string cmCommonTargetGenerator::GetCompilerLauncher(
404
  std::string const& lang, std::string const& config)
405
0
{
406
0
  std::string compilerLauncher;
407
0
  if (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" ||
408
0
      lang == "HIP" || lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX") {
409
0
    std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
410
0
    cmValue clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
411
0
    std::string const evaluatedClauncher = cmGeneratorExpression::Evaluate(
412
0
      *clauncher, this->GeneratorTarget->GetLocalGenerator(), config,
413
0
      this->GeneratorTarget, nullptr, this->GeneratorTarget, lang);
414
0
    if (!evaluatedClauncher.empty()) {
415
0
      compilerLauncher = evaluatedClauncher;
416
0
    }
417
0
  }
418
0
  return compilerLauncher;
419
0
}
420
421
std::string cmCommonTargetGenerator::GenerateCodeCheckRules(
422
  cmSourceFile const& source, std::string& compilerLauncher,
423
  std::string const& cmakeCmd, std::string const& config,
424
  std::function<std::string(std::string const&)> const& pathConverter)
425
0
{
426
0
  auto const lang = source.GetLanguage();
427
0
  std::string tidy;
428
0
  std::string iwyu;
429
0
  std::string cpplint;
430
0
  std::string cppcheck;
431
0
  std::string icstat;
432
0
  std::string pvs;
433
434
0
  auto evaluateProp = [&](std::string const& prop) -> std::string {
435
0
    auto const value = this->GeneratorTarget->GetProperty(prop);
436
0
    if (!value) {
437
0
      return std::string{};
438
0
    }
439
0
    auto evaluatedProp = cmGeneratorExpression::Evaluate(
440
0
      *value, this->GeneratorTarget->GetLocalGenerator(), config,
441
0
      this->GeneratorTarget, nullptr, this->GeneratorTarget, lang);
442
0
    return evaluatedProp;
443
0
  };
444
0
  std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY");
445
0
  tidy = evaluateProp(tidy_prop);
446
447
0
  if (lang == "C" || lang == "CXX") {
448
0
    std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE");
449
0
    iwyu = evaluateProp(iwyu_prop);
450
451
0
    std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT");
452
0
    cpplint = evaluateProp(cpplint_prop);
453
454
0
    std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
455
0
    cppcheck = evaluateProp(cppcheck_prop);
456
457
0
    std::string const icstat_prop = cmStrCat(lang, "_ICSTAT");
458
0
    icstat = evaluateProp(icstat_prop);
459
460
0
    std::string const pvs_prop = cmStrCat(lang, "_PVS_STUDIO");
461
0
    pvs = evaluateProp(pvs_prop);
462
0
  }
463
464
0
  if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
465
0
      cmNonempty(cppcheck) || cmNonempty(icstat) || cmNonempty(pvs)) {
466
0
    std::string code_check = cmakeCmd + " -E __run_co_compile";
467
0
    if (!compilerLauncher.empty()) {
468
      // In __run_co_compile case the launcher command is supplied
469
      // via --launcher=<maybe-list> and consumed
470
0
      code_check =
471
0
        cmStrCat(std::move(code_check), " --launcher=",
472
0
                 this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
473
0
                   compilerLauncher));
474
0
      compilerLauncher.clear();
475
0
    }
476
0
    if (cmNonempty(iwyu)) {
477
0
      code_check += " --iwyu=";
478
479
      // Only add --driver-mode if it is not already specified, as adding
480
      // it unconditionally might override a user-specified driver-mode
481
0
      if (iwyu.find("--driver-mode=") == std::string::npos) {
482
0
        cmValue const p = this->Makefile->GetDefinition(
483
0
          cmStrCat("CMAKE_", lang, "_INCLUDE_WHAT_YOU_USE_DRIVER_MODE"));
484
0
        std::string driverMode;
485
486
0
        if (cmNonempty(p)) {
487
0
          driverMode = *p;
488
0
        } else {
489
0
          driverMode = lang == "C" ? "gcc" : "g++";
490
0
        }
491
492
0
        code_check +=
493
0
          this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
494
0
            cmStrCat(iwyu, ";--driver-mode=", driverMode));
495
0
      } else {
496
0
        code_check +=
497
0
          this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(iwyu);
498
0
      }
499
0
    }
500
0
    if (cmNonempty(tidy)) {
501
0
      code_check += " --tidy=";
502
0
      cmValue const p = this->Makefile->GetDefinition(
503
0
        cmStrCat("CMAKE_", lang, "_CLANG_TIDY_DRIVER_MODE"));
504
0
      std::string driverMode;
505
0
      if (cmNonempty(p)) {
506
0
        driverMode = *p;
507
0
      } else {
508
0
        driverMode = lang == "C" ? "gcc" : "g++";
509
0
      }
510
511
0
      auto const generatorName = this->GeneratorTarget->GetLocalGenerator()
512
0
                                   ->GetGlobalGenerator()
513
0
                                   ->GetName();
514
0
      auto const clangTidyExportFixedDir =
515
0
        this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang);
516
0
      auto fixesFile = this->GetClangTidyReplacementsFilePath(
517
0
        clangTidyExportFixedDir, source, config);
518
0
      std::string exportFixes;
519
0
      if (!clangTidyExportFixedDir.empty()) {
520
0
        this->GlobalCommonGenerator->AddClangTidyExportFixesDir(
521
0
          clangTidyExportFixedDir);
522
0
      }
523
0
      if (generatorName.find("Make") != std::string::npos) {
524
0
        if (!clangTidyExportFixedDir.empty()) {
525
0
          this->GlobalCommonGenerator->AddClangTidyExportFixesFile(fixesFile);
526
0
          cmSystemTools::MakeDirectory(
527
0
            cmSystemTools::GetFilenamePath(fixesFile));
528
0
          fixesFile = this->GeneratorTarget->GetLocalGenerator()
529
0
                        ->MaybeRelativeToCurBinDir(fixesFile);
530
0
          exportFixes = cmStrCat(";--export-fixes=", fixesFile);
531
0
        }
532
0
        code_check +=
533
0
          this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
534
0
            cmStrCat(tidy, ";--extra-arg-before=--driver-mode=", driverMode,
535
0
                     exportFixes));
536
0
      } else if (generatorName.find("Ninja") != std::string::npos ||
537
0
                 generatorName.find("FASTBuild") != std::string::npos) {
538
0
        if (!clangTidyExportFixedDir.empty()) {
539
0
          this->GlobalCommonGenerator->AddClangTidyExportFixesFile(fixesFile);
540
0
          cmSystemTools::MakeDirectory(
541
0
            cmSystemTools::GetFilenamePath(fixesFile));
542
0
          if (pathConverter) {
543
0
            fixesFile = pathConverter(fixesFile);
544
0
          }
545
0
          exportFixes = cmStrCat(";--export-fixes=", fixesFile);
546
0
        }
547
0
        code_check +=
548
0
          this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
549
0
            cmStrCat(tidy, ";--extra-arg-before=--driver-mode=", driverMode,
550
0
                     exportFixes));
551
0
      }
552
0
    }
553
0
    if (cmNonempty(pvs)) {
554
0
      cmMakefile* mf =
555
0
        this->GeneratorTarget->GetLocalGenerator()->GetMakefile();
556
0
      std::string extraPvsArgs;
557
0
      if (lang == "CXX") {
558
0
        extraPvsArgs +=
559
0
          cmStrCat(";--cxx;", mf->GetDefinition("CMAKE_CXX_COMPILER"));
560
0
      } else if (lang == "C") {
561
0
        extraPvsArgs +=
562
0
          cmStrCat(";--cc;", mf->GetDefinition("CMAKE_C_COMPILER"));
563
0
      }
564
      // cocompile args
565
0
      code_check += " --pvs-studio=";
566
0
      code_check += this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
567
0
        cmStrCat(pvs, extraPvsArgs));
568
0
      code_check += " --object=";
569
0
      code_check +=
570
0
        this->GeneratorTarget->GetLocalGenerator()->ConvertToOutputFormat(
571
0
          cmSystemTools::CollapseFullPath(
572
0
            cmStrCat(this->GeneratorTarget->GetObjectDirectory(config), '/',
573
0
                     this->GeneratorTarget->GetObjectName(&source))),
574
0
          cmOutputConverter::SHELL);
575
0
    }
576
0
    if (cmNonempty(cpplint)) {
577
0
      code_check += " --cpplint=";
578
0
      code_check +=
579
0
        this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(cpplint);
580
0
    }
581
0
    if (cmNonempty(cppcheck)) {
582
0
      code_check += " --cppcheck=";
583
0
      code_check +=
584
0
        this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(cppcheck);
585
0
    }
586
0
    if (cmNonempty(icstat)) {
587
0
      code_check += " --icstat=";
588
0
      std::string checksParam{};
589
0
      std::string dbParam{};
590
      // Set default values for mandatory parameters
591
0
      std::string checksFile{ "cstat_sel_checks.txt" };
592
0
      std::string dbFile{ "cstat.db" };
593
      // Populate the command line with C-STAT
594
      // mandatory parameters unless specified
595
0
      if (icstat.find("--checks=") == std::string::npos) {
596
0
        checksParam = cmStrCat(";--checks=", checksFile);
597
0
      }
598
0
      if (icstat.find("--db=") == std::string::npos) {
599
0
        dbParam = cmStrCat(";--db=", dbFile);
600
0
      }
601
0
      code_check += this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
602
0
        cmStrCat(icstat, checksParam, dbParam));
603
0
    }
604
0
    if (cmNonempty(tidy) || (cmNonempty(cpplint)) || (cmNonempty(cppcheck)) ||
605
0
        cmNonempty(pvs)) {
606
0
      code_check += " --source=";
607
0
      code_check +=
608
0
        this->GeneratorTarget->GetLocalGenerator()->ConvertToOutputFormat(
609
0
          source.GetFullPath(), cmOutputConverter::SHELL);
610
0
    }
611
0
    code_check += " -- ";
612
0
    return code_check;
613
0
  }
614
0
  return "";
615
0
}
616
617
std::string cmCommonTargetGenerator::GetLinkerLauncher(
618
  std::string const& config)
619
0
{
620
0
  std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
621
0
  std::string propName = lang + "_LINKER_LAUNCHER";
622
0
  cmValue launcherProp = this->GeneratorTarget->GetProperty(propName);
623
0
  if (cmNonempty(launcherProp)) {
624
0
    cm::GenEx::Context context(this->LocalCommonGenerator, config, lang);
625
0
    cmGeneratorExpressionDAGChecker dagChecker{ this->GeneratorTarget,
626
0
                                                propName, nullptr, nullptr,
627
0
                                                context };
628
0
    std::string evaluatedLinklauncher = cmGeneratorExpression::Evaluate(
629
0
      *launcherProp, context.LG, context.Config, this->GeneratorTarget,
630
0
      &dagChecker, this->GeneratorTarget, context.Language);
631
    // Convert ;-delimited list to single string
632
0
    cmList args{ evaluatedLinklauncher, cmList::EmptyElements::Yes };
633
0
    if (!args.empty()) {
634
0
      args[0] = this->LocalCommonGenerator->ConvertToOutputFormat(
635
0
        args[0], cmOutputConverter::SHELL);
636
0
      for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
637
0
        i = this->LocalCommonGenerator->EscapeForShell(i);
638
0
      }
639
0
      return cmJoin(args, " ");
640
0
    }
641
0
  }
642
0
  return std::string();
643
0
}
644
645
bool cmCommonTargetGenerator::HaveRequiredLanguages(
646
  std::vector<cmSourceFile const*> const& sources,
647
  std::set<std::string>& languagesNeeded) const
648
0
{
649
0
  for (cmSourceFile const* sf : sources) {
650
0
    languagesNeeded.insert(sf->GetLanguage());
651
0
  }
652
653
0
  auto* makefile = this->Makefile;
654
0
  auto* state = makefile->GetState();
655
0
  auto unary = [&state, &makefile](std::string const& lang) -> bool {
656
0
    bool const valid = state->GetLanguageEnabled(lang);
657
0
    if (!valid) {
658
0
      makefile->IssueMessage(
659
0
        MessageType::FATAL_ERROR,
660
0
        cmStrCat("The language ", lang,
661
0
                 " was requested for compilation but was not enabled."
662
0
                 " To enable a language it needs to be specified in a"
663
0
                 " 'project' or 'enable_language' command in the root"
664
0
                 " CMakeLists.txt"));
665
0
    }
666
0
    return valid;
667
0
  };
668
0
  return std::all_of(languagesNeeded.cbegin(), languagesNeeded.cend(), unary);
669
0
}
670
671
void cmCommonTargetGenerator::ComputeRustFlagsForObjects(
672
  std::string& linkCrates, std::string& nativeObjects,
673
  std::vector<std::string> const& objects)
674
0
{
675
0
  std::stringstream rlibsArgs;
676
0
  std::stringstream objectsArgs;
677
0
  auto const processObject = [&](std::string const& obj) {
678
0
    cm::filesystem::path const objPath(obj);
679
0
    if (objPath.extension() == ".rlib") {
680
      // Drop the "lib..." prefix and the ".rs" suffix. The prefix is required
681
      // by Rust on the crate rlib file, but is hidden from the user when using
682
      // the crate from Rust source code, so we drop it to be consistent with
683
      // common usage in Rust.
684
0
      std::string objStem = objPath.stem().string();
685
0
      objStem = objStem.substr(3, objStem.length() - 6);
686
0
      rlibsArgs << " --extern=" << objStem << "="
687
0
                << this->LocalCommonGenerator->ConvertToOutputFormat(
688
0
                     obj, cmOutputConverter::SHELL);
689
0
    } else {
690
0
      objectsArgs << " -Clink-arg="
691
0
                  << this->LocalCommonGenerator->ConvertToOutputFormat(
692
0
                       obj, cmOutputConverter::SHELL);
693
0
    }
694
0
  };
695
0
  for (auto const& obj : objects) {
696
0
    processObject(obj);
697
0
  }
698
0
  linkCrates += rlibsArgs.str();
699
0
  nativeObjects += objectsArgs.str();
700
0
}