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

cmMakefile.cxx 152 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
#include <algorithm>
#include <assert.h>
9
#include <cstring>
10
#include <ctype.h>
11
#include <iterator>
12
#include <memory> // IWYU pragma: keep
13
14
15
16
#include <sstream>
#include <stdlib.h>
#include <utility>

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

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

49
50
class cmMessenger;

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

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

63
64
  this->SuppressWatches = false;

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

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

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

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

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

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

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

#if defined(CMAKE_BUILD_WITH_CMAKE)
  this->AddSourceGroup("", "^.*$");
91
  this->AddSourceGroup("Source Files", CM_SOURCE_REGEX);
92
93
  this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
  this->AddSourceGroup("CMake Rules", "\\.rule$");
94
  this->AddSourceGroup("Resources", CM_RESOURCE_REGEX);
95
  this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
96
97

  this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size();
98
  this->SourceGroups.emplace_back("Object Libraries", "^MATCH_NO_SOURCES$");
99
#endif
100
}
101

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

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

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
bool cmMakefile::CheckCMP0037(std::string const& targetName,
                              cmStateEnums::TargetType targetType) const
{
  cmake::MessageType messageType = cmake::AUTHOR_WARNING;
  std::ostringstream e;
  bool issueMessage = false;
  switch (this->GetPolicyStatus(cmPolicies::CMP0037)) {
    case cmPolicies::WARN:
      if (targetType != cmStateEnums::INTERFACE_LIBRARY) {
        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
        issueMessage = true;
      }
      CM_FALLTHROUGH;
    case cmPolicies::OLD:
      break;
    case cmPolicies::NEW:
    case cmPolicies::REQUIRED_IF_USED:
    case cmPolicies::REQUIRED_ALWAYS:
      issueMessage = true;
      messageType = cmake::FATAL_ERROR;
      break;
  }
  if (issueMessage) {
    e << "The target name \"" << targetName
      << "\" is reserved or not valid for certain "
         "CMake features, such as generator expressions, and may result "
         "in undefined behavior.";
    this->IssueMessage(messageType, e.str());

    if (messageType == cmake::FATAL_ERROR) {
      return false;
    }
  }
  return true;
}

161
162
163
164
void cmMakefile::MaybeWarnCMP0074(std::string const& pkg)
{
  // Warn if a <pkg>_ROOT variable we may use is set.
  std::string const varName = pkg + "_ROOT";
165
166
167
168
169
170
  const char* var = this->GetDefinition(varName);
  std::string env;
  cmSystemTools::GetEnv(varName, env);

  bool const haveVar = var && *var;
  bool const haveEnv = !env.empty();
171
172
173
174
  if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) {
    std::ostringstream w;
    w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0074) << "\n";
    if (haveVar) {
175
176
      w << "CMake variable " << varName << " is set to:\n"
        << "  " << var << "\n";
177
178
    }
    if (haveEnv) {
179
180
      w << "Environment variable " << varName << " is set to:\n"
        << "  " << env << "\n";
181
182
183
184
185
186
    }
    w << "For compatibility, CMake is ignoring the variable.";
    this->IssueMessage(cmake::AUTHOR_WARNING, w.str());
  }
}

187
cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const
188
{
189
  return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
190
191
}

192
cmBacktraceRange cmMakefile::GetIncludeDirectoriesBacktraces() const
193
{
194
  return this->StateSnapshot.GetDirectory()
195
    .GetIncludeDirectoriesEntryBacktraces();
196
197
}

198
cmStringRange cmMakefile::GetCompileOptionsEntries() const
199
{
200
  return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
201
202
}

203
cmBacktraceRange cmMakefile::GetCompileOptionsBacktraces() const
204
{
205
  return this->StateSnapshot.GetDirectory().GetCompileOptionsEntryBacktraces();
206
207
}

208
cmStringRange cmMakefile::GetCompileDefinitionsEntries() const
209
{
210
  return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
211
212
}

213
cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const
214
{
215
  return this->StateSnapshot.GetDirectory()
216
    .GetCompileDefinitionsEntryBacktraces();
217
218
}

Ben Boeckel's avatar
Ben Boeckel committed
219
cmListFileBacktrace cmMakefile::GetBacktrace() const
220
{
221
  return this->Backtrace;
222
223
}

224
cmListFileBacktrace cmMakefile::GetBacktrace(cmCommandContext const& cc) const
225
{
226
227
228
229
230
  cmListFileContext lfc;
  lfc.Name = cc.Name;
  lfc.Line = cc.Line;
  lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
  return this->Backtrace.Push(lfc);
231
232
}

233
234
cmListFileContext cmMakefile::GetExecutionContext() const
{
235
236
237
238
239
240
  cmListFileContext const& cur = this->Backtrace.Top();
  cmListFileContext lfc;
  lfc.Name = cur.Name;
  lfc.Line = cur.Line;
  lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
  return lfc;
241
242
}

243
void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
244
{
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  // 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;
    }
  }

266
  std::ostringstream msg;
267
  msg << full_path << "(" << lff.Line << "):  ";
268
  msg << lff.Name << "(";
Ben Boeckel's avatar
Ben Boeckel committed
269
270
  bool expand = this->GetCMakeInstance()->GetTraceExpand();
  std::string temp;
271
  for (cmListFileArgument const& arg : lff.Arguments) {
272
    if (expand) {
273
      temp = arg.Value;
Ben Boeckel's avatar
Ben Boeckel committed
274
275
      this->ExpandVariablesInString(temp);
      msg << temp;
276
    } else {
277
      msg << arg.Value;
278
    }
279
280
    msg << " ";
  }
281
282
283
284
  msg << ")";
  cmSystemTools::Message(msg.str().c_str());
}

285
286
287
288
// Helper class to make sure the call stack is valid.
class cmMakefileCall
{
public:
289
  cmMakefileCall(cmMakefile* mf, cmCommandContext const& cc,
290
291
292
293
294
                 cmExecutionStatus& status)
    : Makefile(mf)
  {
    cmListFileContext const& lfc = cmListFileContext::FromCommandContext(
      cc, this->Makefile->StateSnapshot.GetExecutionListFile());
295
    this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
296
    this->Makefile->ExecutionStatusStack.push_back(&status);
297
  }
298
299

  ~cmMakefileCall()
300
  {
301
    this->Makefile->ExecutionStatusStack.pop_back();
302
    this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
303
304
  }

305
306
307
308
private:
  cmMakefile* Makefile;
};

309
bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
310
                                cmExecutionStatus& status)
Ken Martin's avatar
Ken Martin committed
311
{
312
  bool result = true;
313

314
  // quick return if blocked
315
  if (this->IsFunctionBlocked(lff, status)) {
316
317
    // No error.
    return result;
318
  }
319

Ken Martin's avatar
Ken Martin committed
320
  std::string name = lff.Name;
321

322
323
324
325
326
  // Place this call on the call stack.
  cmMakefileCall stack_manager(this, lff, status);
  static_cast<void>(stack_manager);

  // Lookup the command prototype.
327
  if (cmCommand* proto = this->GetState()->GetCommand(name)) {
328
    // Clone the prototype.
329
    std::unique_ptr<cmCommand> pcmd(proto->Clone());
330
331
332
    pcmd->SetMakefile(this);

    // Decide whether to invoke the command.
333
    if (!cmSystemTools::GetFatalErrorOccured()) {
334
      // if trace is enabled, print out invoke information
335
      if (this->GetCMakeInstance()->GetTrace()) {
336
        this->PrintCommandTrace(lff);
337
      }
338
      // Try invoking the command.
339
      bool invokeSucceeded = pcmd->InvokeInitialPass(lff.Arguments, status);
340
      bool hadNestedError = status.GetNestedError();
341
      if (!invokeSucceeded || hadNestedError) {
342
        if (!hadNestedError) {
343
          // The command invocation requested that we report an error.
344
345
          std::string const error = name + " " + pcmd->GetError();
          this->IssueMessage(cmake::FATAL_ERROR, error);
346
        }
347
        result = false;
348
        if (this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE) {
349
          cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
350
        }
351
      } else if (pcmd->HasFinalPass()) {
352
        // use the command
353
        this->FinalPassCommands.push_back(pcmd.release());
Ken Martin's avatar
Ken Martin committed
354
355
      }
    }
356
357
  } else {
    if (!cmSystemTools::GetFatalErrorOccured()) {
358
359
360
      std::string error = "Unknown CMake command \"";
      error += lff.Name;
      error += "\".";
Bill Hoffman's avatar
Bill Hoffman committed
361
      this->IssueMessage(cmake::FATAL_ERROR, error);
362
      result = false;
363
      cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
364
    }
365
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
366

367
  return result;
Ken Martin's avatar
Ken Martin committed
368
369
}

Brad King's avatar
Brad King committed
370
371
372
class cmMakefile::IncludeScope
{
public:
373
374
  IncludeScope(cmMakefile* mf, std::string const& filenametoread,
               bool noPolicyScope);
Brad King's avatar
Brad King committed
375
376
  ~IncludeScope();
  void Quiet() { this->ReportError = false; }
377

Brad King's avatar
Brad King committed
378
379
private:
  cmMakefile* Makefile;
380
381
  bool NoPolicyScope;
  bool CheckCMP0011;
Brad King's avatar
Brad King committed
382
  bool ReportError;
383
  void EnforceCMP0011();
Brad King's avatar
Brad King committed
384
385
};

386
cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
387
                                       std::string const& filenametoread,
388
389
390
391
392
                                       bool noPolicyScope)
  : Makefile(mf)
  , NoPolicyScope(noPolicyScope)
  , CheckCMP0011(false)
  , ReportError(true)
Brad King's avatar
Brad King committed
393
{
394
  this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
395

396
397
398
  this->Makefile->PushFunctionBlockerBarrier();

  this->Makefile->StateSnapshot =
399
400
401
    this->Makefile->GetState()->CreateIncludeFileSnapshot(
      this->Makefile->StateSnapshot, filenametoread);
  if (!this->NoPolicyScope) {
402
    // Check CMP0011 to determine the policy scope type.
403
    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
      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;
421
        CM_FALLTHROUGH;
422
423
424
425
426
      case cmPolicies::NEW:
        // NEW behavior is to push a (strong) scope.
        this->Makefile->PushPolicy();
        break;
    }
427
  }
Brad King's avatar
Brad King committed
428
429
430
431
}

cmMakefile::IncludeScope::~IncludeScope()
{
432
  if (!this->NoPolicyScope) {
433
434
435
436
    // 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.
437
438
    if (this->CheckCMP0011 &&
        !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) {
439
      this->CheckCMP0011 = false;
440
    }
441
442
443
444
445
446

    // 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.
447
    if (this->CheckCMP0011) {
448
449
      this->EnforceCMP0011();
    }
450
  }
451
  this->Makefile->PopSnapshot(this->ReportError);
452
453

  this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
454
455

  this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
456
457
458
459
460
461
}

void cmMakefile::IncludeScope::EnforceCMP0011()
{
  // We check the setting of this policy again because the included
  // script might actually set this policy for its includer.
462
  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
463
464
465
    case cmPolicies::WARN:
      // Warn because the user did not set this policy.
      {
466
467
468
469
470
471
472
473
        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());
474
475
476
      }
      break;
    case cmPolicies::REQUIRED_IF_USED:
477
    case cmPolicies::REQUIRED_ALWAYS: {
478
      std::ostringstream e;
479
      /* clang-format off */
Stephen Kelly's avatar
Stephen Kelly committed
480
      e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
481
        << "The included script\n  "
482
        << this->Makefile->GetExecutionFilePath() << "\n"
483
        << "affects policy settings, so it requires this policy to be set.";
484
      /* clang-format on */
485
      this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
486
    } break;
487
488
489
490
491
492
    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;
493
  }
Brad King's avatar
Brad King committed
494
495
}

Stephen Kelly's avatar
Stephen Kelly committed
496
bool cmMakefile::ReadDependentFile(const char* filename, bool noPolicyScope)
497
{
498
499
  this->AddDefinition("CMAKE_PARENT_LIST_FILE",
                      this->GetDefinition("CMAKE_CURRENT_LIST_FILE"));
500
501
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
502

503
  IncludeScope incScope(this, filenametoread, noPolicyScope);
504
505

  cmListFile listFile;
506
507
  if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
                          this->Backtrace)) {
508
    return false;
509
  }
510

511
  this->ReadListFile(listFile, filenametoread);
512
  if (cmSystemTools::GetFatalErrorOccured()) {
513
    incScope.Quiet();
514
  }
515
  return true;
516
517
}

518
519
520
class cmMakefile::ListFileScope
{
public:
521
  ListFileScope(cmMakefile* mf, std::string const& filenametoread)
522
523
    : Makefile(mf)
    , ReportError(true)
524
  {
525
    this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
526

527
    this->Makefile->StateSnapshot =
528
529
      this->Makefile->GetState()->CreateInlineListFileSnapshot(
        this->Makefile->StateSnapshot, filenametoread);
530
    assert(this->Makefile->StateSnapshot.IsValid());
531

532
    this->Makefile->PushFunctionBlockerBarrier();
533
534
535
536
  }

  ~ListFileScope()
  {
537
    this->Makefile->PopSnapshot(this->ReportError);
538
    this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
539
    this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
540
541
542
  }

  void Quiet() { this->ReportError = false; }
543

544
545
546
547
548
private:
  cmMakefile* Makefile;
  bool ReportError;
};

Stephen Kelly's avatar
Stephen Kelly committed
549
bool cmMakefile::ReadListFile(const char* filename)
550
{
551
552
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
553

554
  ListFileScope scope(this, filenametoread);
555
556

  cmListFile listFile;
557
558
  if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
                          this->Backtrace)) {
559
    return false;
560
  }
561

562
  this->ReadListFile(listFile, filenametoread);
563
  if (cmSystemTools::GetFatalErrorOccured()) {
564
    scope.Quiet();
565
  }
566
  return true;
567
568
}

569
570
void cmMakefile::ReadListFile(cmListFile const& listFile,
                              std::string const& filenametoread)
571
{
572
573
  // add this list file to the list of dependencies
  this->ListFiles.push_back(filenametoread);
574

575
576
577
  std::string currentParentFile =
    this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
  std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
578

579
580
  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread.c_str());
  this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
581
                      cmSystemTools::GetFilenamePath(filenametoread).c_str());
582

583
  this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
584
585
586
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");

587
  // Run the parsed commands.
Stephen Kelly's avatar
Stephen Kelly committed
588
  const size_t numberFunctions = listFile.Functions.size();
589
  for (size_t i = 0; i < numberFunctions; ++i) {
590
    cmExecutionStatus status;
591
592
    this->ExecuteCommand(listFile.Functions[i], status);
    if (cmSystemTools::GetFatalErrorOccured()) {
593
      break;
594
595
    }
    if (status.GetReturnInvoked()) {
596
      // Exit early due to return command.
597
      break;
598
    }
599
  }
600
  this->CheckForUnusedVariables();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
601

602
603
604
605
606
607
608
  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");
609
}
610

611
void cmMakefile::EnforceDirectoryLevelRules() const
612
613
{
  // Diagnose a violation of CMP0000 if necessary.
614
  if (this->CheckCMP0000) {
615
    std::ostringstream msg;
616
617
    msg << "No cmake_minimum_required command is present.  "
        << "A line of code such as\n"
618
619
        << "  cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion()
        << "." << cmVersion::GetMinorVersion() << ")\n"
620
621
622
623
624
        << "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\".";
625
    switch (this->GetPolicyStatus(cmPolicies::CMP0000)) {
626
      case cmPolicies::WARN:
luz.paz's avatar
luz.paz committed
627
        // Warn because the user did not provide a minimum required
628
        // version.
629
630
        this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING,
                                               msg.str(), this->Backtrace);
631
632
633
634
635
636
637
638
      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.
639
640
        this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, msg.str(),
                                               this->Backtrace);
641
642
643
        cmSystemTools::SetFatalErrorOccured();
        return;
    }
644
  }
645
}
646

647
648
void cmMakefile::AddEvaluationFile(
  const std::string& inputFile,
649
650
651
  std::unique_ptr<cmCompiledGeneratorExpression> outputName,
  std::unique_ptr<cmCompiledGeneratorExpression> condition,
  bool inputIsContent)
652
{
653
  this->EvaluationFiles.push_back(new cmGeneratorExpressionEvaluationFile(
654
    inputFile, std::move(outputName), std::move(condition), inputIsContent,
655
    this->GetPolicyStatus(cmPolicies::CMP0070)));
656
657
658
659
660
661
662
663
}

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

664
665
666
667
668
669
670
std::vector<cmExportBuildFileGenerator*>
cmMakefile::GetExportBuildFileGenerators() const
{
  return this->ExportBuildFileGenerators;
}

void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
671
  cmExportBuildFileGenerator* gen)
672
673
{
  std::vector<cmExportBuildFileGenerator*>::iterator it =
674
675
676
    std::find(this->ExportBuildFileGenerators.begin(),
              this->ExportBuildFileGenerators.end(), gen);
  if (it != this->ExportBuildFileGenerators.end()) {
677
    this->ExportBuildFileGenerators.erase(it);
678
  }
679
680
681
682
683
684
685
}

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

686
687
namespace {
struct file_not_persistent
688
{
689
  bool operator()(const std::string& path) const
690
  {
691
    return !(path.find("CMakeTmp") == std::string::npos &&
692
             cmSystemTools::FileExists(path));
693
694
  }
};
695
696
}

697
void cmMakefile::FinalPass()
698
699
{
  // do all the variable expansions here
700
  this->ExpandVariablesCMP0019();
701

702
  // give all the commands a chance to do something
703
  // after the file has been parsed before generation
704
705
  for (cmCommand* fpCommand : this->FinalPassCommands) {
    fpCommand->FinalPass();
706
  }
707

708
709
710
711
  // 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
712
  cmEraseIf(this->OutputFiles, file_not_persistent());
713
714
715
716

  // 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
717
  cmEraseIf(this->ListFiles, file_not_persistent());
718
719
}

Bill Hoffman's avatar
Bill Hoffman committed
720
// Generate the output file
721
void cmMakefile::ConfigureFinalPass()
722
723
{
  this->FinalPass();
724
725
726
  const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
  if (oldValue &&
      cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
727
    this->GetCMakeInstance()->IssueMessage(
728
729
730
731
      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 "
732
733
      "use any CMake 2.8.x release or lower.",
      this->Backtrace);
734
  }
735
736
}

737
738
739
740
741
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,
742
743
  bool uses_terminal, const std::string& depfile, bool command_expand_lists,
  ObjectLibraryCommands objLibraryCommands)
744
{
745
  // Find the target to which to add the custom command.
Ken Martin's avatar
Ken Martin committed
746
  cmTargets::iterator ti = this->Targets.find(target);
747

748
  if (ti == this->Targets.end()) {
749
750
    cmake::MessageType messageType = cmake::AUTHOR_WARNING;
    bool issueMessage = false;
751
    std::ostringstream e;
752
    switch (this->GetPolicyStatus(cmPolicies::CMP0040)) {
753
      case cmPolicies::WARN:
Stephen Kelly's avatar
Stephen Kelly committed
754
        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0040) << "\n";
755
756
757
758
759
760
761
762
        issueMessage = true;
      case cmPolicies::OLD:
        break;
      case cmPolicies::NEW:
      case cmPolicies::REQUIRED_IF_USED:
      case cmPolicies::REQUIRED_ALWAYS:
        issueMessage = true;
        messageType = cmake::FATAL_ERROR;
763
    }
764

765
766
767
    if (issueMessage) {
      if (cmTarget const* t = this->FindTargetToUse(target)) {
        if (t->IsImported()) {
768
769
          e << "TARGET '" << target
            << "' is IMPORTED and does not build here.";
770
771
        } else {
          e << "TARGET '" << target << "' was not created in this directory.";
772
        }
773
      } else {
774
775
        e << "No TARGET '" << target
          << "' has been created in this directory.";
776
      }
777
      IssueMessage(messageType, e.str());
778
779
    }

780
781
782
    return;
  }

783
  cmTarget& t = ti->second;
784
  if (objLibraryCommands == RejectObjectLibraryCommands &&
785
      t.GetType() == cmStateEnums::OBJECT_LIBRARY) {
786
    std::ostringstream e;
787
788
789
    e << "Target \"" << target
      << "\" is an OBJECT library "
         "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
790
791
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
792
  }
793
  if (t.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
794
    std::ostringstream e;
795
796
797
    e << "Target \"" << target
      << "\" is an INTERFACE library "
         "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
798
799
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
800
  }
801
802

  // Always create the byproduct sources and mark them generated.
803
804
  for (std::string const& o : byproducts) {
    if (cmSourceFile* out = this->GetOrCreateSource(o, true)) {
805
806
      out->SetProperty("GENERATED", "1");
    }
807
  }
808

809
810
  // Add the command to the appropriate build step for the target.
  std::vector<std::string> no_output;
811
812
  cmCustomCommand cc(this, no_output, byproducts, depends, commandLines,
                     comment, workingDir);
813
814
  cc.SetEscapeOldStyle(escapeOldStyle);
  cc.SetEscapeAllowMakeVars(true);
815
  cc.SetUsesTerminal(uses_terminal);
816
  cc.SetCommandExpandLists(command_expand_lists);
817
  cc.SetDepfile(depfile);
818
  switch (type) {
819
    case cmTarget::PRE_BUILD:
820
      t.AddPreBuildCommand(cc);
821
822
      break;
    case cmTarget::PRE_LINK:
823
      t.AddPreLinkCommand(cc);
824
825
      break;
    case cmTarget::POST_BUILD:
826
      t.AddPostBuildCommand(cc);
827
      break;
828
  }
829
830
}

831
832
833
834
835
836
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,
837
  bool uses_terminal, bool command_expand_lists, const std::string& depfile)
838
{
839
  // Make sure there is at least one output.
840
  if (outputs.empty()) {
841
    cmSystemTools::Error("Attempt to add a custom rule with no output!");
Daniel Pfeifer's avatar
Daniel Pfeifer committed
842
    return nullptr;
843
  }
844

845
  // Validate custom commands.  TODO: More strict?
846
  for (cmCustomCommandLine const& cl : commandLines) {
847
    if (!cl.empty() && !cl[0].empty() && cl[0][0] == '"') {
848
      std::ostringstream e;
849
850
      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
851
      return nullptr;
852
    }
853
  }
854

855
  // Choose a source file on which to store the custom command.