Updates will be applied on October 27th between 12pm - 12:45pm EDT (UTC-0400). Gitlab may be slow during the maintenance window.

cmLocalGenerator.cxx 87.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
20
#include "cmState.h"
#include "cmStateDirectory.h"
21
#include "cmStateTypes.h"
22
23
#include "cmSystemTools.h"
#include "cmTarget.h"
24
#include "cmTestGenerator.h"
25
#include "cmVersion.h"
26
27
#include "cmake.h"

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

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

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

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 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",
66
67
  "CMAKE_CUDA_HOST_COMPILER",
  "CMAKE_CUDA_HOST_LINK_LAUNCHER",
68
69
70
  "CMAKE_CL_SHOWINCLUDES_PREFIX"
};

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

78
  this->Makefile = makefile;
79

80
81
  this->AliasTargets = makefile->GetAliasTargets();

82
  this->EmitUniversalBinaryFlags = true;
83
84
  this->BackwardsCompatibility = 0;
  this->BackwardsCompatibilityFinal = false;
85
86

  this->ComputeObjectMaxPath();
87
88
89
90

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

91
92
93
94
95
96
97
98
99
100
101
102
103
  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");
  }
104
105
106
107
108
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
141
142

  for (std::vector<std::string>::iterator i = enabledLanguages.begin();
       i != enabledLanguages.end(); ++i) {
    std::string const& lang = *i;
    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);

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

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

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

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

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

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

Alexander Neundorf's avatar
   
Alexander Neundorf committed
205
206
void cmLocalGenerator::TraceDependencies()
{
207
208
  std::vector<std::string> configs;
  this->Makefile->GetConfigurations(configs);
209
  if (configs.empty()) {
210
    configs.push_back("");
211
212
213
  }
  for (std::vector<std::string>::const_iterator ci = configs.begin();
       ci != configs.end(); ++ci) {
214
    this->GlobalGenerator->CreateEvaluationSourceFiles(*ci);
215
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
216
  // Generate the rule files for each target.
217
  std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
218
219
  for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
       t != targets.end(); ++t) {
220
    if ((*t)->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
221
      continue;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
222
    }
223
224
    (*t)->TraceDependencies();
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
225
226
}

227
228
void cmLocalGenerator::GenerateTestFiles()
{
229
  if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
230
    return;
231
  }
232
233
234

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

238
239
240
241
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
  file += "/";
  file += "CTestTestfile.cmake";

242
243
244
245
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);

  fout << "# CMake generated Testfile for " << std::endl
246
       << "# Source directory: "
247
       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
248
       << "# Build directory: "
249
       << this->StateSnapshot.GetDirectory().GetCurrentBinary() << std::endl
Ken Martin's avatar
Ken Martin committed
250
       << "# " << std::endl
251
       << "# This file includes the relevant testing commands "
Ken Martin's avatar
Ken Martin committed
252
253
254
       << "required for " << std::endl
       << "# testing this directory and lists subdirectories to "
       << "be tested as well." << std::endl;
255
256

  const char* testIncludeFile =
Ken Martin's avatar
Ken Martin committed
257
    this->Makefile->GetProperty("TEST_INCLUDE_FILE");
258
  if (testIncludeFile) {
259
    fout << "include(\"" << testIncludeFile << "\")" << std::endl;
260
  }
261
262

  // Ask each test generator to write its code.
263
264
265
266
  std::vector<cmTestGenerator*> const& testers =
    this->Makefile->GetTestGenerators();
  for (std::vector<cmTestGenerator*>::const_iterator gi = testers.begin();
       gi != testers.end(); ++gi) {
267
    (*gi)->Compute(this);
268
    (*gi)->Generate(fout, config, configurationTypes);
269
  }
270
  typedef std::vector<cmStateSnapshot> vec_t;
271
  vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
272
  std::string parentBinDir = this->GetCurrentBinaryDirectory();
273
  for (vec_t::const_iterator i = children.begin(); i != children.end(); ++i) {
274
    // TODO: Use add_subdirectory instead?
275
    std::string outP = i->GetDirectory().GetCurrentBinary();
276
    outP = this->ConvertToRelativePath(parentBinDir, outP);
277
    outP = cmOutputConverter::EscapeForCMake(outP);
278
    fout << "subdirs(" << outP << ")" << std::endl;
279
  }
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

  // 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;
  }
299
300
}

301
302
303
void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
304
305
306
307
    this->Makefile->GetEvaluationFiles();
  for (std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator li =
         ef.begin();
       li != ef.end(); ++li) {
308
    (*li)->CreateOutputFile(this, config);
309
  }
310
311
312
}

void cmLocalGenerator::ProcessEvaluationFiles(
313
  std::vector<std::string>& generatedFiles)
314
315
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
316
317
318
319
    this->Makefile->GetEvaluationFiles();
  for (std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator li =
         ef.begin();
       li != ef.end(); ++li) {
320
    (*li)->Generate(this);
321
    if (cmSystemTools::GetFatalErrorOccured()) {
322
      return;
323
    }
324
325
326
327
    std::vector<std::string> files = (*li)->GetFiles();
    std::sort(files.begin(), files.end());

    std::vector<std::string> intersection;
328
329
    std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
                          generatedFiles.end(),
330
                          std::back_inserter(intersection));
331
    if (!intersection.empty()) {
332
      cmSystemTools::Error("Files to be generated by multiple different "
333
334
                           "commands: ",
                           cmWrap('"', intersection, '"', " ").c_str());
335
      return;
336
    }
337
338
339

    generatedFiles.insert(generatedFiles.end(), files.begin(), files.end());
    std::vector<std::string>::iterator newIt =
340
      generatedFiles.end() - files.size();
341
    std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
342
  }
343
344
}

345
346
void cmLocalGenerator::GenerateInstallRules()
{
347
  // Compute the install prefix.
Ken Martin's avatar
Ken Martin committed
348
  const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
349

350
351
#if defined(_WIN32) && !defined(__CYGWIN__)
  std::string prefix_win32;
352
353
  if (!prefix) {
    if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
354
      prefix_win32 = "C:";
355
    }
Ken Martin's avatar
Ken Martin committed
356
    const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME");
357
    if (project_name && project_name[0]) {
358
359
      prefix_win32 += "/Program Files/";
      prefix_win32 += project_name;
360
    } else {
361
362
      prefix_win32 += "/InstalledCMakeProject";
    }
363
364
    prefix = prefix_win32.c_str();
  }
365
#elif defined(__HAIKU__)
366
  char dir[B_PATH_NAME_LENGTH];
367
368
369
  if (!prefix) {
    if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
        B_OK) {
370
      prefix = dir;
371
    } else {
372
      prefix = "/boot/system";
373
    }
374
  }
375
#else
376
  if (!prefix) {
377
    prefix = "/usr/local";
378
  }
379
#endif
380
381
  if (const char* stagingPrefix =
        this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
382
    prefix = stagingPrefix;
383
  }
384

385
386
  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
387
  const std::string& config =
388
    this->Makefile->GetConfigurations(configurationTypes, false);
389

390
  // Choose a default install configuration.
391
  std::string default_config = config;
392
  const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
Daniel Pfeifer's avatar
Daniel Pfeifer committed
393
                                  "DEBUG", CM_NULLPTR };
394
395
396
397
  for (const char** c = default_order; *c && default_config.empty(); ++c) {
    for (std::vector<std::string>::iterator i = configurationTypes.begin();
         i != configurationTypes.end(); ++i) {
      if (cmSystemTools::UpperCase(*i) == *c) {
398
        default_config = *i;
399
400
      }
    }
401
402
  }
  if (default_config.empty() && !configurationTypes.empty()) {
403
    default_config = configurationTypes[0];
404
  }
405

406
  // Create the install script file.
407
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
408
  std::string homedir = this->GetState()->GetBinaryDirectory();
409
  int toplevel_install = 0;
410
  if (file == homedir) {
411
    toplevel_install = 1;
412
  }
413
  file += "/cmake_install.cmake";
414
415
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);
416

417
418
  // Write the header.
  fout << "# Install script for directory: "
419
420
       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
       << std::endl;
Ken Martin's avatar
Ken Martin committed
421
  fout << "# Set the install prefix" << std::endl
422
423
424
425
       << "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
426
427
       << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
       << std::endl;
428

429
  // Write support code for generating per-configuration install rules.
430
  /* clang-format off */
431
432
  fout <<
    "# Set the install configuration name.\n"
433
434
435
    "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
    "  if(BUILD_TYPE)\n"
    "    string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
436
    "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
437
438
439
440
    "  else()\n"
    "    set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
    "  endif()\n"
    "  message(STATUS \"Install configuration: "
Ken Martin's avatar
Ken Martin committed
441
    "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
442
    "endif()\n"
443
    "\n";
444
  /* clang-format on */
445

446
  // Write support code for dealing with component-specific installs.
447
  /* clang-format off */
448
449
  fout <<
    "# Set the component getting installed.\n"
450
451
452
453
454
455
456
457
    "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"
458
    "\n";
459
  /* clang-format on */
460

461
  // Copy user-specified install options to the install code.
462
463
  if (const char* so_no_exe =
        this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
464
    /* clang-format off */
465
466
    fout <<
      "# Install shared libraries without execute permission?\n"
467
468
469
      "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
      "  set(CMAKE_INSTALL_SO_NO_EXE \"" << so_no_exe << "\")\n"
      "endif()\n"
470
      "\n";
471
    /* clang-format on */
472
  }
473

474
475
476
477
478
479
480
481
482
483
484
485
486
  // 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 */
  }

487
488
  // Ask each install generator to write its code.
  std::vector<cmInstallGenerator*> const& installers =
Ken Martin's avatar
Ken Martin committed
489
    this->Makefile->GetInstallGenerators();
490
491
492
  for (std::vector<cmInstallGenerator*>::const_iterator gi =
         installers.begin();
       gi != installers.end(); ++gi) {
493
    (*gi)->Generate(fout, config, configurationTypes);
494
  }
495

496
497
  // Write rules from old-style specification stored in targets.
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
498

499
  // Include install scripts from subdirectories.
500
  std::vector<cmStateSnapshot> children =
501
502
    this->Makefile->GetStateSnapshot().GetChildren();
  if (!children.empty()) {
503
    fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
504
    fout << "  # Include the install script for each subdirectory.\n";
505
    for (std::vector<cmStateSnapshot>::const_iterator ci = children.begin();
506
507
         ci != children.end(); ++ci) {
      if (!ci->GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
508
        std::string odir = ci->GetDirectory().GetCurrentBinary();
509
        cmSystemTools::ConvertToUnixSlashes(odir);
510
511
        fout << "  include(\"" << odir << "/cmake_install.cmake\")"
             << std::endl;
512
      }
513
    }
514
    fout << "\n";
515
    fout << "endif()\n\n";
516
  }
517
518

  // Record the install manifest.
519
  if (toplevel_install) {
520
    /* clang-format off */
521
    fout <<
522
523
      "if(CMAKE_INSTALL_COMPONENT)\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
524
      "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
525
526
      "else()\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
527
528
529
530
531
532
      "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";
533
    /* clang-format on */
534
  }
535
536
}

537
void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt)
538
{
539
  this->GeneratorTargets.push_back(gt);
540
  this->GlobalGenerator->IndexGeneratorTarget(gt);
541
542
}

543
544
545
void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
{
  this->ImportedGeneratorTargets.push_back(gt);
546
  this->GlobalGenerator->IndexGeneratorTarget(gt);
547
548
}

549
550
551
552
553
void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt)
{
  this->OwnedImportedGeneratorTargets.push_back(gt);
}

554
555
556
557
558
559
560
561
562
563
564
struct NamedGeneratorTargetFinder
{
  NamedGeneratorTargetFinder(std::string const& name)
    : Name(name)
  {
  }

  bool operator()(cmGeneratorTarget* tgt)
  {
    return tgt->GetName() == this->Name;
  }
565

566
567
568
569
private:
  std::string Name;
};

570
cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
571
  const std::string& name) const
572
{
573
  std::vector<cmGeneratorTarget*>::const_iterator ti =
574
575
576
    std::find_if(this->GeneratorTargets.begin(), this->GeneratorTargets.end(),
                 NamedGeneratorTargetFinder(name));
  if (ti != this->GeneratorTargets.end()) {
577
    return *ti;
578
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
579
  return CM_NULLPTR;
580
581
}

582
void cmLocalGenerator::ComputeTargetManifest()
583
584
585
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
586
  this->Makefile->GetConfigurations(configNames);
587
  if (configNames.empty()) {
588
    configNames.push_back("");
589
  }
590
591

  // Add our targets to the manifest for each configuration.
592
  std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
593
594
  for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
       t != targets.end(); ++t) {
595
    cmGeneratorTarget* target = *t;
596
    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
597
      continue;
598
599
600
    }
    for (std::vector<std::string>::iterator ci = configNames.begin();
         ci != configNames.end(); ++ci) {
601
      const char* config = ci->c_str();
602
      target->ComputeTargetManifest(config);
603
    }
604
  }
605
606
}

607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
bool cmLocalGenerator::ComputeTargetCompileFeatures()
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
  this->Makefile->GetConfigurations(configNames);
  if (configNames.empty()) {
    configNames.push_back("");
  }

  // Process compile features of all targets.
  std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
  for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
       t != targets.end(); ++t) {
    cmGeneratorTarget* target = *t;
    for (std::vector<std::string>::iterator ci = configNames.begin();
         ci != configNames.end(); ++ci) {
      if (!target->ComputeCompileFeatures(*ci)) {
        return false;
      }
    }
  }

  return true;
}

632
633
634
635
636
bool cmLocalGenerator::IsRootMakefile() const
{
  return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
}

637
638
639
640
641
cmState* cmLocalGenerator::GetState() const
{
  return this->GlobalGenerator->GetCMakeInstance()->GetState();
}

642
cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
643
{
644
  return this->Makefile->GetStateSnapshot();
645
646
}

647
const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
648
                                              const std::string& prop)
649
{
650
  if (target) {
651
    return target->GetProperty(prop);
652
  }
653
  return this->Makefile->GetProperty(prop);
654
655
}

656
657
std::string cmLocalGenerator::ConvertToIncludeReference(
  std::string const& path, OutputFormat format, bool forceFullPaths)
658
{
659
660
  static_cast<void>(forceFullPaths);
  return this->ConvertToOutputForExisting(path, format);
661
662
}

663
std::string cmLocalGenerator::GetIncludeFlags(
664
665
666
667
668
  const std::vector<std::string>& includes, cmGeneratorTarget* target,
  const std::string& lang, bool forceFullPaths, bool forResponseFile,
  const std::string& config)
{
  if (lang.empty()) {
669
    return "";
670
  }
671

672
  OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
673
  std::ostringstream includeFlags;
674
675
676

  std::string flagVar = "CMAKE_INCLUDE_FLAG_";
  flagVar += lang;
677
  const char* includeFlag = this->Makefile->GetSafeDefinition(flagVar);
678
679
  flagVar = "CMAKE_INCLUDE_FLAG_SEP_";
  flagVar += lang;
Stephen Kelly's avatar
Stephen Kelly committed
680
  const char* sep = this->Makefile->GetDefinition(flagVar);
681
  bool quotePaths = false;
682
  if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
683
    quotePaths = true;
684
  }
685
  bool repeatFlag = true;
Ken Martin's avatar
Ken Martin committed
686
  // should the include flag be repeated like ie. -IA -IB
687
  if (!sep) {
688
    sep = " ";
689
  } else {
Ken Martin's avatar
Ken Martin committed
690
691
    // if there is a separator then the flag is not repeated but is only
    // given once i.e.  -classpath a:b:c
692
    repeatFlag = false;
693
  }
694
695
696
697
698

  // 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
699
  const char* sysIncludeFlag = CM_NULLPTR;
700
  if (repeatFlag) {
Stephen Kelly's avatar
Stephen Kelly committed
701
    sysIncludeFlag = this->Makefile->GetDefinition(sysFlagVar);
702
  }
703

704
705
706
  std::string fwSearchFlagVar = "CMAKE_";
  fwSearchFlagVar += lang;
  fwSearchFlagVar += "_FRAMEWORK_SEARCH_FLAG";
707
  const char* fwSearchFlag = this->Makefile->GetDefinition(fwSearchFlagVar);
708

709
710
711
712
713
714
  std::string sysFwSearchFlagVar = "CMAKE_";
  sysFwSearchFlagVar += lang;
  sysFwSearchFlagVar += "_SYSTEM_FRAMEWORK_SEARCH_FLAG";
  const char* sysFwSearchFlag =
    this->Makefile->GetDefinition(sysFwSearchFlagVar);

715
  bool flagUsed = false;
716
  std::set<std::string> emitted;
717
718
719
#ifdef __APPLE__
  emitted.insert("/System/Library/Frameworks");
#endif
720
  std::vector<std::string>::const_iterator i;
721
722
723
  for (i = includes.begin(); i != includes.end(); ++i) {
    if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
        cmSystemTools::IsPathToFramework(i->c_str())) {
724
725
      std::string frameworkDir = *i;
      frameworkDir += "/../";
726
      frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
727
      if (emitted.insert(frameworkDir).second) {
728
        if (sysFwSearchFlag && target &&
729
            target->IsSystemIncludeDirectory(*i, config)) {
730
          includeFlags << sysFwSearchFlag;
731
        } else {
732
          includeFlags << fwSearchFlag;
733
        }
734
735
        includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat)
                     << " ";
736
      }
737
738
      continue;
    }
739

740
741
742
    if (!flagUsed || repeatFlag) {
      if (sysIncludeFlag && target &&
          target->IsSystemIncludeDirectory(*i, config)) {
743
        includeFlags << sysIncludeFlag;
744
      } else {
745
        includeFlags << includeFlag;
746
      }
747
748
      flagUsed = true;
    }
749
    std::string includePath =
750
      this->ConvertToIncludeReference(*i, shellFormat, forceFullPaths);
751
    if (quotePaths && !includePath.empty() && includePath[0] != '\"') {
752
      includeFlags << "\"";
753
    }
754
    includeFlags << includePath;
755
    if (quotePaths && !includePath.empty() && includePath[0] != '\"') {
756
      includeFlags << "\"";
757
    }
758
759
    includeFlags << sep;
  }
760
761
  std::string flags = includeFlags.str();
  // remove trailing separators
762
763
764
  if ((sep[0] != ' ') && !flags.empty() && flags[flags.size() - 1] == sep[0]) {
    flags[flags.size() - 1] = ' ';
  }
765
  return flags;
766
767
}

768
void cmLocalGenerator::AddCompileDefinitions(std::set<std::string>& defines,
769
                                             cmGeneratorTarget const* target,
770
                                             const std::string& config,
771
                                             const std::string& lang) const
772
773
{
  std::vector<std::string> targetDefines;
774
  target->GetCompileDefinitions(targetDefines, config, lang);
775
776
777
  this->AppendDefines(defines, targetDefines);
}

778
779
780
781
void cmLocalGenerator::AddCompileOptions(std::string& flags,
                                         cmGeneratorTarget* target,
                                         const std::string& lang,
                                         const std::string& config)
782
{
783
  std::string langFlagRegexVar = std::string("CMAKE_") + lang + "_FLAG_REGEX";
784

785
786
  if (const char* langFlagRegexStr =
        this->Makefile->GetDefinition(langFlagRegexVar)) {
787
788
789
    // Filter flags acceptable to this language.
    cmsys::RegularExpression r(langFlagRegexStr);
    std::vector<std::string> opts;
790
    if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
791
      cmSystemTools::ParseWindowsCommandLine(targetFlags, opts);
792
    }
793
    target->GetCompileOptions(opts, config, lang);
794
795
796
    for (std::vector<std::string>::const_iterator i = opts.begin();
         i != opts.end(); ++i) {
      if (r.find(i->c_str())) {
797
798
        // (Re-)Escape this flag.  COMPILE_FLAGS were already parsed
        // as a command line above, and COMPILE_OPTIONS are escaped.
Stephen Kelly's avatar
Stephen Kelly committed
799
        this->AppendFlagEscape(flags, *i);
800
      }
801
    }
802
  } else {
803
    // Use all flags.
804
    if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
805
806
      // COMPILE_FLAGS are not escaped for historical reasons.
      this->AppendFlags(flags, targetFlags);
807
    }
808
    std::vector<std::string> opts;
809
    target->GetCompileOptions(opts, config, lang);
810
811
    for (std::vector<std::string>::const_iterator i = opts.begin();
         i != opts.end(); ++i) {
812
      // COMPILE_OPTIONS are escaped.
Stephen Kelly's avatar
Stephen Kelly committed
813
      this->AppendFlagEscape(flags, *i);
814
    }
815
  }
816

817
818
819
  for (std::map<std::string, std::string>::const_iterator it =
         target->GetMaxLanguageStandards().begin();
       it != target->GetMaxLanguageStandards().end(); ++it) {
820
    const char* standard = target->GetProperty(it->first + "_STANDARD");
821
    if (!standard) {
822
      continue;
823
824
    }
    if (this->Makefile->IsLaterStandard(it->first, standard, it->second)) {
825
      std::ostringstream e;
826
827
828
829
830
831
832
833
834
835
836
837
838
      e << "The COMPILE_FEATURES property of target \"" << target->GetName()
        << "\" was evaluated when computing the link "
           "implementation, and the \""
        << it->first << "_STANDARD\" was \"" << it->second
        << "\" for that computation.  Computing the "
           "COMPILE_FEATURES based on the link implementation resulted in a "
           "higher \""
        << it->first << "_STANDARD\" \"" << standard
        << "\".  "
           "This is not permitted. The COMPILE_FEATURES may not both depend "
           "on "
           "and be depended on by the link implementation."
        << std::endl;
839
      this->IssueMessage(cmake::FATAL_ERROR, e.str());
840
841
      return;
    }
842
  }
843
  this->AddCompilerRequirementFlag(flags, target, lang);
844
845
}

846
void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
847
                                             cmGeneratorTarget const* target,
848
                                             const std::string& lang,
849
                                             const std::string& config,
850