cmMakefile.cxx 148 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.  */
3
#include "cmMakefile.h"
Brad King's avatar
Brad King committed
4

5
6
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
7
8
9
10
11
12
13
14
#include <algorithm>
#include <assert.h>
#include <ctype.h>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <utility>

15
#include "cmAlgorithms.h"
16
#include "cmCommand.h"
17
#include "cmCommandArgumentParserHelper.h"
18
19
20
21
22
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmExecutionStatus.h"
#include "cmExpandedCommandArgument.h"
#include "cmFileLockPool.h"
23
#include "cmFunctionBlocker.h"
24
#include "cmGeneratorExpression.h"
25
#include "cmGeneratorExpressionEvaluationFile.h"
26
#include "cmGlobalGenerator.h"
27
#include "cmInstallGenerator.h" // IWYU pragma: keep
28
#include "cmListFileCache.h"
29
30
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
31
32
#include "cmState.h"
#include "cmStateDirectory.h"
33
#include "cmStateTypes.h"
34
#include "cmSystemTools.h"
35
#include "cmTargetLinkLibraryType.h"
36
#include "cmTest.h"
37
#include "cmTestGenerator.h" // IWYU pragma: keep
38
#include "cmVersion.h"
39
#include "cmWorkingDirectory.h"
40
#include "cm_auto_ptr.hxx"
41
#include "cm_sys_stat.h"
42
43
#include "cmake.h"

44
#ifdef CMAKE_BUILD_WITH_CMAKE
45
#include "cmVariableWatch.h"
46
#endif
47

48
49
class cmMessenger;

50
// default is not to be building executables
51
cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
52
                       cmStateSnapshot const& snapshot)
53
54
55
  : GlobalGenerator(globalGenerator)
  , StateSnapshot(snapshot)
  , Backtrace(snapshot)
56
{
57
  this->IsSourceFileTryCompile = false;
58

59
60
  this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
  this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
61

62
63
  this->SuppressWatches = false;

64
  // Setup the default include complaint regular expression (match nothing).
Ken Martin's avatar
Ken Martin committed
65
  this->ComplainFileRegularExpression = "^$";
Alexander Neundorf's avatar
   
Alexander Neundorf committed
66

Ken Martin's avatar
Ken Martin committed
67
  this->DefineFlags = " ";
68

69
70
71
  this->cmDefineRegex.compile("#cmakedefine[ \t]+([A-Za-z_0-9]*)");
  this->cmDefine01Regex.compile("#cmakedefine01[ \t]+([A-Za-z_0-9]*)");
  this->cmAtVarRegex.compile("(@[A-Za-z_0-9/.+-]+@)");
72
  this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
73

74
75
76
  this->StateSnapshot =
    this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
      this->StateSnapshot);
77

78
79
  // Enter a policy level for this directory.
  this->PushPolicy();
80

81
82
83
  // push empty loop block
  this->PushLoopBlockBarrier();

84
85
86
  // By default the check is not done.  It is enabled by
  // cmListFileCache in the top level if necessary.
  this->CheckCMP0000 = false;
87
88
89

#if defined(CMAKE_BUILD_WITH_CMAKE)
  this->AddSourceGroup("", "^.*$");
90
91
92
  this->AddSourceGroup("Source Files",
                       "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|f|f90|for|fpp"
                       "|ftn|m|mm|rc|def|r|odl|idl|hpj|bat)$");
93
94
95
96
  this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
  this->AddSourceGroup("CMake Rules", "\\.rule$");
  this->AddSourceGroup("Resources", "\\.plist$");
  this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
97
98
99
100

  this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size();
  this->SourceGroups.push_back(
    cmSourceGroup("Object Libraries", "^MATCH_NO_SOURCES$"));
101
#endif
102
}
103

104
105
cmMakefile::~cmMakefile()
{
106
107
108
109
110
111
  cmDeleteAll(this->InstallGenerators);
  cmDeleteAll(this->TestGenerators);
  cmDeleteAll(this->SourceFiles);
  cmDeleteAll(this->Tests);
  cmDeleteAll(this->ImportedTargetsOwned);
  cmDeleteAll(this->FunctionBlockers);
112
  cmDeleteAll(this->EvaluationFiles);
113
114
}

115
116
void cmMakefile::IssueMessage(cmake::MessageType t,
                              std::string const& text) const
117
{
118
119
  if (!this->ExecutionStatusStack.empty()) {
    if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) {
120
      this->ExecutionStatusStack.back()->SetNestedError();
121
122
    }
  }
123
  this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace());
124
}
125

126
cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const
127
{
128
  return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
129
130
}

131
cmBacktraceRange cmMakefile::GetIncludeDirectoriesBacktraces() const
132
{
133
  return this->StateSnapshot.GetDirectory()
134
    .GetIncludeDirectoriesEntryBacktraces();
135
136
}

137
cmStringRange cmMakefile::GetCompileOptionsEntries() const
138
{
139
  return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
140
141
}

142
cmBacktraceRange cmMakefile::GetCompileOptionsBacktraces() const
143
{
144
  return this->StateSnapshot.GetDirectory().GetCompileOptionsEntryBacktraces();
145
146
}

147
cmStringRange cmMakefile::GetCompileDefinitionsEntries() const
148
{
149
  return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
150
151
}

152
cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const
153
{
154
  return this->StateSnapshot.GetDirectory()
155
    .GetCompileDefinitionsEntryBacktraces();
156
157
}

Ben Boeckel's avatar
Ben Boeckel committed
158
cmListFileBacktrace cmMakefile::GetBacktrace() const
159
{
160
  return this->Backtrace;
161
162
}

163
cmListFileBacktrace cmMakefile::GetBacktrace(cmCommandContext const& cc) const
164
{
165
166
167
168
169
  cmListFileContext lfc;
  lfc.Name = cc.Name;
  lfc.Line = cc.Line;
  lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
  return this->Backtrace.Push(lfc);
170
171
}

172
173
cmListFileContext cmMakefile::GetExecutionContext() const
{
174
175
176
177
178
179
  cmListFileContext const& cur = this->Backtrace.Top();
  cmListFileContext lfc;
  lfc.Name = cur.Name;
  lfc.Line = cur.Line;
  lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
  return lfc;
180
181
}

182
void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
183
{
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  // Check if current file in the list of requested to trace...
  std::vector<std::string> const& trace_only_this_files =
    this->GetCMakeInstance()->GetTraceSources();
  std::string const& full_path = this->GetExecutionFilePath();
  std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
  bool trace = trace_only_this_files.empty();
  if (!trace) {
    for (std::vector<std::string>::const_iterator i =
           trace_only_this_files.begin();
         !trace && i != trace_only_this_files.end(); ++i) {
      std::string::size_type const pos = full_path.rfind(*i);
      trace = (pos != std::string::npos) &&
        ((pos + i->size()) == full_path.size()) &&
        (only_filename == cmSystemTools::GetFilenameName(*i));
    }
    // Do nothing if current file wasn't requested for trace...
    if (!trace) {
      return;
    }
  }

205
  std::ostringstream msg;
206
  msg << full_path << "(" << lff.Line << "):  ";
207
  msg << lff.Name << "(";
Ben Boeckel's avatar
Ben Boeckel committed
208
209
  bool expand = this->GetCMakeInstance()->GetTraceExpand();
  std::string temp;
210
211
212
213
  for (std::vector<cmListFileArgument>::const_iterator i =
         lff.Arguments.begin();
       i != lff.Arguments.end(); ++i) {
    if (expand) {
Ben Boeckel's avatar
Ben Boeckel committed
214
215
216
      temp = i->Value;
      this->ExpandVariablesInString(temp);
      msg << temp;
217
    } else {
Ben Boeckel's avatar
Ben Boeckel committed
218
      msg << i->Value;
219
    }
220
221
    msg << " ";
  }
222
223
224
225
  msg << ")";
  cmSystemTools::Message(msg.str().c_str());
}

226
227
228
229
// Helper class to make sure the call stack is valid.
class cmMakefileCall
{
public:
230
  cmMakefileCall(cmMakefile* mf, cmCommandContext const& cc,
231
232
233
234
235
                 cmExecutionStatus& status)
    : Makefile(mf)
  {
    cmListFileContext const& lfc = cmListFileContext::FromCommandContext(
      cc, this->Makefile->StateSnapshot.GetExecutionListFile());
236
    this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
237
    this->Makefile->ExecutionStatusStack.push_back(&status);
238
  }
239
240

  ~cmMakefileCall()
241
  {
242
    this->Makefile->ExecutionStatusStack.pop_back();
243
    this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
244
245
  }

246
247
248
249
private:
  cmMakefile* Makefile;
};

250
bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
251
                                cmExecutionStatus& status)
Ken Martin's avatar
Ken Martin committed
252
{
253
  bool result = true;
254

255
  // quick return if blocked
256
  if (this->IsFunctionBlocked(lff, status)) {
257
258
    // No error.
    return result;
259
  }
260

Ken Martin's avatar
Ken Martin committed
261
  std::string name = lff.Name;
262

263
264
265
266
267
  // Place this call on the call stack.
  cmMakefileCall stack_manager(this, lff, status);
  static_cast<void>(stack_manager);

  // Lookup the command prototype.
268
  if (cmCommand* proto = this->GetState()->GetCommand(name)) {
269
    // Clone the prototype.
270
    CM_AUTO_PTR<cmCommand> pcmd(proto->Clone());
271
272
273
    pcmd->SetMakefile(this);

    // Decide whether to invoke the command.
274
    if (!cmSystemTools::GetFatalErrorOccured()) {
275
      // if trace is enabled, print out invoke information
276
      if (this->GetCMakeInstance()->GetTrace()) {
277
        this->PrintCommandTrace(lff);
278
      }
279
      // Try invoking the command.
280
      bool invokeSucceeded = pcmd->InvokeInitialPass(lff.Arguments, status);
281
      bool hadNestedError = status.GetNestedError();
282
      if (!invokeSucceeded || hadNestedError) {
283
        if (!hadNestedError) {
284
          // The command invocation requested that we report an error.
285
286
          std::string const error = name + " " + pcmd->GetError();
          this->IssueMessage(cmake::FATAL_ERROR, error);
287
        }
288
        result = false;
289
        if (this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE) {
290
          cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
291
292
293
        }
      }
    }
294
295
  } else {
    if (!cmSystemTools::GetFatalErrorOccured()) {
296
297
298
      std::string error = "Unknown CMake command \"";
      error += lff.Name;
      error += "\".";
Bill Hoffman's avatar
Bill Hoffman committed
299
      this->IssueMessage(cmake::FATAL_ERROR, error);
300
      result = false;
301
      cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
302
    }
303
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
304

305
  return result;
Ken Martin's avatar
Ken Martin committed
306
307
}

Brad King's avatar
Brad King committed
308
309
310
class cmMakefile::IncludeScope
{
public:
311
312
  IncludeScope(cmMakefile* mf, std::string const& filenametoread,
               bool noPolicyScope);
Brad King's avatar
Brad King committed
313
314
315
316
  ~IncludeScope();
  void Quiet() { this->ReportError = false; }
private:
  cmMakefile* Makefile;
317
318
  bool NoPolicyScope;
  bool CheckCMP0011;
Brad King's avatar
Brad King committed
319
  bool ReportError;
320
  void EnforceCMP0011();
Brad King's avatar
Brad King committed
321
322
};

323
cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
324
                                       std::string const& filenametoread,
325
326
327
328
329
                                       bool noPolicyScope)
  : Makefile(mf)
  , NoPolicyScope(noPolicyScope)
  , CheckCMP0011(false)
  , ReportError(true)
Brad King's avatar
Brad King committed
330
{
331
  this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
332

333
334
335
  this->Makefile->PushFunctionBlockerBarrier();

  this->Makefile->StateSnapshot =
336
337
338
    this->Makefile->GetState()->CreateIncludeFileSnapshot(
      this->Makefile->StateSnapshot, filenametoread);
  if (!this->NoPolicyScope) {
339
    // Check CMP0011 to determine the policy scope type.
340
    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
      case cmPolicies::WARN:
        // We need to push a scope to detect whether the script sets
        // any policies that would affect the includer and therefore
        // requires a warning.  We use a weak scope to simulate OLD
        // behavior by allowing policy changes to affect the includer.
        this->Makefile->PushPolicy(true);
        this->CheckCMP0011 = true;
        break;
      case cmPolicies::OLD:
        // OLD behavior is to not push a scope at all.
        this->NoPolicyScope = true;
        break;
      case cmPolicies::REQUIRED_IF_USED:
      case cmPolicies::REQUIRED_ALWAYS:
        // We should never make this policy required, but we handle it
        // here just in case.
        this->CheckCMP0011 = true;
      case cmPolicies::NEW:
        // NEW behavior is to push a (strong) scope.
        this->Makefile->PushPolicy();
        break;
    }
363
  }
Brad King's avatar
Brad King committed
364
365
366
367
}

cmMakefile::IncludeScope::~IncludeScope()
{
368
  if (!this->NoPolicyScope) {
369
370
371
372
    // If we need to enforce policy CMP0011 then the top entry is the
    // one we pushed above.  If the entry is empty, then the included
    // script did not set any policies that might affect the includer so
    // we do not need to enforce the policy.
373
374
    if (this->CheckCMP0011 &&
        !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) {
375
      this->CheckCMP0011 = false;
376
    }
377
378
379
380
381
382

    // Pop the scope we pushed for the script.
    this->Makefile->PopPolicy();

    // We enforce the policy after the script's policy stack entry has
    // been removed.
383
    if (this->CheckCMP0011) {
384
385
      this->EnforceCMP0011();
    }
386
  }
387
  this->Makefile->PopSnapshot(this->ReportError);
388
389

  this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
390
391

  this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
392
393
394
395
396
397
}

void cmMakefile::IncludeScope::EnforceCMP0011()
{
  // We check the setting of this policy again because the included
  // script might actually set this policy for its includer.
398
  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
399
400
401
    case cmPolicies::WARN:
      // Warn because the user did not set this policy.
      {
402
403
404
405
406
407
408
409
        std::ostringstream w;
        w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0011) << "\n"
          << "The included script\n  "
          << this->Makefile->GetExecutionFilePath() << "\n"
          << "affects policy settings.  "
          << "CMake is implying the NO_POLICY_SCOPE option for compatibility, "
          << "so the effects are applied to the including context.";
        this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
410
411
412
      }
      break;
    case cmPolicies::REQUIRED_IF_USED:
413
    case cmPolicies::REQUIRED_ALWAYS: {
414
      std::ostringstream e;
415
      /* clang-format off */
Stephen Kelly's avatar
Stephen Kelly committed
416
      e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
417
        << "The included script\n  "
418
        << this->Makefile->GetExecutionFilePath() << "\n"
419
        << "affects policy settings, so it requires this policy to be set.";
420
      /* clang-format on */
421
      this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
422
    } break;
423
424
425
426
427
428
    case cmPolicies::OLD:
    case cmPolicies::NEW:
      // The script set this policy.  We assume the purpose of the
      // script is to initialize policies for its includer, and since
      // the policy is now set for later scripts, we do not warn.
      break;
429
  }
Brad King's avatar
Brad King committed
430
431
}

Stephen Kelly's avatar
Stephen Kelly committed
432
bool cmMakefile::ReadDependentFile(const char* filename, bool noPolicyScope)
433
{
434
435
  this->AddDefinition("CMAKE_PARENT_LIST_FILE",
                      this->GetDefinition("CMAKE_CURRENT_LIST_FILE"));
436
437
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
438

439
  IncludeScope incScope(this, filenametoread, noPolicyScope);
440
441

  cmListFile listFile;
442
443
  if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
                          this->Backtrace)) {
444
    return false;
445
  }
446

447
  this->ReadListFile(listFile, filenametoread);
448
  if (cmSystemTools::GetFatalErrorOccured()) {
449
    incScope.Quiet();
450
  }
451
  return true;
452
453
}

454
455
456
class cmMakefile::ListFileScope
{
public:
457
  ListFileScope(cmMakefile* mf, std::string const& filenametoread)
458
459
    : Makefile(mf)
    , ReportError(true)
460
  {
461
    this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
462

463
    this->Makefile->StateSnapshot =
464
465
      this->Makefile->GetState()->CreateInlineListFileSnapshot(
        this->Makefile->StateSnapshot, filenametoread);
466
    assert(this->Makefile->StateSnapshot.IsValid());
467

468
    this->Makefile->PushFunctionBlockerBarrier();
469
470
471
472
  }

  ~ListFileScope()
  {
473
    this->Makefile->PopSnapshot(this->ReportError);
474
    this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
475
    this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
476
477
478
479
480
481
482
483
  }

  void Quiet() { this->ReportError = false; }
private:
  cmMakefile* Makefile;
  bool ReportError;
};

Stephen Kelly's avatar
Stephen Kelly committed
484
bool cmMakefile::ReadListFile(const char* filename)
485
{
486
487
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
488

489
  ListFileScope scope(this, filenametoread);
490
491

  cmListFile listFile;
492
493
  if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
                          this->Backtrace)) {
494
    return false;
495
  }
496

497
  this->ReadListFile(listFile, filenametoread);
498
  if (cmSystemTools::GetFatalErrorOccured()) {
499
    scope.Quiet();
500
  }
501
  return true;
502
503
}

504
505
void cmMakefile::ReadListFile(cmListFile const& listFile,
                              std::string const& filenametoread)
506
{
507
508
  // add this list file to the list of dependencies
  this->ListFiles.push_back(filenametoread);
509

510
511
512
  std::string currentParentFile =
    this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
  std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
513

514
515
  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread.c_str());
  this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
516
                      cmSystemTools::GetFilenamePath(filenametoread).c_str());
517

518
  this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
519
520
521
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");

522
  // Run the parsed commands.
Stephen Kelly's avatar
Stephen Kelly committed
523
  const size_t numberFunctions = listFile.Functions.size();
524
  for (size_t i = 0; i < numberFunctions; ++i) {
525
    cmExecutionStatus status;
526
527
    this->ExecuteCommand(listFile.Functions[i], status);
    if (cmSystemTools::GetFatalErrorOccured()) {
528
      break;
529
530
    }
    if (status.GetReturnInvoked()) {
531
      // Exit early due to return command.
532
      break;
533
    }
534
  }
535
  this->CheckForUnusedVariables();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
536

537
538
539
540
541
542
543
  this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str());
  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str());
  this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
                      cmSystemTools::GetFilenamePath(currentFile).c_str());
  this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
544
}
545

546
void cmMakefile::EnforceDirectoryLevelRules() const
547
548
{
  // Diagnose a violation of CMP0000 if necessary.
549
  if (this->CheckCMP0000) {
550
    std::ostringstream msg;
551
552
    msg << "No cmake_minimum_required command is present.  "
        << "A line of code such as\n"
553
554
        << "  cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion()
        << "." << cmVersion::GetMinorVersion() << ")\n"
555
556
557
558
559
        << "should be added at the top of the file.  "
        << "The version specified may be lower if you wish to "
        << "support older CMake versions for this project.  "
        << "For more information run "
        << "\"cmake --help-policy CMP0000\".";
560
    switch (this->GetPolicyStatus(cmPolicies::CMP0000)) {
561
562
563
      case cmPolicies::WARN:
        // Warn because the user did not provide a mimimum required
        // version.
564
565
        this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING,
                                               msg.str(), this->Backtrace);
566
567
568
569
570
571
572
573
      case cmPolicies::OLD:
        // OLD behavior is to use policy version 2.4 set in
        // cmListFileCache.
        break;
      case cmPolicies::REQUIRED_IF_USED:
      case cmPolicies::REQUIRED_ALWAYS:
      case cmPolicies::NEW:
        // NEW behavior is to issue an error.
574
575
        this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, msg.str(),
                                               this->Backtrace);
576
577
578
        cmSystemTools::SetFatalErrorOccured();
        return;
    }
579
  }
580
}
581

582
583
void cmMakefile::AddEvaluationFile(
  const std::string& inputFile,
584
585
  CM_AUTO_PTR<cmCompiledGeneratorExpression> outputName,
  CM_AUTO_PTR<cmCompiledGeneratorExpression> condition, bool inputIsContent)
586
{
587
588
  this->EvaluationFiles.push_back(new cmGeneratorExpressionEvaluationFile(
    inputFile, outputName, condition, inputIsContent));
589
590
591
592
593
594
595
596
}

std::vector<cmGeneratorExpressionEvaluationFile*>
cmMakefile::GetEvaluationFiles() const
{
  return this->EvaluationFiles;
}

597
598
599
600
601
602
603
std::vector<cmExportBuildFileGenerator*>
cmMakefile::GetExportBuildFileGenerators() const
{
  return this->ExportBuildFileGenerators;
}

void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
604
  cmExportBuildFileGenerator* gen)
605
606
{
  std::vector<cmExportBuildFileGenerator*>::iterator it =
607
608
609
    std::find(this->ExportBuildFileGenerators.begin(),
              this->ExportBuildFileGenerators.end(), gen);
  if (it != this->ExportBuildFileGenerators.end()) {
610
    this->ExportBuildFileGenerators.erase(it);
611
  }
612
613
614
615
616
617
618
}

void cmMakefile::AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen)
{
  this->ExportBuildFileGenerators.push_back(gen);
}

619
620
namespace {
struct file_not_persistent
621
{
622
  bool operator()(const std::string& path) const
623
  {
624
625
626
627
    return !(path.find("CMakeTmp") == path.npos &&
             cmSystemTools::FileExists(path.c_str()));
  }
};
628
629
}

630
631
632
633
634
void cmMakefile::AddFinalAction(FinalAction action)
{
  this->FinalActions.push_back(std::move(action));
}

635
void cmMakefile::FinalPass()
636
637
{
  // do all the variable expansions here
638
  this->ExpandVariablesCMP0019();
639

640
  // give all the commands a chance to do something
641
  // after the file has been parsed before generation
642
643
  for (FinalAction& action : this->FinalActions) {
    action(*this);
644
  }
645

646
647
648
649
  // go through all configured files and see which ones still exist.
  // we don't want cmake to re-run if a configured file is created and deleted
  // during processing as that would make it a transient file that can't
  // influence the build process
650
  cmEraseIf(this->OutputFiles, file_not_persistent());
651
652
653
654

  // if a configured file is used as input for another configured file,
  // and then deleted it will show up in the input list files so we
  // need to scan those too
655
  cmEraseIf(this->ListFiles, file_not_persistent());
656
657
}

Bill Hoffman's avatar
Bill Hoffman committed
658
// Generate the output file
659
void cmMakefile::ConfigureFinalPass()
660
661
{
  this->FinalPass();
662
663
664
  const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
  if (oldValue &&
      cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
665
    this->GetCMakeInstance()->IssueMessage(
666
667
668
669
      cmake::FATAL_ERROR,
      "You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less "
      "than 2.4. This version of CMake only supports backwards compatibility "
      "with CMake 2.4 or later. For compatibility with older versions please "
670
671
      "use any CMake 2.8.x release or lower.",
      this->Backtrace);
672
  }
673
674
}

675
676
677
678
679
void cmMakefile::AddCustomCommandToTarget(
  const std::string& target, const std::vector<std::string>& byproducts,
  const std::vector<std::string>& depends,
  const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
  const char* comment, const char* workingDir, bool escapeOldStyle,
680
681
  bool uses_terminal, const std::string& depfile, bool command_expand_lists,
  ObjectLibraryCommands objLibraryCommands)
682
{
683
  // Find the target to which to add the custom command.
Ken Martin's avatar
Ken Martin committed
684
  cmTargets::iterator ti = this->Targets.find(target);
685

686
  if (ti == this->Targets.end()) {
687
688
    cmake::MessageType messageType = cmake::AUTHOR_WARNING;
    bool issueMessage = false;
689
    std::ostringstream e;
690
    switch (this->GetPolicyStatus(cmPolicies::CMP0040)) {
691
      case cmPolicies::WARN:
Stephen Kelly's avatar
Stephen Kelly committed
692
        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0040) << "\n";
693
694
695
696
697
698
699
700
        issueMessage = true;
      case cmPolicies::OLD:
        break;
      case cmPolicies::NEW:
      case cmPolicies::REQUIRED_IF_USED:
      case cmPolicies::REQUIRED_ALWAYS:
        issueMessage = true;
        messageType = cmake::FATAL_ERROR;
701
    }
702

703
704
705
    if (issueMessage) {
      if (cmTarget const* t = this->FindTargetToUse(target)) {
        if (t->IsImported()) {
706
707
          e << "TARGET '" << target
            << "' is IMPORTED and does not build here.";
708
709
        } else {
          e << "TARGET '" << target << "' was not created in this directory.";
710
        }
711
      } else {
712
713
        e << "No TARGET '" << target
          << "' has been created in this directory.";
714
      }
715
      IssueMessage(messageType, e.str());
716
717
    }

718
719
720
    return;
  }

721
722
  if (objLibraryCommands == RejectObjectLibraryCommands &&
      ti->second.GetType() == cmStateEnums::OBJECT_LIBRARY) {
723
    std::ostringstream e;
724
725
726
    e << "Target \"" << target
      << "\" is an OBJECT library "
         "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
727
728
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
729
  }
730
  if (ti->second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
731
    std::ostringstream e;
732
733
734
    e << "Target \"" << target
      << "\" is an INTERFACE library "
         "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
735
736
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
737
  }
738
739

  // Always create the byproduct sources and mark them generated.
740
741
742
  for (std::vector<std::string>::const_iterator o = byproducts.begin();
       o != byproducts.end(); ++o) {
    if (cmSourceFile* out = this->GetOrCreateSource(*o, true)) {
743
744
      out->SetProperty("GENERATED", "1");
    }
745
  }
746

747
748
  // Add the command to the appropriate build step for the target.
  std::vector<std::string> no_output;
749
750
  cmCustomCommand cc(this, no_output, byproducts, depends, commandLines,
                     comment, workingDir);
751
752
  cc.SetEscapeOldStyle(escapeOldStyle);
  cc.SetEscapeAllowMakeVars(true);
753
  cc.SetUsesTerminal(uses_terminal);
754
  cc.SetCommandExpandLists(command_expand_lists);
755
  cc.SetDepfile(depfile);
756
  switch (type) {
757
758
759
760
761
762
763
764
765
    case cmTarget::PRE_BUILD:
      ti->second.AddPreBuildCommand(cc);
      break;
    case cmTarget::PRE_LINK:
      ti->second.AddPreLinkCommand(cc);
      break;
    case cmTarget::POST_BUILD:
      ti->second.AddPostBuildCommand(cc);
      break;
766
  }
767
768
}

769
770
771
772
773
774
cmSourceFile* cmMakefile::AddCustomCommandToOutput(
  const std::vector<std::string>& outputs,
  const std::vector<std::string>& byproducts,
  const std::vector<std::string>& depends, const std::string& main_dependency,
  const cmCustomCommandLines& commandLines, const char* comment,
  const char* workingDir, bool replace, bool escapeOldStyle,
775
  bool uses_terminal, bool command_expand_lists, const std::string& depfile)
776
{
777
  // Make sure there is at least one output.
778
  if (outputs.empty()) {
779
    cmSystemTools::Error("Attempt to add a custom rule with no output!");
Daniel Pfeifer's avatar
Daniel Pfeifer committed
780
    return CM_NULLPTR;
781
  }
782

783
  // Validate custom commands.  TODO: More strict?
784
785
  for (cmCustomCommandLines::const_iterator i = commandLines.begin();
       i != commandLines.end(); ++i) {
786
    cmCustomCommandLine const& cl = *i;
787
    if (!cl.empty() && !cl[0].empty() && cl[0][0] == '"') {
788
      std::ostringstream e;
789
790
      e << "COMMAND may not contain literal quotes:\n  " << cl[0] << "\n";
      this->IssueMessage(cmake::FATAL_ERROR, e.str());
Daniel Pfeifer's avatar
Daniel Pfeifer committed
791
      return CM_NULLPTR;
792
    }
793
  }
794

795
  // Choose a source file on which to store the custom command.
Daniel Pfeifer's avatar
Daniel Pfeifer committed
796
  cmSourceFile* file = CM_NULLPTR;
797
  if (!commandLines.empty() && !main_dependency.empty()) {
798
799
800
    // The main dependency was specified.  Use it unless a different
    // custom command already used it.
    file = this->GetSource(main_dependency);
801
    if (file && file->GetCustomCommand() && !replace) {
802
      // The main dependency already has a custom command.
803
      if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
804
805
        // The existing custom command is identical.  Silently ignore
        // the duplicate.
806
        return file;
807
      }
808
809
810
      // The existing custom command is different.  We need to
      // generate a rule file for this new command.
      file = CM_NULLPTR;
811
    } else if (!file) {
812
      file = this->CreateSource(main_dependency);
813
    }
814
  }
815

816
  // Generate a rule file if the main dependency is not available.
817
  if (!file) {
818
    cmGlobalGenerator* gg = this->GetGlobalGenerator();
819

820
    // Construct a rule file associated with the first output produced.
821
822
    std::string outName = gg->GenerateRuleFile(outputs[0]);

823
    // Check if the rule file already exists.
Stephen Kelly's avatar
Stephen Kelly committed
824
    file = this->GetSource(outName);
825
    if (file && file->GetCustomCommand() && !replace) {
826
      // The rule file already exists.
827
      if (commandLines != file->GetCustomCommand()->GetCommandLines()) {