cmMakefile.cxx 147 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
#include "cmAlgorithms.h"
6
#include "cmCommand.h"
7
#include "cmCommandArgumentParserHelper.h"
8
9
10
11
12
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmExecutionStatus.h"
#include "cmExpandedCommandArgument.h"
#include "cmFileLockPool.h"
13
#include "cmFunctionBlocker.h"
14
#include "cmGeneratorExpression.h"
15
#include "cmGeneratorExpressionEvaluationFile.h"
16
#include "cmGlobalGenerator.h"
17
#include "cmListFileCache.h"
18
19
20
21
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmState.h"
#include "cmSystemTools.h"
22
#include "cmTest.h"
23
#include "cmVersion.h"
24
25
#include "cmake.h"

26
27
28
#include "cmInstallGenerator.h" // IWYU pragma: keep
#include "cmTestGenerator.h"    // IWYU pragma: keep

29
#ifdef CMAKE_BUILD_WITH_CMAKE
30
#include "cmVariableWatch.h"
31
#endif
32

33
34
#include <algorithm>
#include <assert.h>
35
#include <cm_auto_ptr.hxx>
36
#include <cmsys/FStream.hxx>
37
#include <cmsys/RegularExpression.hxx>
38
39
40
41
42
#include <ctype.h>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <utility>
43

44
45
class cmMessenger;

46
// default is not to be building executables
47
48
cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
                       cmState::Snapshot const& snapshot)
49
50
51
  : GlobalGenerator(globalGenerator)
  , StateSnapshot(snapshot)
  , Backtrace(snapshot)
52
{
53
  this->IsSourceFileTryCompile = false;
54

55
56
  this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
  this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
57

58
59
  this->SuppressWatches = false;

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

Ken Martin's avatar
Ken Martin committed
63
  this->DefineFlags = " ";
64

65
66
67
  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/.+-]+@)");
68
  this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
69

70
71
72
  this->StateSnapshot =
    this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
      this->StateSnapshot);
73

74
75
  // Enter a policy level for this directory.
  this->PushPolicy();
76

77
78
79
  // push empty loop block
  this->PushLoopBlockBarrier();

80
81
82
  // By default the check is not done.  It is enabled by
  // cmListFileCache in the top level if necessary.
  this->CheckCMP0000 = false;
83
84
85

#if defined(CMAKE_BUILD_WITH_CMAKE)
  this->AddSourceGroup("", "^.*$");
86
87
88
  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)$");
89
90
91
92
93
  this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
  this->AddSourceGroup("CMake Rules", "\\.rule$");
  this->AddSourceGroup("Resources", "\\.plist$");
  this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
#endif
94
}
95

96
97
cmMakefile::~cmMakefile()
{
98
99
100
101
102
103
104
  cmDeleteAll(this->InstallGenerators);
  cmDeleteAll(this->TestGenerators);
  cmDeleteAll(this->SourceFiles);
  cmDeleteAll(this->Tests);
  cmDeleteAll(this->ImportedTargetsOwned);
  cmDeleteAll(this->FinalPassCommands);
  cmDeleteAll(this->FunctionBlockers);
105
  cmDeleteAll(this->EvaluationFiles);
106
107
}

108
109
void cmMakefile::IssueMessage(cmake::MessageType t,
                              std::string const& text) const
110
{
111
112
113
114
115
  if (!this->ExecutionStatusStack.empty()) {
    if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) {
      this->ExecutionStatusStack.back()->SetNestedError(true);
    }
  }
116
  this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace());
117
}
118

119
cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const
120
{
121
  return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
122
123
}

124
cmBacktraceRange cmMakefile::GetIncludeDirectoriesBacktraces() const
125
{
126
  return this->StateSnapshot.GetDirectory()
127
    .GetIncludeDirectoriesEntryBacktraces();
128
129
}

130
cmStringRange cmMakefile::GetCompileOptionsEntries() const
131
{
132
  return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
133
134
}

135
cmBacktraceRange cmMakefile::GetCompileOptionsBacktraces() const
136
{
137
  return this->StateSnapshot.GetDirectory().GetCompileOptionsEntryBacktraces();
138
139
}

140
cmStringRange cmMakefile::GetCompileDefinitionsEntries() const
141
{
142
  return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
143
144
}

145
cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const
146
{
147
  return this->StateSnapshot.GetDirectory()
148
    .GetCompileDefinitionsEntryBacktraces();
149
150
}

Ben Boeckel's avatar
Ben Boeckel committed
151
cmListFileBacktrace cmMakefile::GetBacktrace() const
152
{
153
  return this->Backtrace;
154
155
}

156
cmListFileBacktrace cmMakefile::GetBacktrace(cmCommandContext const& cc) const
157
{
158
159
160
161
162
  cmListFileContext lfc;
  lfc.Name = cc.Name;
  lfc.Line = cc.Line;
  lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
  return this->Backtrace.Push(lfc);
163
164
}

165
166
cmListFileContext cmMakefile::GetExecutionContext() const
{
167
168
169
170
171
172
  cmListFileContext const& cur = this->Backtrace.Top();
  cmListFileContext lfc;
  lfc.Name = cur.Name;
  lfc.Line = cur.Line;
  lfc.FilePath = this->StateSnapshot.GetExecutionListFile();
  return lfc;
173
174
}

175
void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
176
{
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  // 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;
    }
  }

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

219
220
221
222
// Helper class to make sure the call stack is valid.
class cmMakefileCall
{
public:
223
  cmMakefileCall(cmMakefile* mf, cmCommandContext const& cc,
224
225
226
227
228
                 cmExecutionStatus& status)
    : Makefile(mf)
  {
    cmListFileContext const& lfc = cmListFileContext::FromCommandContext(
      cc, this->Makefile->StateSnapshot.GetExecutionListFile());
229
    this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
230
    this->Makefile->ExecutionStatusStack.push_back(&status);
231
  }
232
233

  ~cmMakefileCall()
234
  {
235
    this->Makefile->ExecutionStatusStack.pop_back();
236
    this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
237
238
  }

239
240
241
242
private:
  cmMakefile* Makefile;
};

243
bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
244
                                cmExecutionStatus& status)
Ken Martin's avatar
Ken Martin committed
245
{
246
  bool result = true;
247

248
  // quick return if blocked
249
  if (this->IsFunctionBlocked(lff, status)) {
250
251
    // No error.
    return result;
252
  }
253

Ken Martin's avatar
Ken Martin committed
254
  std::string name = lff.Name;
255

256
257
258
259
260
  // Place this call on the call stack.
  cmMakefileCall stack_manager(this, lff, status);
  static_cast<void>(stack_manager);

  // Lookup the command prototype.
261
  if (cmCommand* proto = this->GetState()->GetCommand(name)) {
262
    // Clone the prototype.
263
    CM_AUTO_PTR<cmCommand> pcmd(proto->Clone());
264
265
266
    pcmd->SetMakefile(this);

    // Decide whether to invoke the command.
267
268
269
    if (pcmd->GetEnabled() && !cmSystemTools::GetFatalErrorOccured() &&
        (this->GetCMakeInstance()->GetWorkingMode() != cmake::SCRIPT_MODE ||
         pcmd->IsScriptable()))
270

271
    {
272
      // if trace is enabled, print out invoke information
273
      if (this->GetCMakeInstance()->GetTrace()) {
274
        this->PrintCommandTrace(lff);
275
      }
276
      // Try invoking the command.
277
      bool invokeSucceeded = pcmd->InvokeInitialPass(lff.Arguments, status);
278
      bool hadNestedError = status.GetNestedError();
279
      if (!invokeSucceeded || hadNestedError) {
280
        if (!hadNestedError) {
281
          // The command invocation requested that we report an error.
Bill Hoffman's avatar
Bill Hoffman committed
282
          this->IssueMessage(cmake::FATAL_ERROR, pcmd->GetError());
283
        }
284
        result = false;
285
        if (this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE) {
286
          cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
287
        }
288
      } else if (pcmd->HasFinalPass()) {
289
        // use the command
290
        this->FinalPassCommands.push_back(pcmd.release());
Ken Martin's avatar
Ken Martin committed
291
      }
292
293
294
    } else if (this->GetCMakeInstance()->GetWorkingMode() ==
                 cmake::SCRIPT_MODE &&
               !pcmd->IsScriptable()) {
295
296
297
      std::string error = "Command ";
      error += pcmd->GetName();
      error += "() is not scriptable";
Bill Hoffman's avatar
Bill Hoffman committed
298
      this->IssueMessage(cmake::FATAL_ERROR, error);
299
300
      result = false;
      cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
301
    }
302
303
  } else {
    if (!cmSystemTools::GetFatalErrorOccured()) {
304
305
306
      std::string error = "Unknown CMake command \"";
      error += lff.Name;
      error += "\".";
Bill Hoffman's avatar
Bill Hoffman committed
307
      this->IssueMessage(cmake::FATAL_ERROR, error);
308
      result = false;
309
      cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
310
    }
311
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
312

313
  return result;
Ken Martin's avatar
Ken Martin committed
314
315
}

Brad King's avatar
Brad King committed
316
317
318
class cmMakefile::IncludeScope
{
public:
319
320
  IncludeScope(cmMakefile* mf, std::string const& filenametoread,
               bool noPolicyScope);
Brad King's avatar
Brad King committed
321
322
323
324
  ~IncludeScope();
  void Quiet() { this->ReportError = false; }
private:
  cmMakefile* Makefile;
325
326
  bool NoPolicyScope;
  bool CheckCMP0011;
Brad King's avatar
Brad King committed
327
  bool ReportError;
328
  void EnforceCMP0011();
Brad King's avatar
Brad King committed
329
330
};

331
cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
332
                                       std::string const& filenametoread,
333
334
335
336
337
                                       bool noPolicyScope)
  : Makefile(mf)
  , NoPolicyScope(noPolicyScope)
  , CheckCMP0011(false)
  , ReportError(true)
Brad King's avatar
Brad King committed
338
{
339
  this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
340

341
342
343
  this->Makefile->PushFunctionBlockerBarrier();

  this->Makefile->StateSnapshot =
344
345
346
    this->Makefile->GetState()->CreateIncludeFileSnapshot(
      this->Makefile->StateSnapshot, filenametoread);
  if (!this->NoPolicyScope) {
347
    // Check CMP0011 to determine the policy scope type.
348
    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
      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;
    }
371
  }
Brad King's avatar
Brad King committed
372
373
374
375
}

cmMakefile::IncludeScope::~IncludeScope()
{
376
  if (!this->NoPolicyScope) {
377
378
379
380
    // 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.
381
382
    if (this->CheckCMP0011 &&
        !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) {
383
      this->CheckCMP0011 = false;
384
    }
385
386
387
388
389
390

    // 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.
391
    if (this->CheckCMP0011) {
392
393
      this->EnforceCMP0011();
    }
394
  }
395
  this->Makefile->PopSnapshot(this->ReportError);
396
397

  this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
398
399

  this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
400
401
402
403
404
405
}

void cmMakefile::IncludeScope::EnforceCMP0011()
{
  // We check the setting of this policy again because the included
  // script might actually set this policy for its includer.
406
  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
407
408
409
    case cmPolicies::WARN:
      // Warn because the user did not set this policy.
      {
410
411
412
413
414
415
416
417
        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());
418
419
420
      }
      break;
    case cmPolicies::REQUIRED_IF_USED:
421
    case cmPolicies::REQUIRED_ALWAYS: {
422
      std::ostringstream e;
423
      /* clang-format off */
Stephen Kelly's avatar
Stephen Kelly committed
424
      e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
425
        << "The included script\n  "
426
        << this->Makefile->GetExecutionFilePath() << "\n"
427
        << "affects policy settings, so it requires this policy to be set.";
428
      /* clang-format on */
429
      this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
430
    } break;
431
432
433
434
435
436
    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;
437
  }
Brad King's avatar
Brad King committed
438
439
}

Stephen Kelly's avatar
Stephen Kelly committed
440
bool cmMakefile::ReadDependentFile(const char* filename, bool noPolicyScope)
441
{
442
443
  this->AddDefinition("CMAKE_PARENT_LIST_FILE",
                      this->GetDefinition("CMAKE_CURRENT_LIST_FILE"));
444
445
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
446

447
  IncludeScope incScope(this, filenametoread, noPolicyScope);
448
449

  cmListFile listFile;
450
451
  if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
                          this->Backtrace)) {
452
    return false;
453
  }
454

455
  this->ReadListFile(listFile, filenametoread);
456
  if (cmSystemTools::GetFatalErrorOccured()) {
457
    incScope.Quiet();
458
  }
459
  return true;
460
461
}

462
463
464
class cmMakefile::ListFileScope
{
public:
465
  ListFileScope(cmMakefile* mf, std::string const& filenametoread)
466
467
    : Makefile(mf)
    , ReportError(true)
468
  {
469
    this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
470

471
    this->Makefile->StateSnapshot =
472
473
      this->Makefile->GetState()->CreateInlineListFileSnapshot(
        this->Makefile->StateSnapshot, filenametoread);
474
    assert(this->Makefile->StateSnapshot.IsValid());
475

476
    this->Makefile->PushFunctionBlockerBarrier();
477
478
479
480
  }

  ~ListFileScope()
  {
481
    this->Makefile->PopSnapshot(this->ReportError);
482
    this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
483
    this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
484
485
486
487
488
489
490
491
  }

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

Stephen Kelly's avatar
Stephen Kelly committed
492
bool cmMakefile::ReadListFile(const char* filename)
493
{
494
495
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
496

497
  ListFileScope scope(this, filenametoread);
498
499

  cmListFile listFile;
500
501
  if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
                          this->Backtrace)) {
502
    return false;
503
  }
504

505
  this->ReadListFile(listFile, filenametoread);
506
  if (cmSystemTools::GetFatalErrorOccured()) {
507
    scope.Quiet();
508
  }
509
  return true;
510
511
}

512
513
void cmMakefile::ReadListFile(cmListFile const& listFile,
                              std::string const& filenametoread)
514
{
515
516
  // add this list file to the list of dependencies
  this->ListFiles.push_back(filenametoread);
517

518
519
520
  std::string currentParentFile =
    this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
  std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
521

522
523
  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread.c_str());
  this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
524
                      cmSystemTools::GetFilenamePath(filenametoread).c_str());
525

526
  this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
527
528
529
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");

530
  // Run the parsed commands.
Stephen Kelly's avatar
Stephen Kelly committed
531
  const size_t numberFunctions = listFile.Functions.size();
532
  for (size_t i = 0; i < numberFunctions; ++i) {
533
    cmExecutionStatus status;
534
535
    this->ExecuteCommand(listFile.Functions[i], status);
    if (cmSystemTools::GetFatalErrorOccured()) {
536
      break;
537
538
    }
    if (status.GetReturnInvoked()) {
539
      // Exit early due to return command.
540
      break;
541
    }
542
  }
543
  this->CheckForUnusedVariables();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
544

545
546
547
548
549
550
551
  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");
552
}
553

554
void cmMakefile::EnforceDirectoryLevelRules() const
555
556
{
  // Diagnose a violation of CMP0000 if necessary.
557
  if (this->CheckCMP0000) {
558
    std::ostringstream msg;
559
560
    msg << "No cmake_minimum_required command is present.  "
        << "A line of code such as\n"
561
562
        << "  cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion()
        << "." << cmVersion::GetMinorVersion() << ")\n"
563
564
565
566
567
        << "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\".";
568
    switch (this->GetPolicyStatus(cmPolicies::CMP0000)) {
569
570
571
      case cmPolicies::WARN:
        // Warn because the user did not provide a mimimum required
        // version.
572
573
        this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING,
                                               msg.str(), this->Backtrace);
574
575
576
577
578
579
580
581
      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.
582
583
        this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, msg.str(),
                                               this->Backtrace);
584
585
586
        cmSystemTools::SetFatalErrorOccured();
        return;
    }
587
  }
588
}
589

590
591
void cmMakefile::AddEvaluationFile(
  const std::string& inputFile,
592
593
  CM_AUTO_PTR<cmCompiledGeneratorExpression> outputName,
  CM_AUTO_PTR<cmCompiledGeneratorExpression> condition, bool inputIsContent)
594
{
595
596
  this->EvaluationFiles.push_back(new cmGeneratorExpressionEvaluationFile(
    inputFile, outputName, condition, inputIsContent));
597
598
599
600
601
602
603
604
}

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

605
606
607
608
609
610
611
std::vector<cmExportBuildFileGenerator*>
cmMakefile::GetExportBuildFileGenerators() const
{
  return this->ExportBuildFileGenerators;
}

void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
612
  cmExportBuildFileGenerator* gen)
613
614
{
  std::vector<cmExportBuildFileGenerator*>::iterator it =
615
616
617
    std::find(this->ExportBuildFileGenerators.begin(),
              this->ExportBuildFileGenerators.end(), gen);
  if (it != this->ExportBuildFileGenerators.end()) {
618
    this->ExportBuildFileGenerators.erase(it);
619
  }
620
621
622
623
624
625
626
}

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

627
628
namespace {
struct file_not_persistent
629
{
630
  bool operator()(const std::string& path) const
631
  {
632
633
634
635
    return !(path.find("CMakeTmp") == path.npos &&
             cmSystemTools::FileExists(path.c_str()));
  }
};
636
637
}

638
void cmMakefile::FinalPass()
639
640
{
  // do all the variable expansions here
641
  this->ExpandVariablesCMP0019();
642

643
  // give all the commands a chance to do something
644
  // after the file has been parsed before generation
645
646
  for (std::vector<cmCommand*>::iterator i = this->FinalPassCommands.begin();
       i != this->FinalPassCommands.end(); ++i) {
647
    (*i)->FinalPass();
648
  }
649

650
651
652
653
  // 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
654

655
656
  // remove_if will move all items that don't have a valid file name to the
  // back of the vector
657
  std::vector<std::string>::iterator new_output_files_end = std::remove_if(
658
659
660
661
662
663
664
    this->OutputFiles.begin(), this->OutputFiles.end(), file_not_persistent());
  // we just have to erase all items at the back
  this->OutputFiles.erase(new_output_files_end, this->OutputFiles.end());

  // 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
665
  std::vector<std::string>::iterator new_list_files_end = std::remove_if(
666
    this->ListFiles.begin(), this->ListFiles.end(), file_not_persistent());
667

668
  this->ListFiles.erase(new_list_files_end, this->ListFiles.end());
669
670
}

Bill Hoffman's avatar
Bill Hoffman committed
671
// Generate the output file
672
void cmMakefile::ConfigureFinalPass()
673
674
{
  this->FinalPass();
675
676
677
  const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
  if (oldValue &&
      cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
678
    this->GetCMakeInstance()->IssueMessage(
679
680
681
682
      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 "
683
684
      "use any CMake 2.8.x release or lower.",
      this->Backtrace);
685
  }
686
687
}

688
689
690
691
692
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,
693
  bool uses_terminal, const std::string& depfile)
694
{
695
  // Find the target to which to add the custom command.
Ken Martin's avatar
Ken Martin committed
696
  cmTargets::iterator ti = this->Targets.find(target);
697

698
  if (ti == this->Targets.end()) {
699
700
    cmake::MessageType messageType = cmake::AUTHOR_WARNING;
    bool issueMessage = false;
701
    std::ostringstream e;
702
    switch (this->GetPolicyStatus(cmPolicies::CMP0040)) {
703
      case cmPolicies::WARN:
Stephen Kelly's avatar
Stephen Kelly committed
704
        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0040) << "\n";
705
706
707
708
709
710
711
712
        issueMessage = true;
      case cmPolicies::OLD:
        break;
      case cmPolicies::NEW:
      case cmPolicies::REQUIRED_IF_USED:
      case cmPolicies::REQUIRED_ALWAYS:
        issueMessage = true;
        messageType = cmake::FATAL_ERROR;
713
    }
714

715
716
717
    if (issueMessage) {
      if (cmTarget const* t = this->FindTargetToUse(target)) {
        if (t->IsImported()) {
718
719
          e << "TARGET '" << target
            << "' is IMPORTED and does not build here.";
720
721
        } else {
          e << "TARGET '" << target << "' was not created in this directory.";
722
        }
723
      } else {
724
725
        e << "No TARGET '" << target
          << "' has been created in this directory.";
726
      }
727
      IssueMessage(messageType, e.str());
728
729
    }

730
731
732
733
    return;
  }

  if (ti->second.GetType() == cmState::OBJECT_LIBRARY) {
734
    std::ostringstream e;
735
736
737
    e << "Target \"" << target
      << "\" is an OBJECT library "
         "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
738
739
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
740
741
  }
  if (ti->second.GetType() == cmState::INTERFACE_LIBRARY) {
742
    std::ostringstream e;
743
744
745
    e << "Target \"" << target
      << "\" is an INTERFACE library "
         "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
746
747
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
748
  }
749
750

  // Always create the byproduct sources and mark them generated.
751
752
753
  for (std::vector<std::string>::const_iterator o = byproducts.begin();
       o != byproducts.end(); ++o) {
    if (cmSourceFile* out = this->GetOrCreateSource(*o, true)) {
754
755
      out->SetProperty("GENERATED", "1");
    }
756
  }
757

758
759
  // Add the command to the appropriate build step for the target.
  std::vector<std::string> no_output;
760
761
  cmCustomCommand cc(this, no_output, byproducts, depends, commandLines,
                     comment, workingDir);
762
763
  cc.SetEscapeOldStyle(escapeOldStyle);
  cc.SetEscapeAllowMakeVars(true);
764
  cc.SetUsesTerminal(uses_terminal);
765
  cc.SetDepfile(depfile);
766
  switch (type) {
767
768
769
770
771
772
773
774
775
    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;
776
  }
777
778
}

779
780
781
782
783
784
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,
785
  bool uses_terminal, const std::string& depfile)
786
{
787
  // Make sure there is at least one output.
788
  if (outputs.empty()) {
789
    cmSystemTools::Error("Attempt to add a custom rule with no output!");
Daniel Pfeifer's avatar
Daniel Pfeifer committed
790
    return CM_NULLPTR;
791
  }
792

793
  // Validate custom commands.  TODO: More strict?
794
795
  for (cmCustomCommandLines::const_iterator i = commandLines.begin();
       i != commandLines.end(); ++i) {
796
    cmCustomCommandLine const& cl = *i;
797
    if (!cl.empty() && !cl[0].empty() && cl[0][0] == '"') {
798
      std::ostringstream e;
799
800
      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
801
      return CM_NULLPTR;
802
    }
803
  }
804

805
  // Choose a source file on which to store the custom command.
Daniel Pfeifer's avatar
Daniel Pfeifer committed
806
  cmSourceFile* file = CM_NULLPTR;
807
  if (!commandLines.empty() && !main_dependency.empty()) {
808
809
810
    // The main dependency was specified.  Use it unless a different
    // custom command already used it.
    file = this->GetSource(main_dependency);
811
    if (file && file->GetCustomCommand() && !replace) {
812
      // The main dependency already has a custom command.
813
      if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
814
815
        // The existing custom command is identical.  Silently ignore
        // the duplicate.
816
        return file;
817
      }
818
819
820
      // The existing custom command is different.  We need to
      // generate a rule file for this new command.
      file = CM_NULLPTR;
821
    } else if (!file) {
822
      file = this->CreateSource(main_dependency);
823
    }
824
  }
825

826
  // Generate a rule file if the main dependency is not available.
827
  if (!file) {
828
    cmGlobalGenerator* gg = this->GetGlobalGenerator();
829

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

833
    // Check if the rule file already exists.
Stephen Kelly's avatar
Stephen Kelly committed
834
    file = this->GetSource(outName);
835
    if (file && file->GetCustomCommand() && !replace) {
836
      // The rule file already exists.
837
      if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
838
        cmSystemTools::Error("Attempt to add a custom rule to output \"",
839
840
                             outName.c_str(),
                             "\" which already has a custom rule.");
841
      }
842
843
      return file;
    }
844
845

    // Create a cmSourceFile for the rule file.
846
    if (!file) {
847
      file = this->CreateSource(outName, true);
848
    }
849
850
    file->SetProperty("__CMAKE_RULE", "1");
  }
851

852
  // Always create the output sources and mark them generated.
853
854
855
  for (std::vector<std::string>::const_iterator o = outputs.begin();
       o != outputs.end(); ++o) {
    if (cmSourceFile* out = this->GetOrCreateSource(*o, true)) {