cmLocalGenerator.cxx 158 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
Ken Martin's avatar
Ken Martin committed
3
#include "cmLocalGenerator.h"
4

5
#include <algorithm>
6
#include <array>
7
8
9
10
11
12
13
14
15
16
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <initializer_list>
#include <iterator>
#include <sstream>
#include <unordered_set>
#include <utility>
#include <vector>

17
#include <cm/memory>
18
#include <cm/string_view>
19
#include <cmext/algorithm>
20
#include <cmext/string_view>
21

22
23
#include "cmsys/RegularExpression.hxx"

24
#include "cmAlgorithms.h"
25
#include "cmComputeLinkInformation.h"
26
#include "cmCustomCommand.h"
27
#include "cmCustomCommandGenerator.h"
28
#include "cmCustomCommandLines.h"
29
#include "cmCustomCommandTypes.h"
30
#include "cmGeneratedFileStream.h"
31
#include "cmGeneratorExpression.h"
32
#include "cmGeneratorExpressionEvaluationFile.h"
33
#include "cmGeneratorTarget.h"
Ken Martin's avatar
updates    
Ken Martin committed
34
#include "cmGlobalGenerator.h"
35
#include "cmInstallGenerator.h"
36
37
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
38
#include "cmLinkLineComputer.h"
Ken Martin's avatar
Ken Martin committed
39
#include "cmMakefile.h"
40
#include "cmProperty.h"
41
#include "cmRulePlaceholderExpander.h"
42
#include "cmSourceFile.h"
43
#include "cmSourceFileLocation.h"
44
#include "cmSourceFileLocationKind.h"
45
#include "cmStandardLevelResolver.h"
46
47
#include "cmState.h"
#include "cmStateDirectory.h"
48
#include "cmStateTypes.h"
49
#include "cmStringAlgorithms.h"
50
51
#include "cmSystemTools.h"
#include "cmTarget.h"
52
#include "cmTestGenerator.h"
53
#include "cmVersion.h"
54
55
#include "cmake.h"

56
#if !defined(CMAKE_BOOTSTRAP)
57
58
#  define CM_LG_ENCODE_OBJECT_NAMES
#  include "cmCryptoHash.h"
59
60
#endif

61
#if defined(__HAIKU__)
62
63
#  include <FindDirectory.h>
#  include <StorageDefs.h>
64
65
#endif

66
67
68
69
70
// List of variables that are replaced when
// rules are expanced.  These variables are
// replaced in the form <var> with GetSafeDefinition(var).
// ${LANG} is replaced in the variable first with all enabled
// languages.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
                                "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
                                "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
                                "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
                                "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
                                "CMAKE_${LANG}_LINK_FLAGS",
                                "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
                                "CMAKE_${LANG}_ARCHIVE",
                                "CMAKE_AR",
                                "CMAKE_CURRENT_SOURCE_DIR",
                                "CMAKE_CURRENT_BINARY_DIR",
                                "CMAKE_RANLIB",
                                "CMAKE_LINKER",
                                "CMAKE_MT",
                                "CMAKE_CUDA_HOST_COMPILER",
                                "CMAKE_CUDA_HOST_LINK_LAUNCHER",
                                "CMAKE_CL_SHOWINCLUDES_PREFIX" };
88

89
90
91
cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
  : cmOutputConverter(makefile->GetStateSnapshot())
  , StateSnapshot(makefile->GetStateSnapshot())
92
  , DirectoryBacktrace(makefile->GetBacktrace())
Ken Martin's avatar
Ken Martin committed
93
{
94
  this->GlobalGenerator = gg;
95

96
  this->Makefile = makefile;
97

98
99
  this->AliasTargets = makefile->GetAliasTargets();

100
  this->EmitUniversalBinaryFlags = true;
101
102
  this->BackwardsCompatibility = 0;
  this->BackwardsCompatibilityFinal = false;
103
104

  this->ComputeObjectMaxPath();
105

106
107
108
109
110
111
112
113
114
115
116
117
118
  // Canonicalize entries of the CPATH environment variable the same
  // way detection of CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES does.
  {
    std::vector<std::string> cpath;
    cmSystemTools::GetPath(cpath, "CPATH");
    for (std::string& cp : cpath) {
      if (cmSystemTools::FileIsFullPath(cp)) {
        cp = cmSystemTools::CollapseFullPath(cp);
        this->EnvCPATH.emplace(std::move(cp));
      }
    }
  }

119
120
121
  std::vector<std::string> enabledLanguages =
    this->GetState()->GetEnabledLanguages();

122
  if (cmProp sysrootCompile =
123
        this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
124
    this->CompilerSysroot = *sysrootCompile;
125
126
127
128
  } else {
    this->CompilerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
  }

129
  if (cmProp sysrootLink =
130
        this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
131
    this->LinkerSysroot = *sysrootLink;
132
133
134
  } else {
    this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
  }
135

136
  if (cmProp appleArchSysroots =
137
        this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    std::string const& appleArchs =
      this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
    std::vector<std::string> archs;
    std::vector<std::string> sysroots;
    cmExpandList(appleArchs, archs);
    cmExpandList(*appleArchSysroots, sysroots, true);
    if (archs.size() == sysroots.size()) {
      for (size_t i = 0; i < archs.size(); ++i) {
        this->AppleArchSysroots[archs[i]] = sysroots[i];
      }
    } else {
      std::string const e =
        cmStrCat("CMAKE_APPLE_ARCH_SYSROOTS:\n  ", *appleArchSysroots,
                 "\n"
                 "is not the same length as CMAKE_OSX_ARCHITECTURES:\n  ",
                 appleArchs);
      this->IssueMessage(MessageType::FATAL_ERROR, e);
    }
  }

158
  for (std::string const& lang : enabledLanguages) {
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    if (lang == "NONE") {
      continue;
    }
    this->Compilers["CMAKE_" + lang + "_COMPILER"] = lang;

    this->VariableMappings["CMAKE_" + lang + "_COMPILER"] =
      this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER");

    std::string const& compilerArg1 = "CMAKE_" + lang + "_COMPILER_ARG1";
    std::string const& compilerTarget = "CMAKE_" + lang + "_COMPILER_TARGET";
    std::string const& compilerOptionTarget =
      "CMAKE_" + lang + "_COMPILE_OPTIONS_TARGET";
    std::string const& compilerExternalToolchain =
      "CMAKE_" + lang + "_COMPILER_EXTERNAL_TOOLCHAIN";
    std::string const& compilerOptionExternalToolchain =
      "CMAKE_" + lang + "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN";
    std::string const& compilerOptionSysroot =
      "CMAKE_" + lang + "_COMPILE_OPTIONS_SYSROOT";

    this->VariableMappings[compilerArg1] =
      this->Makefile->GetSafeDefinition(compilerArg1);
    this->VariableMappings[compilerTarget] =
      this->Makefile->GetSafeDefinition(compilerTarget);
    this->VariableMappings[compilerOptionTarget] =
      this->Makefile->GetSafeDefinition(compilerOptionTarget);
    this->VariableMappings[compilerExternalToolchain] =
      this->Makefile->GetSafeDefinition(compilerExternalToolchain);
    this->VariableMappings[compilerOptionExternalToolchain] =
      this->Makefile->GetSafeDefinition(compilerOptionExternalToolchain);
    this->VariableMappings[compilerOptionSysroot] =
      this->Makefile->GetSafeDefinition(compilerOptionSysroot);

191
192
193
    for (std::string replaceVar : ruleReplaceVars) {
      if (replaceVar.find("${LANG}") != std::string::npos) {
        cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
194
195
      }

196
197
      this->VariableMappings[replaceVar] =
        this->Makefile->GetSafeDefinition(replaceVar);
198
199
    }
  }
Ken Martin's avatar
Ken Martin committed
200
201
}

202
203
204
205
cmRulePlaceholderExpander* cmLocalGenerator::CreateRulePlaceholderExpander()
  const
{
  return new cmRulePlaceholderExpander(this->Compilers, this->VariableMappings,
206
207
                                       this->CompilerSysroot,
                                       this->LinkerSysroot);
208
209
}

210
cmLocalGenerator::~cmLocalGenerator() = default;
Ken Martin's avatar
Ken Martin committed
211

212
void cmLocalGenerator::IssueMessage(MessageType t,
213
214
                                    std::string const& text) const
{
215
  this->GetCMakeInstance()->IssueMessage(t, text, this->DirectoryBacktrace);
216
217
}

218
219
void cmLocalGenerator::ComputeObjectMaxPath()
{
220
// Choose a maximum object file name length.
221
222
223
224
225
#if defined(_WIN32) || defined(__CYGWIN__)
  this->ObjectPathMax = 250;
#else
  this->ObjectPathMax = 1000;
#endif
226
  cmProp plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
Vitaly Stakhovsky's avatar
Vitaly Stakhovsky committed
227
  if (cmNonempty(plen)) {
228
    unsigned int pmax;
229
    if (sscanf(plen->c_str(), "%u", &pmax) == 1) {
230
      if (pmax >= 128) {
231
        this->ObjectPathMax = pmax;
232
      } else {
233
        std::ostringstream w;
234
235
236
        w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax
          << ", which is less than the minimum of 128.  "
          << "The value will be ignored.";
237
        this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
238
      }
239
    } else {
240
      std::ostringstream w;
241
      w << "CMAKE_OBJECT_PATH_MAX is set to \"" << *plen
242
243
        << "\", which fails to parse as a positive integer.  "
        << "The value will be ignored.";
244
      this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
245
    }
246
  }
247
  this->ObjectMaxPathViolations.clear();
248
249
}

250
251
252
253
static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs,
                                    const std::string& config,
                                    const std::string& lang,
                                    const cmGeneratorTarget* target)
254
255
256
257
258
259
260
261
262
263
264
265
266
{
  if (!target) {
    return;
  }

  std::stable_sort(
    includeDirs.begin(), includeDirs.end(),
    [&target, &config, &lang](std::string const& a, std::string const& b) {
      return !target->IsSystemIncludeDirectory(a, config, lang) &&
        target->IsSystemIncludeDirectory(b, config, lang);
    });
}

267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs,
                                    const std::string& config,
                                    const std::string& lang,
                                    const cmGeneratorTarget* target)
{
  if (!target) {
    return;
  }

  std::stable_sort(includeDirs.begin(), includeDirs.end(),
                   [target, &config, &lang](BT<std::string> const& a,
                                            BT<std::string> const& b) {
                     return !target->IsSystemIncludeDirectory(a.Value, config,
                                                              lang) &&
                       target->IsSystemIncludeDirectory(b.Value, config, lang);
                   });
}

285
void cmLocalGenerator::TraceDependencies() const
Alexander Neundorf's avatar
   
Alexander Neundorf committed
286
287
{
  // Generate the rule files for each target.
288
289
  const auto& targets = this->GetGeneratorTargets();
  for (const auto& target : targets) {
290
    if (!target->IsInBuildSystem()) {
291
      continue;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
292
    }
293
    target->TraceDependencies();
294
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
295
296
}

297
298
void cmLocalGenerator::GenerateTestFiles()
{
299
  if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
300
    return;
301
  }
302
303

  // Compute the set of configurations.
304
305
306
  std::vector<std::string> configurationTypes =
    this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
  std::string config = this->Makefile->GetDefaultConfiguration();
307

308
309
310
  std::string file =
    cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentBinary(),
             "/CTestTestfile.cmake");
311

312
  cmGeneratedFileStream fout(file);
313
314
  fout.SetCopyIfDifferent(true);

315
316
317
318
319
320
321
322
323
324
325
326
  fout << "# CMake generated Testfile for \n"
          "# Source directory: "
       << this->StateSnapshot.GetDirectory().GetCurrentSource()
       << "\n"
          "# Build directory: "
       << this->StateSnapshot.GetDirectory().GetCurrentBinary()
       << "\n"
          "# \n"
          "# This file includes the relevant testing commands "
          "required for \n"
          "# testing this directory and lists subdirectories to "
          "be tested as well.\n";
327

328
329
330
331
332
333
  std::string resourceSpecFile =
    this->Makefile->GetSafeDefinition("CTEST_RESOURCE_SPEC_FILE");
  if (!resourceSpecFile.empty()) {
    fout << "set(CTEST_RESOURCE_SPEC_FILE \"" << resourceSpecFile << "\")\n";
  }

334
  cmProp testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE");
335
  if (testIncludeFile) {
336
    fout << "include(\"" << *testIncludeFile << "\")\n";
337
  }
338

339
  cmProp testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES");
Matthew Woehlke's avatar
Matthew Woehlke committed
340
  if (testIncludeFiles) {
341
    std::vector<std::string> includesList = cmExpandedList(*testIncludeFiles);
342
    for (std::string const& i : includesList) {
343
      fout << "include(\"" << i << "\")\n";
Matthew Woehlke's avatar
Matthew Woehlke committed
344
345
346
    }
  }

347
  // Ask each test generator to write its code.
348
  for (const auto& tester : this->Makefile->GetTestGenerators()) {
349
350
    tester->Compute(this);
    tester->Generate(fout, config, configurationTypes);
351
  }
352
  using vec_t = std::vector<cmStateSnapshot>;
353
  vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
354
  std::string parentBinDir = this->GetCurrentBinaryDirectory();
355
  for (cmStateSnapshot const& i : children) {
356
    // TODO: Use add_subdirectory instead?
357
    std::string outP = i.GetDirectory().GetCurrentBinary();
358
    outP = this->MaybeConvertToRelativePath(parentBinDir, outP);
359
    outP = cmOutputConverter::EscapeForCMake(outP);
360
    fout << "subdirs(" << outP << ")\n";
361
  }
362
363

  // Add directory labels property
364
  cmProp directoryLabels =
365
    this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS");
366
  cmProp labels = this->Makefile->GetProperty("LABELS");
367
368
369
370

  if (labels || directoryLabels) {
    fout << "set_directory_properties(PROPERTIES LABELS ";
    if (labels) {
371
      fout << cmOutputConverter::EscapeForCMake(*labels);
372
373
374
375
376
    }
    if (labels && directoryLabels) {
      fout << ";";
    }
    if (directoryLabels) {
377
      fout << cmOutputConverter::EscapeForCMake(*directoryLabels);
378
    }
379
    fout << ")\n";
380
  }
381
382
}

383
384
385
void cmLocalGenerator::CreateEvaluationFileOutputs()
{
  std::vector<std::string> const& configs =
386
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
387
388
389
390
391
  for (std::string const& c : configs) {
    this->CreateEvaluationFileOutputs(c);
  }
}

392
393
void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
{
394
  for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
395
    geef->CreateOutputFile(this, config);
396
  }
397
398
399
}

void cmLocalGenerator::ProcessEvaluationFiles(
400
  std::vector<std::string>& generatedFiles)
401
{
402
  for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
403
    geef->Generate(this);
404
    if (cmSystemTools::GetFatalErrorOccured()) {
405
      return;
406
    }
407
    std::vector<std::string> files = geef->GetFiles();
408
409
410
    std::sort(files.begin(), files.end());

    std::vector<std::string> intersection;
411
412
    std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
                          generatedFiles.end(),
413
                          std::back_inserter(intersection));
414
    if (!intersection.empty()) {
415
      cmSystemTools::Error("Files to be generated by multiple different "
416
417
                           "commands: " +
                           cmWrap('"', intersection, '"', " "));
418
      return;
419
    }
420

421
    cm::append(generatedFiles, files);
422
423
424
    std::inplace_merge(generatedFiles.begin(),
                       generatedFiles.end() - files.size(),
                       generatedFiles.end());
425
  }
426
427
}

428
429
void cmLocalGenerator::GenerateInstallRules()
{
430
  // Compute the install prefix.
431
432
  const char* prefix =
    cmToCStr(this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX"));
433

434
435
#if defined(_WIN32) && !defined(__CYGWIN__)
  std::string prefix_win32;
436
437
  if (!prefix) {
    if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
438
      prefix_win32 = "C:";
439
    }
440
    cmProp project_name = this->Makefile->GetDefinition("PROJECT_NAME");
Vitaly Stakhovsky's avatar
Vitaly Stakhovsky committed
441
    if (cmNonempty(project_name)) {
442
      prefix_win32 += "/Program Files/";
443
      prefix_win32 += *project_name;
444
    } else {
445
446
      prefix_win32 += "/InstalledCMakeProject";
    }
447
448
    prefix = prefix_win32.c_str();
  }
449
#elif defined(__HAIKU__)
450
  char dir[B_PATH_NAME_LENGTH];
451
452
453
  if (!prefix) {
    if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
        B_OK) {
454
      prefix = dir;
455
    } else {
456
      prefix = "/boot/system";
457
    }
458
  }
459
#else
460
  if (!prefix) {
461
    prefix = "/usr/local";
462
  }
463
#endif
464
  if (cmProp stagingPrefix =
465
        this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
466
    prefix = stagingPrefix->c_str();
467
  }
468

469
  // Compute the set of configurations.
470
471
472
  std::vector<std::string> configurationTypes =
    this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
  std::string config = this->Makefile->GetDefaultConfiguration();
473

474
  // Choose a default install configuration.
475
  std::string default_config = config;
476
  const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
Daniel Pfeifer's avatar
Daniel Pfeifer committed
477
                                  "DEBUG", nullptr };
478
  for (const char** c = default_order; *c && default_config.empty(); ++c) {
479
480
481
    for (std::string const& configurationType : configurationTypes) {
      if (cmSystemTools::UpperCase(configurationType) == *c) {
        default_config = configurationType;
482
483
      }
    }
484
485
  }
  if (default_config.empty() && !configurationTypes.empty()) {
486
    default_config = configurationTypes[0];
487
  }
488

489
  // Create the install script file.
490
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
491
  std::string homedir = this->GetState()->GetBinaryDirectory();
492
  int toplevel_install = 0;
493
  if (file == homedir) {
494
    toplevel_install = 1;
495
  }
496
  file += "/cmake_install.cmake";
497
  cmGeneratedFileStream fout(file);
498
  fout.SetCopyIfDifferent(true);
499

500
  // Write the header.
501
  /* clang-format off */
502
  fout << "# Install script for directory: "
503
504
505
506
507
508
       << this->StateSnapshot.GetDirectory().GetCurrentSource()
       << "\n\n"
          "# Set the install prefix\n"
          "if(NOT DEFINED CMAKE_INSTALL_PREFIX)\n"
          "  set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")\n"
          "endif()\n"
509
       << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
510
511
       << "\"${CMAKE_INSTALL_PREFIX}\")\n\n";
  /* clang-format on */
512

513
  // Write support code for generating per-configuration install rules.
514
  /* clang-format off */
515
516
  fout <<
    "# Set the install configuration name.\n"
517
518
519
    "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
    "  if(BUILD_TYPE)\n"
    "    string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
520
    "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
521
522
523
524
    "  else()\n"
    "    set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
    "  endif()\n"
    "  message(STATUS \"Install configuration: "
Ken Martin's avatar
Ken Martin committed
525
    "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
526
    "endif()\n"
527
    "\n";
528
  /* clang-format on */
529

530
  // Write support code for dealing with component-specific installs.
531
  /* clang-format off */
532
533
  fout <<
    "# Set the component getting installed.\n"
534
535
536
537
538
539
540
541
    "if(NOT CMAKE_INSTALL_COMPONENT)\n"
    "  if(COMPONENT)\n"
    "    message(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n"
    "    set(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n"
    "  else()\n"
    "    set(CMAKE_INSTALL_COMPONENT)\n"
    "  endif()\n"
    "endif()\n"
542
    "\n";
543
  /* clang-format on */
544

545
  // Copy user-specified install options to the install code.
546
  if (cmProp so_no_exe =
547
        this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
548
    /* clang-format off */
549
550
    fout <<
      "# Install shared libraries without execute permission?\n"
551
      "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
552
      "  set(CMAKE_INSTALL_SO_NO_EXE \"" << *so_no_exe << "\")\n"
553
      "endif()\n"
554
      "\n";
555
    /* clang-format on */
556
  }
557

558
  // Copy cmake cross compile state to install code.
559
  if (cmProp crosscompiling =
560
561
562
563
564
        this->Makefile->GetDefinition("CMAKE_CROSSCOMPILING")) {
    /* clang-format off */
    fout <<
      "# Is this installation the result of a crosscompile?\n"
      "if(NOT DEFINED CMAKE_CROSSCOMPILING)\n"
565
      "  set(CMAKE_CROSSCOMPILING \"" << *crosscompiling << "\")\n"
566
567
568
569
570
      "endif()\n"
      "\n";
    /* clang-format on */
  }

571
  // Write default directory permissions.
572
  if (cmProp defaultDirPermissions = this->Makefile->GetDefinition(
573
574
575
576
577
578
        "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS")) {
    /* clang-format off */
    fout <<
      "# Set default install directory permissions.\n"
      "if(NOT DEFINED CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS)\n"
      "  set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS \""
579
         << *defaultDirPermissions << "\")\n"
580
581
582
583
584
      "endif()\n"
      "\n";
    /* clang-format on */
  }

585
586
587
  // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM so that
  // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
  // has same platform variable as when running cmake
588
  if (cmProp platform = this->Makefile->GetDefinition(
589
590
591
592
593
594
        "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM")) {
    /* clang-format off */
    fout <<
      "# Set default install directory permissions.\n"
      "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM)\n"
      "  set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM \""
595
         << *platform << "\")\n"
596
597
598
599
600
601
602
603
      "endif()\n"
      "\n";
    /* clang-format on */
  }

  // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL so that
  // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
  // has same tool selected as when running cmake
604
  if (cmProp command =
605
606
607
608
609
610
        this->Makefile->GetDefinition("CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL")) {
    /* clang-format off */
    fout <<
      "# Set default install directory permissions.\n"
      "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL)\n"
      "  set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL \""
611
         << *command << "\")\n"
612
613
614
615
616
617
618
619
      "endif()\n"
      "\n";
    /* clang-format on */
  }

  // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND so that
  // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
  // has same path to the tool as when running cmake
620
  if (cmProp command = this->Makefile->GetDefinition(
621
622
623
624
625
626
        "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND")) {
    /* clang-format off */
    fout <<
      "# Set default install directory permissions.\n"
      "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND)\n"
      "  set(CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND \""
627
         << *command << "\")\n"
628
629
630
631
632
633
634
635
636
637
      "endif()\n"
      "\n";
    /* clang-format on */
  }

  // Write out CMAKE_OBJDUMP so that installed code that uses
  // `file(GET_RUNTIME_DEPENDENCIES)` and hasn't specified
  // CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND has consistent
  // logic to fallback to CMAKE_OBJDUMP when `objdump` is
  // not on the path
638
  if (cmProp command = this->Makefile->GetDefinition("CMAKE_OBJDUMP")) {
639
640
641
642
643
    /* clang-format off */
    fout <<
      "# Set default install directory permissions.\n"
      "if(NOT DEFINED CMAKE_OBJDUMP)\n"
      "  set(CMAKE_OBJDUMP \""
644
         << *command << "\")\n"
645
646
647
648
649
      "endif()\n"
      "\n";
    /* clang-format on */
  }

650
651
  this->AddGeneratorSpecificInstallSetup(fout);

652
  // Ask each install generator to write its code.
653
  cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082);
654
  auto const& installers = this->Makefile->GetInstallGenerators();
655
656
657
  bool haveSubdirectoryInstall = false;
  bool haveInstallAfterSubdirectory = false;
  if (status == cmPolicies::WARN) {
658
    for (const auto& installer : installers) {
659
660
661
662
663
      installer->CheckCMP0082(haveSubdirectoryInstall,
                              haveInstallAfterSubdirectory);
      installer->Generate(fout, config, configurationTypes);
    }
  } else {
664
    for (const auto& installer : installers) {
665
666
      installer->Generate(fout, config, configurationTypes);
    }
667
  }
668

669
670
  // Write rules from old-style specification stored in targets.
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
671

672
  // Include install scripts from subdirectories.
673
674
675
676
677
678
679
  switch (status) {
    case cmPolicies::WARN:
      if (haveInstallAfterSubdirectory &&
          this->Makefile->PolicyOptionalWarningEnabled(
            "CMAKE_POLICY_WARNING_CMP0082")) {
        std::ostringstream e;
        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0082) << "\n";
680
        this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
681
      }
682
683
684
685
686
687
688
689
690
691
692
      CM_FALLTHROUGH;
    case cmPolicies::OLD: {
      std::vector<cmStateSnapshot> children =
        this->Makefile->GetStateSnapshot().GetChildren();
      if (!children.empty()) {
        fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
        fout << "  # Include the install script for each subdirectory.\n";
        for (cmStateSnapshot const& c : children) {
          if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
            std::string odir = c.GetDirectory().GetCurrentBinary();
            cmSystemTools::ConvertToUnixSlashes(odir);
693
            fout << "  include(\"" << odir << "/cmake_install.cmake\")\n";
694
695
696
697
698
699
700
701
702
703
704
705
706
          }
        }
        fout << "\n";
        fout << "endif()\n\n";
      }
    } break;

    case cmPolicies::REQUIRED_IF_USED:
    case cmPolicies::REQUIRED_ALWAYS:
    case cmPolicies::NEW:
      // NEW behavior is handled in
      // cmInstallSubdirectoryGenerator::GenerateScript()
      break;
707
  }
708
709

  // Record the install manifest.
710
  if (toplevel_install) {
711
    /* clang-format off */
712
    fout <<
713
714
      "if(CMAKE_INSTALL_COMPONENT)\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
715
      "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
716
717
      "else()\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
718
719
720
721
722
723
      "endif()\n"
      "\n"
      "string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n"
      "       \"${CMAKE_INSTALL_MANIFEST_FILES}\")\n"
      "file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n"
      "     \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n";
724
    /* clang-format on */
725
  }
726
727
}

728
729
void cmLocalGenerator::AddGeneratorTarget(
  std::unique_ptr<cmGeneratorTarget> gt)
730
{
731
732
733
734
735
  cmGeneratorTarget* gt_ptr = gt.get();

  this->GeneratorTargets.push_back(std::move(gt));
  this->GeneratorTargetSearchIndex.emplace(gt_ptr->GetName(), gt_ptr);
  this->GlobalGenerator->IndexGeneratorTarget(gt_ptr);
736
737
}

738
739
void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
{
740
  this->ImportedGeneratorTargets.emplace(gt->GetName(), gt);
741
  this->GlobalGenerator->IndexGeneratorTarget(gt);
742
743
}

744
745
void cmLocalGenerator::AddOwnedImportedGeneratorTarget(
  std::unique_ptr<cmGeneratorTarget> gt)
746
{
747
  this->OwnedImportedGeneratorTargets.push_back(std::move(gt));
748
749
}

750
cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
751
  const std::string& name) const
752
{
wahikihiki's avatar
wahikihiki committed
753
  auto ti = this->GeneratorTargetSearchIndex.find(name);
754
755
  if (ti != this->GeneratorTargetSearchIndex.end()) {
    return ti->second;
756
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
757
  return nullptr;
758
759
}

760
void cmLocalGenerator::ComputeTargetManifest()
761
762
{
  // Collect the set of configuration types.
763
764
  std::vector<std::string> configNames =
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
765
766

  // Add our targets to the manifest for each configuration.
767
768
  const auto& targets = this->GetGeneratorTargets();
  for (const auto& target : targets) {
769
    if (!target->IsInBuildSystem()) {
770
      continue;
771
    }
772
773
    for (std::string const& c : configNames) {
      target->ComputeTargetManifest(c);
774
    }
775
  }
776
777
}

778
779
780
bool cmLocalGenerator::ComputeTargetCompileFeatures()
{
  // Collect the set of configuration types.
781
782
  std::vector<std::string> configNames =
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
783

784
785
  using LanguagePair = std::pair<std::string, std::string>;
  std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" },
786
787
788
                                             { "OBJCXX", "CXX" },
                                             { "CUDA", "CXX" } };
  std::set<LanguagePair> inferredEnabledLanguages;
789
790
  for (auto const& lang : pairedLanguages) {
    if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) {
791
      inferredEnabledLanguages.insert(lang);
792
793
794
    }
  }

795
  // Process compile features of all targets.
796
797
  const auto& targets = this->GetGeneratorTargets();
  for (const auto& target : targets) {
798
799
    for (std::string const& c : configNames) {
      if (!target->ComputeCompileFeatures(c)) {
800
801
802
        return false;
      }
    }
803
804
805

    // Now that C/C++ _STANDARD values have been computed
    // set the values to ObjC/ObjCXX _STANDARD variables
806
    if (target->CanCompileSources()) {
807
808
      for (std::string const& c : configNames) {
        target->ComputeCompileFeatures(c, inferredEnabledLanguages);
809
      }
810
    }
811
812
813
814
815
  }

  return true;
}

816
817
818
819
820
bool cmLocalGenerator::IsRootMakefile() const
{
  return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
}

821
822
823
824
825
cmState* cmLocalGenerator::GetState() const
{
  return this->GlobalGenerator->GetCMakeInstance()->GetState();
}

826
cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
827
{
828
  return this->Makefile->GetStateSnapshot();
829
830
}

831
832
cmProp cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
                                         const std::string& prop)
833
{
834
  if (target) {
835
    return target->GetProperty(prop);
836
  }
837
  return this->Makefile->GetProperty(prop);
838
839
}

840
841
std::string cmLocalGenerator::ConvertToIncludeReference(
  std::string const& path, OutputFormat format, bool forceFullPaths)
842
{
843
844
  static_cast<void>(forceFullPaths);
  return this->ConvertToOutputForExisting(path, format);
845
846
}

847
std::string cmLocalGenerator::GetIncludeFlags(
848
  const std::vector<std::string>& includeDirs, cmGeneratorTarget* target,
849
850
851
852
  const std::string& lang, bool forceFullPaths, bool forResponseFile,
  const std::string& config)
{
  if (lang.empty()) {
853
    return "";
854
  }
855

856
  std::vector<std::string> includes = includeDirs;
857
  MoveSystemIncludesToEnd(includes, config, lang, target);
858

859
  OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
860
  std::ostringstream includeFlags;
861

wahikihiki's avatar
wahikihiki committed
862
863
  std::string const& includeFlag =
    this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang));
864
865
  const char* sep = cmToCStr(
    this->Makefile->GetDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang)));
866
  bool quotePaths = false;
867
  if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
868
    quotePaths = true;
869
  }
870
  bool repeatFlag = true;
Ken Martin's avatar
Ken Martin committed
871
  // should the include flag be repeated like ie. -IA -IB
872
  if (!sep) {
873
    sep = " ";
874
  } else {
Ken Martin's avatar
Ken Martin committed
875
876
    // if there is a separator then the flag is not repeated but is only
    // given once i.e.  -classpath a:b:c
877
    repeatFlag = false;
878
  }
879
880
881

  // Support special system include flag if it is available and the
  // normal flag is repeated for each directory.
882
  cmProp sysIncludeFlag = nullptr;
883
  if (repeatFlag) {
wahikihiki's avatar
wahikihiki committed
884
885
    sysIncludeFlag = this->Makefile->GetDefinition(
      cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
886
  }
887

888
  cmProp fwSearchFlag = this->Makefile->GetDefinition(
wahikihiki's avatar
wahikihiki committed
889
    cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG"));
890
  cmProp sysFwSearchFlag = this->Makefile->GetDefinition(
wahikihiki's avatar
wahikihiki committed
891
    cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG"));
892

893
  bool flagUsed = false;