cmLocalGenerator.cxx 90.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
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
}

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

Alexander Neundorf's avatar
 
Alexander Neundorf committed
221
222
void cmLocalGenerator::TraceDependencies()
{
223
224
  std::vector<std::string> configs;
  this->Makefile->GetConfigurations(configs);
225
  if (configs.empty()) {
226
    configs.emplace_back();
227
  }
228
229
  for (std::string const& c : configs) {
    this->GlobalGenerator->CreateEvaluationSourceFiles(c);
230
  }
Alexander Neundorf's avatar
 
Alexander Neundorf committed
231
  // Generate the rule files for each target.
232
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
233
234
  for (cmGeneratorTarget* target : targets) {
    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
235
      continue;
Alexander Neundorf's avatar
 
Alexander Neundorf committed
236
    }
237
    target->TraceDependencies();
238
  }
Alexander Neundorf's avatar
 
Alexander Neundorf committed
239
240
}

241
242
void cmLocalGenerator::GenerateTestFiles()
{
243
  if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
244
    return;
245
  }
246
247
248

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

252
253
254
255
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
  file += "/";
  file += "CTestTestfile.cmake";

256
257
258
259
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);

  fout << "# CMake generated Testfile for " << std::endl
260
       << "# Source directory: "
261
       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
262
       << "# Build directory: "
263
       << this->StateSnapshot.GetDirectory().GetCurrentBinary() << std::endl
Ken Martin's avatar
Ken Martin committed
264
       << "# " << std::endl
265
       << "# This file includes the relevant testing commands "
Ken Martin's avatar
Ken Martin committed
266
267
268
       << "required for " << std::endl
       << "# testing this directory and lists subdirectories to "
       << "be tested as well." << std::endl;
269
270

  const char* testIncludeFile =
Ken Martin's avatar
Ken Martin committed
271
    this->Makefile->GetProperty("TEST_INCLUDE_FILE");
272
  if (testIncludeFile) {
273
    fout << "include(\"" << testIncludeFile << "\")" << std::endl;
274
  }
275

Matthew Woehlke's avatar
Matthew Woehlke committed
276
277
278
279
280
  const char* testIncludeFiles =
    this->Makefile->GetProperty("TEST_INCLUDE_FILES");
  if (testIncludeFiles) {
    std::vector<std::string> includesList;
    cmSystemTools::ExpandListArgument(testIncludeFiles, includesList);
281
282
    for (std::string const& i : includesList) {
      fout << "include(\"" << i << "\")" << std::endl;
Matthew Woehlke's avatar
Matthew Woehlke committed
283
284
285
    }
  }

286
  // Ask each test generator to write its code.
287
288
  std::vector<cmTestGenerator*> const& testers =
    this->Makefile->GetTestGenerators();
289
290
291
  for (cmTestGenerator* tester : testers) {
    tester->Compute(this);
    tester->Generate(fout, config, configurationTypes);
292
  }
293
  typedef std::vector<cmStateSnapshot> vec_t;
294
  vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
295
  std::string parentBinDir = this->GetCurrentBinaryDirectory();
296
  for (cmStateSnapshot const& i : children) {
297
    // TODO: Use add_subdirectory instead?
298
    std::string outP = i.GetDirectory().GetCurrentBinary();
299
    outP = this->ConvertToRelativePath(parentBinDir, outP);
300
    outP = cmOutputConverter::EscapeForCMake(outP);
301
    fout << "subdirs(" << outP << ")" << std::endl;
302
  }
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321

  // 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;
  }
322
323
}

324
325
326
void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
327
    this->Makefile->GetEvaluationFiles();
328
329
  for (cmGeneratorExpressionEvaluationFile* geef : ef) {
    geef->CreateOutputFile(this, config);
330
  }
331
332
333
}

void cmLocalGenerator::ProcessEvaluationFiles(
334
  std::vector<std::string>& generatedFiles)
335
336
{
  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
337
    this->Makefile->GetEvaluationFiles();
338
339
  for (cmGeneratorExpressionEvaluationFile* geef : ef) {
    geef->Generate(this);
340
    if (cmSystemTools::GetFatalErrorOccured()) {
341
      return;
342
    }
343
    std::vector<std::string> files = geef->GetFiles();
344
345
346
    std::sort(files.begin(), files.end());

    std::vector<std::string> intersection;
347
348
    std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
                          generatedFiles.end(),
349
                          std::back_inserter(intersection));
350
    if (!intersection.empty()) {
351
      cmSystemTools::Error("Files to be generated by multiple different "
352
353
                           "commands: ",
                           cmWrap('"', intersection, '"', " ").c_str());
354
      return;
355
    }
356
357
358

    generatedFiles.insert(generatedFiles.end(), files.begin(), files.end());
    std::vector<std::string>::iterator newIt =
359
      generatedFiles.end() - files.size();
360
    std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
361
  }
362
363
}

364
365
void cmLocalGenerator::GenerateInstallRules()
{
366
  // Compute the install prefix.
Ken Martin's avatar
Ken Martin committed
367
  const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
368

369
370
#if defined(_WIN32) && !defined(__CYGWIN__)
  std::string prefix_win32;
371
372
  if (!prefix) {
    if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
373
      prefix_win32 = "C:";
374
    }
Ken Martin's avatar
Ken Martin committed
375
    const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME");
376
    if (project_name && project_name[0]) {
377
378
      prefix_win32 += "/Program Files/";
      prefix_win32 += project_name;
379
    } else {
380
381
      prefix_win32 += "/InstalledCMakeProject";
    }
382
383
    prefix = prefix_win32.c_str();
  }
384
#elif defined(__HAIKU__)
385
  char dir[B_PATH_NAME_LENGTH];
386
387
388
  if (!prefix) {
    if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
        B_OK) {
389
      prefix = dir;
390
    } else {
391
      prefix = "/boot/system";
392
    }
393
  }
394
#else
395
  if (!prefix) {
396
    prefix = "/usr/local";
397
  }
398
#endif
399
400
  if (const char* stagingPrefix =
        this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
401
    prefix = stagingPrefix;
402
  }
403

404
405
  // Compute the set of configurations.
  std::vector<std::string> configurationTypes;
406
  const std::string& config =
407
    this->Makefile->GetConfigurations(configurationTypes, false);
408

409
  // Choose a default install configuration.
410
  std::string default_config = config;
411
  const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
Daniel Pfeifer's avatar
Daniel Pfeifer committed
412
                                  "DEBUG", nullptr };
413
  for (const char** c = default_order; *c && default_config.empty(); ++c) {
414
415
416
    for (std::string const& configurationType : configurationTypes) {
      if (cmSystemTools::UpperCase(configurationType) == *c) {
        default_config = configurationType;
417
418
      }
    }
419
420
  }
  if (default_config.empty() && !configurationTypes.empty()) {
421
    default_config = configurationTypes[0];
422
  }
423

424
  // Create the install script file.
425
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
426
  std::string homedir = this->GetState()->GetBinaryDirectory();
427
  int toplevel_install = 0;
428
  if (file == homedir) {
429
    toplevel_install = 1;
430
  }
431
  file += "/cmake_install.cmake";
432
433
  cmGeneratedFileStream fout(file.c_str());
  fout.SetCopyIfDifferent(true);
434

435
436
  // Write the header.
  fout << "# Install script for directory: "
437
438
       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
       << std::endl;
Ken Martin's avatar
Ken Martin committed
439
  fout << "# Set the install prefix" << std::endl
440
441
442
443
       << "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
444
445
       << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
       << std::endl;
446

447
  // Write support code for generating per-configuration install rules.
448
  /* clang-format off */
449
450
  fout <<
    "# Set the install configuration name.\n"
451
452
453
    "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
    "  if(BUILD_TYPE)\n"
    "    string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
454
    "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
455
456
457
458
    "  else()\n"
    "    set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
    "  endif()\n"
    "  message(STATUS \"Install configuration: "
Ken Martin's avatar
Ken Martin committed
459
    "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
460
    "endif()\n"
461
    "\n";
462
  /* clang-format on */
463

464
  // Write support code for dealing with component-specific installs.
465
  /* clang-format off */
466
467
  fout <<
    "# Set the component getting installed.\n"
468
469
470
471
472
473
474
475
    "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"
476
    "\n";
477
  /* clang-format on */
478

479
  // Copy user-specified install options to the install code.
480
481
  if (const char* so_no_exe =
        this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
482
    /* clang-format off */
483
484
    fout <<
      "# Install shared libraries without execute permission?\n"
485
486
487
      "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
      "  set(CMAKE_INSTALL_SO_NO_EXE \"" << so_no_exe << "\")\n"
      "endif()\n"
488
      "\n";
489
    /* clang-format on */
490
  }
491

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

505
506
507
508
509
510
511
512
513
514
515
516
517
518
  // 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 */
  }

519
520
  // Ask each install generator to write its code.
  std::vector<cmInstallGenerator*> const& installers =
Ken Martin's avatar
Ken Martin committed
521
    this->Makefile->GetInstallGenerators();
522
523
  for (cmInstallGenerator* installer : installers) {
    installer->Generate(fout, config, configurationTypes);
524
  }
525

526
527
  // Write rules from old-style specification stored in targets.
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
528

529
  // Include install scripts from subdirectories.
530
  std::vector<cmStateSnapshot> children =
531
532
    this->Makefile->GetStateSnapshot().GetChildren();
  if (!children.empty()) {
533
    fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
534
    fout << "  # Include the install script for each subdirectory.\n";
535
536
537
    for (cmStateSnapshot const& c : children) {
      if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
        std::string odir = c.GetDirectory().GetCurrentBinary();
538
        cmSystemTools::ConvertToUnixSlashes(odir);
539
540
        fout << "  include(\"" << odir << "/cmake_install.cmake\")"
             << std::endl;
541
      }
542
    }
543
    fout << "\n";
544
    fout << "endif()\n\n";
545
  }
546
547

  // Record the install manifest.
548
  if (toplevel_install) {
549
    /* clang-format off */
550
    fout <<
551
552
      "if(CMAKE_INSTALL_COMPONENT)\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
553
      "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
554
555
      "else()\n"
      "  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
556
557
558
559
560
561
      "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";
562
    /* clang-format on */
563
  }
564
565
}

566
void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt)
567
{
568
  this->GeneratorTargets.push_back(gt);
569
  this->GeneratorTargetSearchIndex.emplace(gt->GetName(), gt);
570
  this->GlobalGenerator->IndexGeneratorTarget(gt);
571
572
}

573
574
void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
{
575
  this->ImportedGeneratorTargets.emplace(gt->GetName(), gt);
576
  this->GlobalGenerator->IndexGeneratorTarget(gt);
577
578
}

579
580
581
582
583
void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt)
{
  this->OwnedImportedGeneratorTargets.push_back(gt);
}

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

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

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

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

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

  return true;
}

638
639
640
641
642
bool cmLocalGenerator::IsRootMakefile() const
{
  return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
}

643
644
645
646
647
cmState* cmLocalGenerator::GetState() const
{
  return this->GlobalGenerator->GetCMakeInstance()->GetState();
}

648
cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
649
{
650
  return this->Makefile->GetStateSnapshot();
651
652
}

653
const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
654
                                              const std::string& prop)
655
{
656
  if (target) {
657
    return target->GetProperty(prop);
658
  }
659
  return this->Makefile->GetProperty(prop);
660
661
}

662
663
std::string cmLocalGenerator::ConvertToIncludeReference(
  std::string const& path, OutputFormat format, bool forceFullPaths)
664
{
665
666
  static_cast<void>(forceFullPaths);
  return this->ConvertToOutputForExisting(path, format);
667
668
}

669
std::string cmLocalGenerator::GetIncludeFlags(
670
  const std::vector<std::string>& includeDirs, cmGeneratorTarget* target,
671
672
673
674
  const std::string& lang, bool forceFullPaths, bool forResponseFile,
  const std::string& config)
{
  if (lang.empty()) {
675
    return "";
676
  }
677

678
679
680
  std::vector<std::string> includes = includeDirs;
  this->MoveSystemIncludesToEnd(includes, config, lang, target);

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

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

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

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

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

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

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

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

786
787
788
789
void cmLocalGenerator::AddCompileOptions(std::string& <