cmLocalGenerator.cxx 95.8 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) {
787
        if (sysFwSearchFlag && target &&
788
            target->IsSystemIncludeDirectory(i, config, lang)) {
789
          includeFlags << sysFwSearchFlag;
790
        } else {
791
          includeFlags << fwSearchFlag;
792
        }
793
794
        includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat)
                     << " ";
795
      }
796
797
      continue;
    }
798

799
800
    if (!flagUsed || repeatFlag) {
      if (sysIncludeFlag && target &&
801
          target->IsSystemIncludeDirectory(i, config, lang)) {
802
        includeFlags << sysIncludeFlag;
803
      } else {
804
        includeFlags << includeFlag;
805
      }
806
807
      flagUsed = true;
    }
808
    std::string includePath =
809
      this->ConvertToIncludeReference(i, shellFormat, forceFullPaths);
810
    if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
811
      includeFlags << "\"";
812
    }
813
    includeFlags << includePath;
814
    if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
815
      includeFlags << "\"";
816
    }
817
818
    includeFlags << sep;
  }
819
820
  std::string flags = includeFlags.str();
  // remove trailing separators