cmLocalGenerator.cxx 90.6 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
#define CM_LG_ENCODE_OBJECT_NAMES
31
#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
69
  "CMAKE_CUDA_HOST_COMPILER",
  "CMAKE_CUDA_HOST_LINK_LAUNCHER",
70
71
72
  "CMAKE_CL_SHOWINCLUDES_PREFIX"
};

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

80
  this->Makefile = makefile;
81

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

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

  this->ComputeObjectMaxPath();
89
90
91
92

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

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

107
  for (std::string const& lang : enabledLanguages) {
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
    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);

140
141
    for (const char* const* replaceIter = cm::cbegin(ruleReplaceVars);
         replaceIter != cm::cend(ruleReplaceVars); ++replaceIter) {
142
      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.emplace_back();
211
  }
212
213
  for (std::string const& c : configs) {
    this->GlobalGenerator->CreateEvaluationSourceFiles(c);
214
  }
Alexander Neundorf's avatar
 
Alexander Neundorf committed
215
  // Generate the rule files for each target.
216
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
217
218
  for (cmGeneratorTarget* target : targets) {
    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
219
      continue;
Alexander Neundorf's avatar
 
Alexander Neundorf committed
220
    }
221
    target->TraceDependencies();
222
  }
Alexander Neundorf's avatar
 
Alexander Neundorf committed
223
224
}

225
226
void cmLocalGenerator::GenerateTestFiles()
{
227
228
229
230
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
  file += "/";
  file += "CTestTestfile.cmake";

231
  if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
232
233
234
    if (cmSystemTools::FileExists(file)) {
      cmSystemTools::RemoveFile(file);
    }
235
    return;
236
  }
237
238
239

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

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

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

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

Matthew Woehlke's avatar
Matthew Woehlke committed
263
264
265
266
267
  const char* testIncludeFiles =
    this->Makefile->GetProperty("TEST_INCLUDE_FILES");
  if (testIncludeFiles) {
    std::vector<std::string> includesList;
    cmSystemTools::ExpandListArgument(testIncludeFiles, includesList);
268
269
    for (std::string const& i : includesList) {
      fout << "include(\"" << i << "\")" << std::endl;
Matthew Woehlke's avatar
Matthew Woehlke committed
270
271
272
    }
  }

273
  // Ask each test generator to write its code.
274
275
  std::vector<cmTestGenerator*> const& testers =
    this->Makefile->GetTestGenerators();
276
277
278
  for (cmTestGenerator* tester : testers) {
    tester->Compute(this);
    tester->Generate(fout, config, configurationTypes);
279
  }
280
  typedef std::vector<cmStateSnapshot> vec_t;
281
  vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
282
  std::string parentBinDir = this->GetCurrentBinaryDirectory();
283
  for (cmStateSnapshot const& i : children) {
284
    // TODO: Use add_subdirectory instead?
285
    std::string outP = i.GetDirectory().GetCurrentBinary();
286
    outP = this->ConvertToRelativePath(parentBinDir, outP);
287
    outP = cmOutputConverter::EscapeForCMake(outP);
288
    fout << "subdirs(" << outP << ")" << std::endl;
289
  }
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308

  // 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;
  }
309
310
}

311
312
313
void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
314
    this->Makefile->GetEvaluationFiles();
315
316
  for (cmGeneratorExpressionEvaluationFile* geef : ef) {
    geef->CreateOutputFile(this, config);
317
  }
318
319
320
}

void cmLocalGenerator::ProcessEvaluationFiles(
321
  std::vector<std::string>& generatedFiles)
322
323
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
324
    this->Makefile->GetEvaluationFiles();
325
326
  for (cmGeneratorExpressionEvaluationFile* geef : ef) {
    geef->Generate(this);
327
    if (cmSystemTools::GetFatalErrorOccured()) {
328
      return;
329
    }
330
    std::vector<std::string> files = geef->GetFiles();
331
332
333
    std::sort(files.begin(), files.end());

    std::vector<std::string> intersection;
334
335
    std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
                          generatedFiles.end(),
336
                          std::back_inserter(intersection));
337
    if (!intersection.empty()) {
338
      cmSystemTools::Error("Files to be generated by multiple different "
339
340
                           "commands: ",
                           cmWrap('"', intersection, '"', " ").c_str());
341
      return;
342
    }
343
344
345

    generatedFiles.insert(generatedFiles.end(), files.begin(), files.end());
    std::vector<std::string>::iterator newIt =
346
      generatedFiles.end() - files.size();
347
    std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
348
  }
349
350
}

351
352
void cmLocalGenerator::GenerateInstallRules()
{
353
  // Compute the install prefix.
Ken Martin's avatar
Ken Martin committed
354
  const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
355

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

391
392
  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
393
  const std::string& config =
394
    this->Makefile->GetConfigurations(configurationTypes, false);
395

396
  // Choose a default install configuration.
397
  std::string default_config = config;
398
  const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
Daniel Pfeifer's avatar
Daniel Pfeifer committed
399
                                  "DEBUG", nullptr };
400
  for (const char** c = default_order; *c && default_config.empty(); ++c) {
401
402
403
    for (std::string const& configurationType : configurationTypes) {
      if (cmSystemTools::UpperCase(configurationType) == *c) {
        default_config = configurationType;
404
405
      }
    }
406
407
  }
  if (default_config.empty() && !configurationTypes.empty()) {
408
    default_config = configurationTypes[0];
409
  }
410

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

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

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

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

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

479
480
481
482
483
484
485
486
487
488
489
490
491
  // 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 */
  }

492
493
494
495
496
497
498
499
500
501
502
503
504
505
  // 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 */
  }

506
507
  // Ask each install generator to write its code.
  std::vector<cmInstallGenerator*> const& installers =
Ken Martin's avatar
Ken Martin committed
508
    this->Makefile->GetInstallGenerators();
509
510
  for (cmInstallGenerator* installer : installers) {
    installer->Generate(fout, config, configurationTypes);
511
  }
512

513
514
  // Write rules from old-style specification stored in targets.
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
515

516
  // Include install scripts from subdirectories.
517
  std::vector<cmStateSnapshot> children =
518
519
    this->Makefile->GetStateSnapshot().GetChildren();
  if (!children.empty()) {
520
    fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
521
    fout << "  # Include the install script for each subdirectory.\n";
522
523
524
    for (cmStateSnapshot const& c : children) {
      if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
        std::string odir = c.GetDirectory().GetCurrentBinary();
525
        cmSystemTools::ConvertToUnixSlashes(odir);
526
527
        fout << "  include(\"" << odir << "/cmake_install.cmake\")"
             << std::endl;
528
      }
529
    }
530
    fout << "\n";
531
    fout << "endif()\n\n";
532
  }
533
534

  // Record the install manifest.
535
  if (toplevel_install) {
536
    /* clang-format off */
537
    fout <<
538
539
      "if(CMAKE_INSTALL_COMPONENT)\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
540
      "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
541
542
      "else()\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
543
544
545
546
547
548
      "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";
549
    /* clang-format on */
550
  }
551
552
}

553
void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt)
554
{
555
  this->GeneratorTargets.push_back(gt);
556
557
  this->GeneratorTargetSearchIndex.insert(
    std::pair<std::string, cmGeneratorTarget*>(gt->GetName(), gt));
558
  this->GlobalGenerator->IndexGeneratorTarget(gt);
559
560
}

561
562
563
void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
{
  this->ImportedGeneratorTargets.push_back(gt);
564
  this->GlobalGenerator->IndexGeneratorTarget(gt);
565
566
}

567
568
569
570
571
void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt)
{
  this->OwnedImportedGeneratorTargets.push_back(gt);
}

572
573
574
575
576
577
578
579
580
581
582
struct NamedGeneratorTargetFinder
{
  NamedGeneratorTargetFinder(std::string const& name)
    : Name(name)
  {
  }

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

584
585
586
587
private:
  std::string Name;
};

588
cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
589
  const std::string& name) const
590
{
591
592
593
594
  GeneratorTargetMap::const_iterator ti =
    this->GeneratorTargetSearchIndex.find(name);
  if (ti != this->GeneratorTargetSearchIndex.end()) {
    return ti->second;
595
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
596
  return nullptr;
597
598
}

599
void cmLocalGenerator::ComputeTargetManifest()
600
601
602
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
603
  this->Makefile->GetConfigurations(configNames);
604
  if (configNames.empty()) {
605
    configNames.emplace_back();
606
  }
607
608

  // Add our targets to the manifest for each configuration.
609
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
610
  for (cmGeneratorTarget* target : targets) {
611
    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
612
      continue;
613
    }
614
615
    for (std::string const& c : configNames) {
      target->ComputeTargetManifest(c);
616
    }
617
  }
618
619
}

620
621
622
623
624
625
bool cmLocalGenerator::ComputeTargetCompileFeatures()
{
  // Collect the set of configuration types.
  std::vector<std::string> configNames;
  this->Makefile->GetConfigurations(configNames);
  if (configNames.empty()) {
626
    configNames.emplace_back();
627
628
629
  }

  // Process compile features of all targets.
630
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
631
632
633
  for (cmGeneratorTarget* target : targets) {
    for (std::string const& c : configNames) {
      if (!target->ComputeCompileFeatures(c)) {
634
635
636
637
638
639
640
641
        return false;
      }
    }
  }

  return true;
}

642
643
644
645
646
bool cmLocalGenerator::IsRootMakefile() const
{
  return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
}

647
648
649
650
651
cmState* cmLocalGenerator::GetState() const
{
  return this->GlobalGenerator->GetCMakeInstance()->GetState();
}

652
cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
653
{
654
  return this->Makefile->GetStateSnapshot();
655
656
}

657
const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
658
                                              const std::string& prop)
659
{
660
  if (target) {
661
    return target->GetProperty(prop);
662
  }
663
  return this->Makefile->GetProperty(prop);
664
665
}

666
667
std::string cmLocalGenerator::ConvertToIncludeReference(
  std::string const& path, OutputFormat format, bool forceFullPaths)
668
{
669
670
  static_cast<void>(forceFullPaths);
  return this->ConvertToOutputForExisting(path, format);
671
672
}

673
std::string cmLocalGenerator::GetIncludeFlags(
674
675
676
677
678
  const std::vector<std::string>& includes, cmGeneratorTarget* target,
  const std::string& lang, bool forceFullPaths, bool forResponseFile,
  const std::string& config)
{
  if (lang.empty()) {
679
    return "";
680
  }
681

682
  OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
683
  std::ostringstream includeFlags;
684
685
686

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

  // 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
709
  const char* sysIncludeFlag = nullptr;
710
  if (repeatFlag) {
Stephen Kelly's avatar
Stephen Kelly committed
711
    sysIncludeFlag = this->Makefile->GetDefinition(sysFlagVar);
712
  }
713

714
715
716
  std::string fwSearchFlagVar = "CMAKE_";
  fwSearchFlagVar += lang;
  fwSearchFlagVar += "_FRAMEWORK_SEARCH_FLAG";
717
  const char* fwSearchFlag = this->Makefile->GetDefinition(fwSearchFlagVar);
718

719
720
721
722
723
724
  std::string sysFwSearchFlagVar = "CMAKE_";
  sysFwSearchFlagVar += lang;
  sysFwSearchFlagVar += "_SYSTEM_FRAMEWORK_SEARCH_FLAG";
  const char* sysFwSearchFlag =
    this->Makefile->GetDefinition(sysFwSearchFlagVar);

725
  bool flagUsed = false;
726
  std::set<std::string> emitted;
727
728
729
#ifdef __APPLE__
  emitted.insert("/System/Library/Frameworks");
#endif
730
  for (std::string const& i : includes) {
731
    if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
732
733
        cmSystemTools::IsPathToFramework(i.c_str())) {
      std::string frameworkDir = i;
734
      frameworkDir += "/../";
735
      frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
736
      if (emitted.insert(frameworkDir).second) {
737
        if (sysFwSearchFlag && target &&
738
            target->IsSystemIncludeDirectory(i, config)) {
739
          includeFlags << sysFwSearchFlag;
740
        } else {
741
          includeFlags << fwSearchFlag;
742
        }
743
744
        includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat)
                     << " ";
745
      }
746
747
      continue;
    }
748

749
750
    if (!flagUsed || repeatFlag) {
      if (sysIncludeFlag && target &&
751
          target->IsSystemIncludeDirectory(i, config)) {
752
        includeFlags << sysIncludeFlag;
753
      } else {
754
        includeFlags << includeFlag;
755
      }
756
757
      flagUsed = true;
    }
758
    std::string includePath =
759
      this->ConvertToIncludeReference(i, shellFormat, forceFullPaths);
760
    if (quotePaths && !includePath.empty() && includePath[0] != '\"') {
761
      includeFlags << "\"";
762
    }
763
    includeFlags << includePath;
764
    if (quotePaths && !includePath.empty() && includePath[0] != '\"') {
765
      includeFlags << "\"";
766
    }
767
768
    includeFlags << sep;
  }
769
770
  std::string flags = includeFlags.str();
  // remove trailing separators
771
772
773
  if ((sep[0] != ' ') && !flags.empty() && flags[flags.size() - 1] == sep[0]) {
    flags[flags.size() - 1] = ' ';
  }
774
  return flags;
775
776
}

777
void cmLocalGenerator::AddCompileDefinitions(std::set<std::string>& defines,
778
                                             cmGeneratorTarget const* target,
779
                                             const std::string& config,
780
                                             const std::string& lang) const
781
782
{
  std::vector<std::string> targetDefines;
783
  target->GetCompileDefinitions(targetDefines, config, lang);
784
785
786
  this->AppendDefines(defines, targetDefines);
}

787
788
789
790
void cmLocalGenerator::AddCompileOptions(std::string& flags