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

cmMakefile.cxx 147 KB
Newer Older
1
2
3
/*============================================================================
  CMake - Cross Platform Makefile Generator
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4

5
6
  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.
7

8
9
10
11
  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
12
#include "cmMakefile.h"
Brad King's avatar
Brad King committed
13

14
#include "cmAlgorithms.h"
15
#include "cmCommand.h"
16
#include "cmCommandArgumentParserHelper.h"
17
18
19
20
21
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmExecutionStatus.h"
#include "cmExpandedCommandArgument.h"
#include "cmFileLockPool.h"
22
#include "cmFunctionBlocker.h"
23
#include "cmGeneratorExpression.h"
24
#include "cmGeneratorExpressionEvaluationFile.h"
25
#include "cmGlobalGenerator.h"
26
#include "cmInstallGenerator.h"
27
#include "cmListFileCache.h"
28
29
30
31
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmState.h"
#include "cmSystemTools.h"
32
#include "cmTest.h"
33
#include "cmTestGenerator.h"
34
#include "cmVersion.h"
35
36
#include "cmake.h"

37
#ifdef CMAKE_BUILD_WITH_CMAKE
38
#include "cmVariableWatch.h"
39
#endif
40

41
#include <cm_auto_ptr.hxx>
42
#include <cmsys/FStream.hxx>
43
#include <cmsys/RegularExpression.hxx>
44

45
#include <algorithm>
46
#include <assert.h>
47
48
49
50
51
#include <ctype.h>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <utility>
52

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

62
63
  this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
  this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
64

65
66
  this->SuppressWatches = false;

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

Ken Martin's avatar
Ken Martin committed
70
  this->DefineFlags = " ";
71

72
73
74
  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/.+-]+@)");
75
  this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
76

77
78
79
  this->StateSnapshot =
    this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
      this->StateSnapshot);
80

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

84
85
86
  // push empty loop block
  this->PushLoopBlockBarrier();

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

#if defined(CMAKE_BUILD_WITH_CMAKE)
  this->AddSourceGroup("", "^.*$");
93
94
95
  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)$");
96
97
98
99
100
  this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
  this->AddSourceGroup("CMake Rules", "\\.rule$");
  this->AddSourceGroup("Resources", "\\.plist$");
  this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
#endif
101
}
102

103
104
cmMakefile::~cmMakefile()
{
105
106
107
108
109
110
111
  cmDeleteAll(this->InstallGenerators);
  cmDeleteAll(this->TestGenerators);
  cmDeleteAll(this->SourceFiles);
  cmDeleteAll(this->Tests);
  cmDeleteAll(this->ImportedTargetsOwned);
  cmDeleteAll(this->FinalPassCommands);
  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
120
  assert(!this->ExecutionStatusStack.empty());
  if ((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR)) {
    this->ExecutionStatusStack.back()->SetNestedError(true);
121
  }
122
  this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace());
123
}
124

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

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

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

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

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

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

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

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

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

181
void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
182
{
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  // 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;
    }
  }

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

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

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

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

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

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

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

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

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

    // Decide whether to invoke the command.
273
274
275
    if (pcmd->GetEnabled() && !cmSystemTools::GetFatalErrorOccured() &&
        (this->GetCMakeInstance()->GetWorkingMode() != cmake::SCRIPT_MODE ||
         pcmd->IsScriptable()))
276

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

319
  return result;
Ken Martin's avatar
Ken Martin committed
320
321
}

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

337
cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
338
                                       std::string const& filenametoread,
339
340
341
342
343
                                       bool noPolicyScope)
  : Makefile(mf)
  , NoPolicyScope(noPolicyScope)
  , CheckCMP0011(false)
  , ReportError(true)
Brad King's avatar
Brad King committed
344
{
345
  this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
346

347
348
349
  this->Makefile->PushFunctionBlockerBarrier();

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

cmMakefile::IncludeScope::~IncludeScope()
{
382
  if (!this->NoPolicyScope) {
383
384
385
386
    // 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.
387
388
    if (this->CheckCMP0011 &&
        !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) {
389
      this->CheckCMP0011 = false;
390
    }
391
392
393
394
395
396

    // 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.
397
    if (this->CheckCMP0011) {
398
399
      this->EnforceCMP0011();
    }
400
  }
401
  this->Makefile->PopSnapshot(this->ReportError);
402
403

  this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
404
405

  this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
406
407
408
409
410
411
}

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

Stephen Kelly's avatar
Stephen Kelly committed
446
bool cmMakefile::ReadDependentFile(const char* filename, bool noPolicyScope)
447
{
448
449
  this->AddDefinition("CMAKE_PARENT_LIST_FILE",
                      this->GetDefinition("CMAKE_CURRENT_LIST_FILE"));
450
451
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
452

453
  IncludeScope incScope(this, filenametoread, noPolicyScope);
454
455

  cmListFile listFile;
456
  if (!listFile.ParseFile(filenametoread.c_str(), this)) {
457
    return false;
458
  }
459

460
  this->ReadListFile(listFile, filenametoread);
461
  if (cmSystemTools::GetFatalErrorOccured()) {
462
    incScope.Quiet();
463
  }
464
  return true;
465
466
}

467
468
469
class cmMakefile::ListFileScope
{
public:
470
  ListFileScope(cmMakefile* mf, std::string const& filenametoread)
471
472
    : Makefile(mf)
    , ReportError(true)
473
  {
474
    this->Makefile->Backtrace = this->Makefile->Backtrace.Push(filenametoread);
475

476
    this->Makefile->StateSnapshot =
477
478
      this->Makefile->GetState()->CreateInlineListFileSnapshot(
        this->Makefile->StateSnapshot, filenametoread);
479
    assert(this->Makefile->StateSnapshot.IsValid());
480

481
    this->Makefile->PushFunctionBlockerBarrier();
482
483
484
485
  }

  ~ListFileScope()
  {
486
    this->Makefile->PopSnapshot(this->ReportError);
487
    this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
488
    this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
489
490
491
492
493
494
495
496
  }

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

Stephen Kelly's avatar
Stephen Kelly committed
497
bool cmMakefile::ReadListFile(const char* filename)
498
{
499
500
  std::string filenametoread = cmSystemTools::CollapseFullPath(
    filename, this->GetCurrentSourceDirectory());
501

502
  ListFileScope scope(this, filenametoread);
503
504

  cmListFile listFile;
505
  if (!listFile.ParseFile(filenametoread.c_str(), this)) {
506
    return false;
507
  }
508

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

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

522
523
524
  std::string currentParentFile =
    this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
  std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
525

526
527
  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread.c_str());
  this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
528
                      cmSystemTools::GetFilenamePath(filenametoread).c_str());
529

530
  this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
531
532
533
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");

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

549
550
551
552
553
554
555
  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");
556
}
557

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

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

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

609
610
611
612
613
614
615
std::vector<cmExportBuildFileGenerator*>
cmMakefile::GetExportBuildFileGenerators() const
{
  return this->ExportBuildFileGenerators;
}

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

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

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

642
void cmMakefile::FinalPass()
643
644
{
  // do all the variable expansions here
645
  this->ExpandVariablesCMP0019();
646

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

654
655
656
657
  // 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
658

659
660
  // remove_if will move all items that don't have a valid file name to the
  // back of the vector
661
  std::vector<std::string>::iterator new_output_files_end = std::remove_if(
662
663
664
665
666
667
668
    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
669
  std::vector<std::string>::iterator new_list_files_end = std::remove_if(
670
    this->ListFiles.begin(), this->ListFiles.end(), file_not_persistent());
671

672
  this->ListFiles.erase(new_list_files_end, this->ListFiles.end());
673
674
}

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

692
693
694
695
696
697
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,
  bool uses_terminal)
698
{
699
  // Find the target to which to add the custom command.
Ken Martin's avatar
Ken Martin committed
700
  cmTargets::iterator ti = this->Targets.find(target);
701

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

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

734
735
736
737
    return;
  }

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

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

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

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

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

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

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

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

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

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

855
  // Always create the output sources and mark them generated.
856
857
858 <