cmLocalGenerator.cxx 95.9 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 "cmAlgorithms.h"
6
#include "cmComputeLinkInformation.h"
7
#include "cmCustomCommandGenerator.h"
8
#include "cmGeneratedFileStream.h"
9
#include "cmGeneratorExpressionEvaluationFile.h"
10
#include "cmGeneratorTarget.h"
Ken Martin's avatar
updates  
Ken Martin committed
11
#include "cmGlobalGenerator.h"
12
#include "cmInstallGenerator.h"
13 14
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
15
#include "cmLinkLineComputer.h"
Ken Martin's avatar
Ken Martin committed
16
#include "cmMakefile.h"
17
#include "cmRulePlaceholderExpander.h"
18
#include "cmSourceFile.h"
19
#include "cmSourceFileLocation.h"
20 21
#include "cmState.h"
#include "cmStateDirectory.h"
22
#include "cmStateTypes.h"
23 24
#include "cmSystemTools.h"
#include "cmTarget.h"
25
#include "cmTestGenerator.h"
26
#include "cmVersion.h"
27 28
#include "cmake.h"

29
#if defined(CMAKE_BUILD_WITH_CMAKE)
30 31
#  define CM_LG_ENCODE_OBJECT_NAMES
#  include "cmCryptoHash.h"
32 33
#endif

34
#include "cmsys/RegularExpression.hxx"
35
#include <algorithm>
36
#include <assert.h>
37 38 39
#include <iterator>
#include <sstream>
#include <stdio.h>
40
#include <string.h>
41
#include <unordered_set>
42
#include <utility>
43

44
#if defined(__HAIKU__)
45 46
#  include <FindDirectory.h>
#  include <StorageDefs.h>
47 48
#endif

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
// 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.
static const char* 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",
68
  "CMAKE_MT",
69 70
  "CMAKE_CUDA_HOST_COMPILER",
  "CMAKE_CUDA_HOST_LINK_LAUNCHER",
71 72 73
  "CMAKE_CL_SHOWINCLUDES_PREFIX"
};

74 75 76
cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
  : cmOutputConverter(makefile->GetStateSnapshot())
  , StateSnapshot(makefile->GetStateSnapshot())
77
  , DirectoryBacktrace(makefile->GetBacktrace())
Ken Martin's avatar
Ken Martin committed
78
{
79
  this->GlobalGenerator = gg;
80

81
  this->Makefile = makefile;
82

83 84
  this->AliasTargets = makefile->GetAliasTargets();

85
  this->EmitUniversalBinaryFlags = true;
86 87
  this->BackwardsCompatibility = 0;
  this->BackwardsCompatibilityFinal = false;
88 89

  this->ComputeObjectMaxPath();
90 91 92 93

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

94 95 96 97 98 99 100 101 102 103 104 105 106
  if (const char* sysrootCompile =
        this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
    this->CompilerSysroot = sysrootCompile;
  } else {
    this->CompilerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
  }

  if (const char* sysrootLink =
        this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
    this->LinkerSysroot = sysrootLink;
  } else {
    this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
  }
107

108
  for (std::string const& lang : enabledLanguages) {
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    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);

141 142
    for (const char* const* replaceIter = cm::cbegin(ruleReplaceVars);
         replaceIter != cm::cend(ruleReplaceVars); ++replaceIter) {
143
      std::string actualReplace = *replaceIter;
144
      if (actualReplace.find("${LANG}") != std::string::npos) {
145 146 147 148 149 150 151
        cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang);
      }

      this->VariableMappings[actualReplace] =
        this->Makefile->GetSafeDefinition(actualReplace);
    }
  }
Ken Martin's avatar
Ken Martin committed
152 153
}

154 155 156 157
cmRulePlaceholderExpander* cmLocalGenerator::CreateRulePlaceholderExpander()
  const
{
  return new cmRulePlaceholderExpander(this->Compilers, this->VariableMappings,
158 159
                                       this->CompilerSysroot,
                                       this->LinkerSysroot);
160 161
}

Ken Martin's avatar
Ken Martin committed
162 163
cmLocalGenerator::~cmLocalGenerator()
{
164 165
  cmDeleteAll(this->GeneratorTargets);
  cmDeleteAll(this->OwnedImportedGeneratorTargets);
Ken Martin's avatar
Ken Martin committed
166 167
}

168
void cmLocalGenerator::IssueMessage(MessageType t,
169 170
                                    std::string const& text) const
{
171
  this->GetCMakeInstance()->IssueMessage(t, text, this->DirectoryBacktrace);
172 173
}

174 175
void cmLocalGenerator::ComputeObjectMaxPath()
{
176
// Choose a maximum object file name length.
177 178 179 180 181 182
#if defined(_WIN32) || defined(__CYGWIN__)
  this->ObjectPathMax = 250;
#else
  this->ObjectPathMax = 1000;
#endif
  const char* plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
183
  if (plen && *plen) {
184
    unsigned int pmax;
185 186
    if (sscanf(plen, "%u", &pmax) == 1) {
      if (pmax >= 128) {
187
        this->ObjectPathMax = pmax;
188
      } else {
189
        std::ostringstream w;
190 191 192
        w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax
          << ", which is less than the minimum of 128.  "
          << "The value will be ignored.";
193
        this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
194
      }
195
    } else {
196
      std::ostringstream w;
197 198 199
      w << "CMAKE_OBJECT_PATH_MAX is set to \"" << plen
        << "\", which fails to parse as a positive integer.  "
        << "The value will be ignored.";
200
      this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
201
    }
202
  }
203
  this->ObjectMaxPathViolations.clear();
204 205
}

206 207 208 209
static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs,
                                    const std::string& config,
                                    const std::string& lang,
                                    const cmGeneratorTarget* target)
210 211 212 213 214 215 216 217 218 219 220 221 222
{
  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);
    });
}

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
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);
                   });
}

Alexander Neundorf's avatar
 
Alexander Neundorf committed
241 242
void cmLocalGenerator::TraceDependencies()
{
243 244
  std::vector<std::string> configs;
  this->Makefile->GetConfigurations(configs);
245
  if (configs.empty()) {
246
    configs.emplace_back();
247
  }
248 249
  for (std::string const& c : configs) {
    this->GlobalGenerator->CreateEvaluationSourceFiles(c);
250
  }
Alexander Neundorf's avatar
 
Alexander Neundorf committed
251
  // Generate the rule files for each target.
252
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
253 254
  for (cmGeneratorTarget* target : targets) {
    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
255
      continue;
Alexander Neundorf's avatar
 
Alexander Neundorf committed
256
    }
257
    target->TraceDependencies();
258
  }
Alexander Neundorf's avatar
 
Alexander Neundorf committed
259 260
}

261 262
void cmLocalGenerator::GenerateTestFiles()
{
263
  if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
264
    return;
265
  }
266 267 268

  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
269
  const std::string& config =
270
    this->Makefile->GetConfigurations(configurationTypes, false);
271

272 273 274 275
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
  file += "/";
  file += "CTestTestfile.cmake";

276
  cmGeneratedFileStream fout(file);
277 278 279
  fout.SetCopyIfDifferent(true);

  fout << "# CMake generated Testfile for " << std::endl
280
       << "# Source directory: "
281
       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
282
       << "# Build directory: "
283
       << this->StateSnapshot.GetDirectory().GetCurrentBinary() << std::endl
Ken Martin's avatar
Ken Martin committed
284
       << "# " << std::endl
285
       << "# This file includes the relevant testing commands "
Ken Martin's avatar
Ken Martin committed
286 287 288
       << "required for " << std::endl
       << "# testing this directory and lists subdirectories to "
       << "be tested as well." << std::endl;
289 290

  const char* testIncludeFile =
Ken Martin's avatar
Ken Martin committed
291
    this->Makefile->GetProperty("TEST_INCLUDE_FILE");
292
  if (testIncludeFile) {
293
    fout << "include(\"" << testIncludeFile << "\")" << std::endl;
294
  }
295

Matthew Woehlke's avatar
Matthew Woehlke committed
296 297 298 299 300
  const char* testIncludeFiles =
    this->Makefile->GetProperty("TEST_INCLUDE_FILES");
  if (testIncludeFiles) {
    std::vector<std::string> includesList;
    cmSystemTools::ExpandListArgument(testIncludeFiles, includesList);
301 302
    for (std::string const& i : includesList) {
      fout << "include(\"" << i << "\")" << std::endl;
Matthew Woehlke's avatar
Matthew Woehlke committed
303 304 305
    }
  }

306
  // Ask each test generator to write its code.
307 308
  std::vector<cmTestGenerator*> const& testers =
    this->Makefile->GetTestGenerators();
309 310 311
  for (cmTestGenerator* tester : testers) {
    tester->Compute(this);
    tester->Generate(fout, config, configurationTypes);
312
  }
313
  typedef std::vector<cmStateSnapshot> vec_t;
314
  vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
315
  std::string parentBinDir = this->GetCurrentBinaryDirectory();
316
  for (cmStateSnapshot const& i : children) {
317
    // TODO: Use add_subdirectory instead?
318
    std::string outP = i.GetDirectory().GetCurrentBinary();
319
    outP = this->ConvertToRelativePath(parentBinDir, outP);
320
    outP = cmOutputConverter::EscapeForCMake(outP);
321
    fout << "subdirs(" << outP << ")" << std::endl;
322
  }
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

  // Add directory labels property
  const char* directoryLabels =
    this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS");
  const char* labels = this->Makefile->GetProperty("LABELS");

  if (labels || directoryLabels) {
    fout << "set_directory_properties(PROPERTIES LABELS ";
    if (labels) {
      fout << cmOutputConverter::EscapeForCMake(labels);
    }
    if (labels && directoryLabels) {
      fout << ";";
    }
    if (directoryLabels) {
      fout << cmOutputConverter::EscapeForCMake(directoryLabels);
    }
    fout << ")" << std::endl;
  }
342 343
}

344 345 346
void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
347
    this->Makefile->GetEvaluationFiles();
348 349
  for (cmGeneratorExpressionEvaluationFile* geef : ef) {
    geef->CreateOutputFile(this, config);
350
  }
351 352 353
}

void cmLocalGenerator::ProcessEvaluationFiles(
354
  std::vector<std::string>& generatedFiles)
355 356
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
357
    this->Makefile->GetEvaluationFiles();
358 359
  for (cmGeneratorExpressionEvaluationFile* geef : ef) {
    geef->Generate(this);
360
    if (cmSystemTools::GetFatalErrorOccured()) {
361
      return;
362
    }
363
    std::vector<std::string> files = geef->GetFiles();
364 365 366
    std::sort(files.begin(), files.end());

    std::vector<std::string> intersection;
367 368
    std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
                          generatedFiles.end(),
369
                          std::back_inserter(intersection));
370
    if (!intersection.empty()) {
371
      cmSystemTools::Error("Files to be generated by multiple different "
372 373
                           "commands: ",
                           cmWrap('"', intersection, '"', " ").c_str());
374
      return;
375
    }
376 377 378

    generatedFiles.insert(generatedFiles.end(), files.begin(), files.end());
    std::vector<std::string>::iterator newIt =
379
      generatedFiles.end() - files.size();
380
    std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
381
  }
382 383
}

384 385
void cmLocalGenerator::GenerateInstallRules()
{
386
  // Compute the install prefix.
Ken Martin's avatar
Ken Martin committed
387
  const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
388

389 390
#if defined(_WIN32) && !defined(__CYGWIN__)
  std::string prefix_win32;
391 392
  if (!prefix) {
    if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
393
      prefix_win32 = "C:";
394
    }
Ken Martin's avatar
Ken Martin committed
395
    const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME");
396
    if (project_name && project_name[0]) {
397 398
      prefix_win32 += "/Program Files/";
      prefix_win32 += project_name;
399
    } else {
400 401
      prefix_win32 += "/InstalledCMakeProject";
    }
402 403
    prefix = prefix_win32.c_str();
  }
404
#elif defined(__HAIKU__)
405
  char dir[B_PATH_NAME_LENGTH];
406 407 408
  if (!prefix) {
    if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
        B_OK) {
409
      prefix = dir;
410
    } else {
411
      prefix = "/boot/system";
412
    }
413
  }
414
#else
415
  if (!prefix) {
416
    prefix = "/usr/local";
417
  }
418
#endif
419 420
  if (const char* stagingPrefix =
        this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
421
    prefix = stagingPrefix;
422
  }
423

424 425
  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
426
  const std::string& config =
427
    this->Makefile->GetConfigurations(configurationTypes, false);
428

429
  // Choose a default install configuration.
430
  std::string default_config = config;
431
  const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
Daniel Pfeifer's avatar
Daniel Pfeifer committed
432
                                  "DEBUG", nullptr };
433
  for (const char** c = default_order; *c && default_config.empty(); ++c) {
434 435 436
    for (std::string const& configurationType : configurationTypes) {
      if (cmSystemTools::UpperCase(configurationType) == *c) {
        default_config = configurationType;
437 438
      }
    }
439 440
  }
  if (default_config.empty() && !configurationTypes.empty()) {
441
    default_config = configurationTypes[0];
442
  }
443

444
  // Create the install script file.
445
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
446
  std::string homedir = this->GetState()->GetBinaryDirectory();
447
  int toplevel_install = 0;
448
  if (file == homedir) {
449
    toplevel_install = 1;
450
  }
451
  file += "/cmake_install.cmake";
452
  cmGeneratedFileStream fout(file);
453
  fout.SetCopyIfDifferent(true);
454

455 456
  // Write the header.
  fout << "# Install script for directory: "
457 458
       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
       << std::endl;
Ken Martin's avatar
Ken Martin committed
459
  fout << "# Set the install prefix" << std::endl
460 461 462 463
       << "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
       << "  set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
       << "endif()" << std::endl
       << "string(REGEX REPLACE \"/$\" \"\" CMAKE_INSTALL_PREFIX "
Ken Martin's avatar
Ken Martin committed
464 465
       << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
       << std::endl;
466

467
  // Write support code for generating per-configuration install rules.
468
  /* clang-format off */
469 470
  fout <<
    "# Set the install configuration name.\n"
471 472 473
    "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
    "  if(BUILD_TYPE)\n"
    "    string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
474
    "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
475 476 477 478
    "  else()\n"
    "    set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
    "  endif()\n"
    "  message(STATUS \"Install configuration: "
Ken Martin's avatar
Ken Martin committed
479
    "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
480
    "endif()\n"
481
    "\n";
482
  /* clang-format on */
483

484
  // Write support code for dealing with component-specific installs.
485
  /* clang-format off */
486 487
  fout <<
    "# Set the component getting installed.\n"
488 489 490 491 492 493 494 495
    "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"
496
    "\n";
497
  /* clang-format on */
498

499
  // Copy user-specified install options to the install code.
500 501
  if (const char* so_no_exe =
        this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
502
    /* clang-format off */
503 504
    fout <<
      "# Install shared libraries without execute permission?\n"
505 506 507
      "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
      "  set(CMAKE_INSTALL_SO_NO_EXE \"" << so_no_exe << "\")\n"
      "endif()\n"
508
      "\n";
509
    /* clang-format on */
510
  }
511

512 513 514 515 516 517 518 519 520 521 522 523 524
  // Copy cmake cross compile state to install code.
  if (const char* crosscompiling =
        this->Makefile->GetDefinition("CMAKE_CROSSCOMPILING")) {
    /* clang-format off */
    fout <<
      "# Is this installation the result of a crosscompile?\n"
      "if(NOT DEFINED CMAKE_CROSSCOMPILING)\n"
      "  set(CMAKE_CROSSCOMPILING \"" << crosscompiling << "\")\n"
      "endif()\n"
      "\n";
    /* clang-format on */
  }

525 526 527 528 529 530 531 532 533 534 535 536 537 538
  // Write default directory permissions.
  if (const char* defaultDirPermissions = this->Makefile->GetDefinition(
        "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 \""
         << defaultDirPermissions << "\")\n"
      "endif()\n"
      "\n";
    /* clang-format on */
  }

539
  // Ask each install generator to write its code.
540
  cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082);
541
  std::vector<cmInstallGenerator*> const& installers =
Ken Martin's avatar
Ken Martin committed
542
    this->Makefile->GetInstallGenerators();
543 544 545 546 547 548 549 550 551 552 553 554
  bool haveSubdirectoryInstall = false;
  bool haveInstallAfterSubdirectory = false;
  if (status == cmPolicies::WARN) {
    for (cmInstallGenerator* installer : installers) {
      installer->CheckCMP0082(haveSubdirectoryInstall,
                              haveInstallAfterSubdirectory);
      installer->Generate(fout, config, configurationTypes);
    }
  } else {
    for (cmInstallGenerator* installer : installers) {
      installer->Generate(fout, config, configurationTypes);
    }
555
  }
556

557 558
  // Write rules from old-style specification stored in targets.
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
559

560
  // Include install scripts from subdirectories.
561 562 563 564 565 566 567
  switch (status) {
    case cmPolicies::WARN:
      if (haveInstallAfterSubdirectory &&
          this->Makefile->PolicyOptionalWarningEnabled(
            "CMAKE_POLICY_WARNING_CMP0082")) {
        std::ostringstream e;
        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0082) << "\n";
568
        this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
569
      }
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
      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);
            fout << "  include(\"" << odir << "/cmake_install.cmake\")"
                 << std::endl;
          }
        }
        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;
596
  }
597 598

  // Record the install manifest.
599
  if (toplevel_install) {
600
    /* clang-format off */
601
    fout <<
602 603
      "if(CMAKE_INSTALL_COMPONENT)\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
604
      "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
605 606
      "else()\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
607 608 609 610 611 612
      "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";
613
    /* clang-format on */
614
  }
615 616
}

617
void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt)
618
{
619
  this->GeneratorTargets.push_back(gt);
620
  this->GeneratorTargetSearchIndex.emplace(gt->GetName(), gt);
621
  this->GlobalGenerator->IndexGeneratorTarget(gt);
622 623
}

624 625
void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
{
626
  this->ImportedGeneratorTargets.emplace(gt->GetName(), gt);
627
  this->GlobalGenerator->IndexGeneratorTarget(gt);
628 629
}

630 631 632 633 634
void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt)
{
  this->OwnedImportedGeneratorTargets.push_back(gt);
}

635
cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
636
  const std::string& name) const
637
{
638 639 640 641
  GeneratorTargetMap::const_iterator ti =
    this->GeneratorTargetSearchIndex.find(name);
  if (ti != this->GeneratorTargetSearchIndex.end()) {
    return ti->second;
642
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
643
  return nullptr;
644 645
}

646
void cmLocalGenerator::ComputeTargetManifest()
647 648 649
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
650
  this->Makefile->GetConfigurations(configNames);
651
  if (configNames.empty()) {
652
    configNames.emplace_back();
653
  }
654 655

  // Add our targets to the manifest for each configuration.
656
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
657
  for (cmGeneratorTarget* target : targets) {
658
    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
659
      continue;
660
    }
661 662
    for (std::string const& c : configNames) {
      target->ComputeTargetManifest(c);
663
    }
664
  }
665 666
}

667 668 669 670 671 672
bool cmLocalGenerator::ComputeTargetCompileFeatures()
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
  this->Makefile->GetConfigurations(configNames);
  if (configNames.empty()) {
673
    configNames.emplace_back();
674 675 676
  }

  // Process compile features of all targets.
677
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
678 679 680
  for (cmGeneratorTarget* target : targets) {
    for (std::string const& c : configNames) {
      if (!target->ComputeCompileFeatures(c)) {
681 682 683 684 685 686 687 688
        return false;
      }
    }
  }

  return true;
}

689 690 691 692 693
bool cmLocalGenerator::IsRootMakefile() const
{
  return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
}

694 695 696 697 698
cmState* cmLocalGenerator::GetState() const
{
  return this->GlobalGenerator->GetCMakeInstance()->GetState();
}

699
cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
700
{
701
  return this->Makefile->GetStateSnapshot();
702 703
}

704
const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
705
                                              const std::string& prop)
706
{
707
  if (target) {
708
    return target->GetProperty(prop);
709
  }
710
  return this->Makefile->GetProperty(prop);
711 712
}

713 714
std::string cmLocalGenerator::ConvertToIncludeReference(
  std::string const& path, OutputFormat format, bool forceFullPaths)
715
{
716 717
  static_cast<void>(forceFullPaths);
  return this->ConvertToOutputForExisting(path, format);
718 719
}

720
std::string cmLocalGenerator::GetIncludeFlags(
721
  const std::vector<std::string>& includeDirs, cmGeneratorTarget* target,
722 723 724 725
  const std::string& lang, bool forceFullPaths, bool forResponseFile,
  const std::string& config)
{
  if (lang.empty()) {
726
    return "";
727
  }
728

729
  std::vector<std::string> includes = includeDirs;
730
  MoveSystemIncludesToEnd(includes, config, lang, target);
731

732
  OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
733
  std::ostringstream includeFlags;
734 735 736

  std::string flagVar = "CMAKE_INCLUDE_FLAG_";
  flagVar += lang;
737
  std::string const& includeFlag = this->Makefile->GetSafeDefinition(flagVar);
738 739
  flagVar = "CMAKE_INCLUDE_FLAG_SEP_";
  flagVar += lang;
Stephen Kelly's avatar
Stephen Kelly committed
740
  const char* sep = this->Makefile->GetDefinition(flagVar);
741
  bool quotePaths = false;
742
  if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
743
    quotePaths = true;
744
  }
745
  bool repeatFlag = true;
Ken Martin's avatar
Ken Martin committed
746
  // should the include flag be repeated like ie. -IA -IB
747
  if (!sep) {
748
    sep = " ";
749
  } else {
Ken Martin's avatar
Ken Martin committed
750 751
    // if there is a separator then the flag is not repeated but is only
    // given once i.e.  -classpath a:b:c
752
    repeatFlag = false;
753
  }
754 755 756 757 758

  // Support special system include flag if it is available and the
  // normal flag is repeated for each directory.
  std::string sysFlagVar = "CMAKE_INCLUDE_SYSTEM_FLAG_";
  sysFlagVar += lang;
Daniel Pfeifer's avatar
Daniel Pfeifer committed
759
  const char* sysIncludeFlag = nullptr;
760
  if (repeatFlag) {
Stephen Kelly's avatar
Stephen Kelly committed
761
    sysIncludeFlag = this->Makefile->GetDefinition(sysFlagVar);
762
  }
763

764 765 766
  std::string fwSearchFlagVar = "CMAKE_";
  fwSearchFlagVar += lang;
  fwSearchFlagVar += "_FRAMEWORK_SEARCH_FLAG";
767
  const char* fwSearchFlag = this->Makefile->GetDefinition(fwSearchFlagVar);
768

769 770 771 772 773 774
  std::string sysFwSearchFlagVar = "CMAKE_";
  sysFwSearchFlagVar += lang;
  sysFwSearchFlagVar += "_SYSTEM_FRAMEWORK_SEARCH_FLAG";
  const char* sysFwSearchFlag =
    this->Makefile->GetDefinition(sysFwSearchFlagVar);

775
  bool flagUsed = false;
776
  std::set<std::string> emitted;
777 778 779
#ifdef __APPLE__
  emitted.insert("/System/Library/Frameworks");
#endif
780
  for (std::string const& i : includes) {
781
    if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
782 783
        cmSystemTools::IsPathToFramework(i.c_str())) {
      std::string frameworkDir = i;
784
      frameworkDir += "/../";
785
      frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
786
      if (emitted.insert(frameworkDir).second) {