cmMakefile.cxx 168 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"
13
#include "cmVersion.h"
14
#include "cmCommand.h"
15
#include "cmSourceFile.h"
16
#include "cmSourceFileLocation.h"
17
#include "cmSystemTools.h"
Ken Martin's avatar
Ken Martin committed
18
19
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
20
#include "cmCommands.h"
Stephen Kelly's avatar
Stephen Kelly committed
21
#include "cmState.h"
22
#include "cmFunctionBlocker.h"
23
#include "cmListFileCache.h"
24
#include "cmCommandArgumentParserHelper.h"
25
#include "cmGeneratorExpression.h"
26
#include "cmTest.h"
27
28
29
#ifdef CMAKE_BUILD_WITH_CMAKE
#  include "cmVariableWatch.h"
#endif
30
#include "cmInstallGenerator.h"
31
#include "cmTestGenerator.h"
32
#include "cmDefinitions.h"
33
#include "cmAlgorithms.h"
34
#include "cmake.h"
35
#include <stdlib.h> // required for atoi
36
37

#include <cmsys/RegularExpression.hxx>
38
#include <cmsys/FStream.hxx>
39
40
#include <cmsys/auto_ptr.hxx>

41
#include <stack>
42
#include <list>
43
#include <ctype.h> // for isspace
44
#include <assert.h>
45

46
47
48
49
class cmMakefile::Internals
{
public:
  std::stack<cmDefinitions, std::list<cmDefinitions> > VarStack;
50
51
  std::stack<std::set<std::string> > VarInitStack;
  std::stack<std::set<std::string> > VarUsageStack;
52
  bool IsSourceFileTryCompile;
53
54
};

55
// default is not to be building executables
56
cmMakefile::cmMakefile(cmLocalGenerator* localGenerator)
Stephen Kelly's avatar
Stephen Kelly committed
57
58
59
60
  : Internal(new Internals),
    LocalGenerator(localGenerator),
    StateSnapshot(localGenerator->GetGlobalGenerator()
                                ->GetCMakeInstance()->GetState())
61
{
62
  const cmDefinitions& defs = cmDefinitions();
63
  const std::set<std::string> globalKeys = defs.LocalKeys();
64
65
  this->Internal->VarStack.push(defs);
  this->Internal->VarInitStack.push(globalKeys);
66
  this->Internal->VarUsageStack.push(globalKeys);
67
  this->Internal->IsSourceFileTryCompile = false;
68

Stephen Kelly's avatar
Stephen Kelly committed
69
70
71
72
73
74
75
76
77
78
79
80
81
  if (this->LocalGenerator->GetParent())
    {
    cmMakefile* parentMf = this->LocalGenerator->GetParent()->GetMakefile();
    this->StateSnapshot =
        this->GetState()->CreateSnapshot(parentMf->StateSnapshot);
    }
  else
    {
    this->StateSnapshot =
        this->GetState()->CreateSnapshot(this->StateSnapshot);
    }


82
83
84
  // Initialize these first since AddDefaultDefinitions calls AddDefinition
  this->WarnUnused = false;
  this->CheckSystemVars = false;
85

86
87
88
  this->GeneratingBuildSystem = false;
  this->SuppressWatches = false;

89
  // Setup the default include file regular expression (match everything).
Ken Martin's avatar
Ken Martin committed
90
  this->IncludeFileRegularExpression = "^.*$";
91
  // Setup the default include complaint regular expression (match nothing).
Ken Martin's avatar
Ken Martin committed
92
  this->ComplainFileRegularExpression = "^$";
93
  // Source and header file extensions that we can handle
94

95
  // Set up a list of source and header extensions
Alexander Neundorf's avatar
   
Alexander Neundorf committed
96
  // these are used to find files when the extension
97
  // is not given
98
  // The "c" extension MUST precede the "C" extension.
Ken Martin's avatar
Ken Martin committed
99
100
  this->SourceFileExtensions.push_back( "c" );
  this->SourceFileExtensions.push_back( "C" );
Alexander Neundorf's avatar
   
Alexander Neundorf committed
101

Ken Martin's avatar
Ken Martin committed
102
103
104
105
106
  this->SourceFileExtensions.push_back( "c++" );
  this->SourceFileExtensions.push_back( "cc" );
  this->SourceFileExtensions.push_back( "cpp" );
  this->SourceFileExtensions.push_back( "cxx" );
  this->SourceFileExtensions.push_back( "m" );
Alexander Neundorf's avatar
   
Alexander Neundorf committed
107
  this->SourceFileExtensions.push_back( "M" );
Ken Martin's avatar
Ken Martin committed
108
109
110
  this->SourceFileExtensions.push_back( "mm" );

  this->HeaderFileExtensions.push_back( "h" );
111
  this->HeaderFileExtensions.push_back( "hh" );
Ken Martin's avatar
Ken Martin committed
112
113
114
115
116
117
  this->HeaderFileExtensions.push_back( "h++" );
  this->HeaderFileExtensions.push_back( "hm" );
  this->HeaderFileExtensions.push_back( "hpp" );
  this->HeaderFileExtensions.push_back( "hxx" );
  this->HeaderFileExtensions.push_back( "in" );
  this->HeaderFileExtensions.push_back( "txx" );
Alexander Neundorf's avatar
   
Alexander Neundorf committed
118

Ken Martin's avatar
Ken Martin committed
119
  this->DefineFlags = " ";
120
  this->LocalGenerator = localGenerator;
121

122
  this->AddDefaultDefinitions();
123

124
  this->Initialize();
125
}
126

127
128
129
130
131
132
//----------------------------------------------------------------------------
void cmMakefile::Initialize()
{
  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/.+-]+@)");
133
  this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
134
135
136

  // Enter a policy level for this directory.
  this->PushPolicy();
137

Brad King's avatar
Brad King committed
138
139
140
  // Protect the directory-level policies.
  this->PushPolicyBarrier();

141
142
143
  // push empty loop block
  this->PushLoopBlockBarrier();

144
145
146
  // By default the check is not done.  It is enabled by
  // cmListFileCache in the top level if necessary.
  this->CheckCMP0000 = false;
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

#if defined(CMAKE_BUILD_WITH_CMAKE)
  this->AddSourceGroup("", "^.*$");
  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)$");
  this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
  this->AddSourceGroup("CMake Rules", "\\.rule$");
  this->AddSourceGroup("Resources", "\\.plist$");
  this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
#endif

  this->Properties.SetCMakeInstance(this->GetCMakeInstance());
  this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
  this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();

  {
  const char* dir = this->GetCMakeInstance()->GetHomeDirectory();
  this->AddDefinition("CMAKE_SOURCE_DIR", dir);
  if ( !this->GetDefinition("CMAKE_CURRENT_SOURCE_DIR") )
    {
    this->AddDefinition("CMAKE_CURRENT_SOURCE_DIR", dir);
    }
  }
  {
  const char* dir = this->GetCMakeInstance()->GetHomeOutputDirectory();
  this->AddDefinition("CMAKE_BINARY_DIR", dir);
  if ( !this->GetDefinition("CMAKE_CURRENT_BINARY_DIR") )
    {
    this->AddDefinition("CMAKE_CURRENT_BINARY_DIR", dir);
    }
  }
180
}
181

182
183
cmMakefile::~cmMakefile()
{
184
185
186
187
188
189
190
  cmDeleteAll(this->InstallGenerators);
  cmDeleteAll(this->TestGenerators);
  cmDeleteAll(this->SourceFiles);
  cmDeleteAll(this->Tests);
  cmDeleteAll(this->ImportedTargetsOwned);
  cmDeleteAll(this->FinalPassCommands);
  cmDeleteAll(this->FunctionBlockers);
Ken Martin's avatar
Ken Martin committed
191
  this->FunctionBlockers.clear();
192
193
194
195
196
  if (this->PolicyStack.size() != 1)
  {
    cmSystemTools::Error("Internal CMake Error, Policy Stack has not been"
      " popped properly");
  }
197
198
}

Alexander Neundorf's avatar
   
Alexander Neundorf committed
199
void cmMakefile::PrintStringVector(const char* s,
Ken Martin's avatar
Ken Martin committed
200
                                   const std::vector<std::string>& v) const
201
{
202
  std::cout << s << ": ( \n" << cmWrap('"', v, '"', " ") << ")\n";
203
204
}

Ken Martin's avatar
Ken Martin committed
205
void cmMakefile
Alexander Neundorf's avatar
   
Alexander Neundorf committed
206
::PrintStringVector(const char* s,
207
                    const std::vector<std::pair<std::string, bool> >& v) const
208
209
{
  std::cout << s << ": ( \n";
210
  for(std::vector<std::pair<std::string, bool> >::const_iterator i
Ken Martin's avatar
Ken Martin committed
211
        = v.begin(); i != v.end(); ++i)
212
    {
213
    std::cout << i->first << " " << i->second;
214
215
216
217
    }
  std::cout << " )\n";
}

218
219

// call print on all the classes in the makefile
220
void cmMakefile::Print() const
221
{
222
  // print the class lists
223
  std::cout << "classes:\n";
224

Ken Martin's avatar
Ken Martin committed
225
226
227
  std::cout << " this->Targets: ";
  for (cmTargets::iterator l = this->Targets.begin();
       l != this->Targets.end(); l++)
228
229
230
231
    {
    std::cout << l->first << std::endl;
    }

Alexander Neundorf's avatar
   
Alexander Neundorf committed
232
  std::cout << " this->StartOutputDirectory; " <<
233
    this->GetCurrentBinaryDirectory() << std::endl;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
234
  std::cout << " this->HomeOutputDirectory; " <<
235
    this->GetHomeOutputDirectory() << std::endl;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
236
  std::cout << " this->cmStartDirectory; " <<
237
    this->GetCurrentSourceDirectory() << std::endl;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
238
  std::cout << " this->cmHomeDirectory; " <<
239
    this->GetHomeDirectory() << std::endl;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
240
  std::cout << " this->ProjectName; "
241
            <<  this->ProjectName << std::endl;
Ken Martin's avatar
Ken Martin committed
242
  this->PrintStringVector("this->LinkDirectories", this->LinkDirectories);
243
#if defined(CMAKE_BUILD_WITH_CMAKE)
Alexander Neundorf's avatar
   
Alexander Neundorf committed
244
  for( std::vector<cmSourceGroup>::const_iterator i =
Ken Martin's avatar
Ken Martin committed
245
         this->SourceGroups.begin(); i != this->SourceGroups.end(); ++i)
246
    {
247
    std::cout << "Source Group: " << i->GetName() << std::endl;
248
    }
249
#endif
250
251
}

252
//----------------------------------------------------------------------------
Bill Hoffman's avatar
Bill Hoffman committed
253
254
void cmMakefile::IssueMessage(cmake::MessageType t,
                              std::string const& text) const
255
{
256
  // Collect context information.
257
258
259
260
261
262
  cmLocalGenerator* localGen = this->GetLocalGenerator();
  if(this->CallStack.empty() && this->GetCMakeInstance()->GetIsInTryCompile())
    {
    localGen = 0;
    }
  cmListFileBacktrace backtrace(localGen);
263
  if(!this->CallStack.empty())
264
    {
265
    if((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR))
266
      {
267
      this->CallStack.back().Status->SetNestedError(true);
268
      }
Ben Boeckel's avatar
Ben Boeckel committed
269
    backtrace = this->GetBacktrace();
270
    }
271
  else
272
    {
273
    cmListFileContext lfc;
274
275
276
    if(this->ListFileStack.empty())
      {
      // We are not processing the project.  Add the directory-level context.
277
      lfc.FilePath = this->GetCurrentSourceDirectory();
278
279
280
281
282
283
284
285
      lfc.FilePath += "/CMakeLists.txt";
      }
    else
      {
      // We are processing the project but are not currently executing a
      // command.  Add whatever context information we have.
      lfc.FilePath = this->ListFileStack.back();
      }
286
287
    lfc.Line = 0;
    backtrace.push_back(lfc);
288
    }
289

290
291
292
  // Issue the message.
  this->GetCMakeInstance()->IssueMessage(t, text, backtrace);
}
293

294
//----------------------------------------------------------------------------
Ben Boeckel's avatar
Ben Boeckel committed
295
cmListFileBacktrace cmMakefile::GetBacktrace() const
296
{
297
  cmListFileBacktrace backtrace(this->GetLocalGenerator());
298
299
  for(CallStackType::const_reverse_iterator i = this->CallStack.rbegin();
      i != this->CallStack.rend(); ++i)
300
    {
301
    backtrace.push_back(*i->Context);
302
    }
Ben Boeckel's avatar
Ben Boeckel committed
303
  return backtrace;
304
305
}

306
//----------------------------------------------------------------------------
307
void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
308
{
309
  std::ostringstream msg;
310
311
312
313
314
315
316
317
318
319
320
321
  msg << lff.FilePath << "(" << lff.Line << "):  ";
  msg << lff.Name << "(";
  for(std::vector<cmListFileArgument>::const_iterator i =
        lff.Arguments.begin(); i != lff.Arguments.end(); ++i)
    {
    msg << i->Value;
    msg << " ";
    }
  msg << ")";
  cmSystemTools::Message(msg.str().c_str());
}

322
//----------------------------------------------------------------------------
323
324
bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
                                cmExecutionStatus &status)
Ken Martin's avatar
Ken Martin committed
325
{
326
  bool result = true;
327

328
  // quick return if blocked
329
  if(this->IsFunctionBlocked(lff,status))
330
    {
331
332
    // No error.
    return result;
333
    }
334

Ken Martin's avatar
Ken Martin committed
335
  std::string name = lff.Name;
336

337
338
339
340
341
  // Place this call on the call stack.
  cmMakefileCall stack_manager(this, lff, status);
  static_cast<void>(stack_manager);

  // Lookup the command prototype.
342
  if(cmCommand* proto = this->GetState()->GetCommand(name))
343
344
345
346
347
348
349
    {
    // Clone the prototype.
    cmsys::auto_ptr<cmCommand> pcmd(proto->Clone());
    pcmd->SetMakefile(this);

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

353
      {
354
      // if trace is enabled, print out invoke information
Bill Hoffman's avatar
Bill Hoffman committed
355
356
      if(this->GetCMakeInstance()->GetTrace())
        {
357
        this->PrintCommandTrace(lff);
Bill Hoffman's avatar
Bill Hoffman committed
358
        }
359
360
361
      // Try invoking the command.
      if(!pcmd->InvokeInitialPass(lff.Arguments,status) ||
         status.GetNestedError())
Ken Martin's avatar
Ken Martin committed
362
        {
363
364
365
        if(!status.GetNestedError())
          {
          // The command invocation requested that we report an error.
Bill Hoffman's avatar
Bill Hoffman committed
366
          this->IssueMessage(cmake::FATAL_ERROR, pcmd->GetError());
367
          }
368
        result = false;
369
        if ( this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE)
Ken Martin's avatar
Ken Martin committed
370
          {
371
          cmSystemTools::SetFatalErrorOccured();
Ken Martin's avatar
Ken Martin committed
372
373
          }
        }
374
      else if(pcmd->HasFinalPass())
375
376
        {
        // use the command
377
        this->FinalPassCommands.push_back(pcmd.release());
378
        }
Ken Martin's avatar
Ken Martin committed
379
      }
380
    else if ( this->GetCMakeInstance()->GetWorkingMode() == cmake::SCRIPT_MODE
381
              && !pcmd->IsScriptable() )
382
      {
383
384
385
      std::string error = "Command ";
      error += pcmd->GetName();
      error += "() is not scriptable";
Bill Hoffman's avatar
Bill Hoffman committed
386
      this->IssueMessage(cmake::FATAL_ERROR, error);
387
388
389
      result = false;
      cmSystemTools::SetFatalErrorOccured();
      }
Ken Martin's avatar
Ken Martin committed
390
391
392
    }
  else
    {
393
394
    if(!cmSystemTools::GetFatalErrorOccured())
      {
395
396
397
      std::string error = "Unknown CMake command \"";
      error += lff.Name;
      error += "\".";
Bill Hoffman's avatar
Bill Hoffman committed
398
      this->IssueMessage(cmake::FATAL_ERROR, error);
399
      result = false;
400
      cmSystemTools::SetFatalErrorOccured();
401
      }
Ken Martin's avatar
Ken Martin committed
402
    }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
403

404
  return result;
Ken Martin's avatar
Ken Martin committed
405
406
}

Brad King's avatar
Brad King committed
407
408
409
410
//----------------------------------------------------------------------------
class cmMakefile::IncludeScope
{
public:
411
  IncludeScope(cmMakefile* mf, const char* fname, bool noPolicyScope);
Brad King's avatar
Brad King committed
412
413
414
415
  ~IncludeScope();
  void Quiet() { this->ReportError = false; }
private:
  cmMakefile* Makefile;
416
417
418
  const char* File;
  bool NoPolicyScope;
  bool CheckCMP0011;
Brad King's avatar
Brad King committed
419
  bool ReportError;
420
  void EnforceCMP0011();
Brad King's avatar
Brad King committed
421
422
423
};

//----------------------------------------------------------------------------
424
425
426
427
cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf, const char* fname,
                                       bool noPolicyScope):
  Makefile(mf), File(fname), NoPolicyScope(noPolicyScope),
  CheckCMP0011(false), ReportError(true)
Brad King's avatar
Brad King committed
428
{
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  if(!this->NoPolicyScope)
    {
    // Check CMP0011 to determine the policy scope type.
    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011))
      {
      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;
      }
    }

Brad King's avatar
Brad King committed
458
459
460
461
462
463
464
465
466
  // The included file cannot pop our policy scope.
  this->Makefile->PushPolicyBarrier();
}

//----------------------------------------------------------------------------
cmMakefile::IncludeScope::~IncludeScope()
{
  // Enforce matching policy scopes inside the included file.
  this->Makefile->PopPolicyBarrier(this->ReportError);
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501

  if(!this->NoPolicyScope)
    {
    // 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.
    if(this->CheckCMP0011 && this->Makefile->PolicyStack.back().empty())
      {
      this->CheckCMP0011 = false;
      }

    // 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.
    if(this->CheckCMP0011)
      {
      this->EnforceCMP0011();
      }
    }
}

//----------------------------------------------------------------------------
void cmMakefile::IncludeScope::EnforceCMP0011()
{
  // We check the setting of this policy again because the included
  // script might actually set this policy for its includer.
  cmPolicies* policies = this->Makefile->GetPolicies();
  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011))
    {
    case cmPolicies::WARN:
      // Warn because the user did not set this policy.
      {
502
      std::ostringstream w;
503
504
505
506
507
508
509
510
511
512
513
      w << policies->GetPolicyWarning(cmPolicies::CMP0011) << "\n"
        << "The included script\n  " << this->File << "\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());
      }
      break;
    case cmPolicies::REQUIRED_IF_USED:
    case cmPolicies::REQUIRED_ALWAYS:
      {
514
      std::ostringstream e;
515
516
517
518
519
520
521
522
523
524
525
526
527
      e << policies->GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
        << "The included script\n  " << this->File << "\n"
        << "affects policy settings, so it requires this policy to be set.";
      this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
      }
      break;
    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;
    }
Brad King's avatar
Brad King committed
528
529
}

530
531
bool cmMakefile::ProcessBuildsystemFile(const char* listfile)
{
532
  this->AddDefinition("CMAKE_PARENT_LIST_FILE", listfile);
533
  this->cmCurrentListFile = listfile;
534
  std::string curSrc = this->GetCurrentSourceDirectory();
535
  return this->ReadListFile(listfile, true,
536
                            curSrc == this->GetHomeDirectory());
537
538
}

539
540
bool cmMakefile::ReadDependentFile(const char* listfile, bool noPolicyScope)
{
541
  this->AddDefinition("CMAKE_PARENT_LIST_FILE", this->GetCurrentListFile());
542
  this->cmCurrentListFile =
543
    cmSystemTools::CollapseFullPath(listfile,
544
                                    this->GetCurrentSourceDirectory());
545
  return this->ReadListFile(this->cmCurrentListFile.c_str(),
546
547
548
                            noPolicyScope);
}

Brad King's avatar
Brad King committed
549
//----------------------------------------------------------------------------
550
// Parse the given CMakeLists.txt file executing all commands
Anonymous's avatar
Anonymous committed
551
//
552
bool cmMakefile::ReadListFile(const char* listfile,
553
554
                              bool noPolicyScope,
                              bool requireProjectCommand)
555
{
556
557
  std::string filenametoread =
    cmSystemTools::CollapseFullPath(listfile,
558
                                    this->GetCurrentSourceDirectory());
559

560
561
562
563
564
  std::string currentParentFile
      = this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
  std::string currentFile
    = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");

565
566
567
568
  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread.c_str());
  this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
                       cmSystemTools::GetFilenamePath(filenametoread).c_str());

569
  this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
570
571
572
573
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
  this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");

  this->ListFileStack.push_back(filenametoread);
574

575
  bool res = this->ReadListFileInternal(filenametoread.c_str(),
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
                                        noPolicyScope, requireProjectCommand);

  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");

  this->ListFileStack.pop_back();

  if (res)
    {
    // Check for unused variables
    this->CheckForUnusedVariables();
    }

  return res;
}

bool cmMakefile::ReadListFileInternal(const char* filenametoread,
                                      bool noPolicyScope,
                                      bool requireProjectCommand)
{
601
  cmListFile cacheFile;
602
  if( !cacheFile.ParseFile(filenametoread, requireProjectCommand, this) )
603
604
605
    {
    return false;
    }
606
  // add this list file to the list of dependencies
Ken Martin's avatar
Ken Martin committed
607
  this->ListFiles.push_back( filenametoread);
608
609
610
611

  // Enforce balanced blocks (if/endif, function/endfunction, etc.).
  {
  LexicalPushPop lexScope(this);
612
  IncludeScope incScope(this, filenametoread, noPolicyScope);
613
614

  // Run the parsed commands.
Ken Martin's avatar
Ken Martin committed
615
  const size_t numberFunctions = cacheFile.Functions.size();
616
  for(size_t i =0; i < numberFunctions; ++i)
617
    {
618
619
    cmExecutionStatus status;
    this->ExecuteCommand(cacheFile.Functions[i],status);
620
    if(cmSystemTools::GetFatalErrorOccured())
621
      {
622
623
      // Exit early due to error.
      lexScope.Quiet();
Brad King's avatar
Brad King committed
624
      incScope.Quiet();
625
626
627
628
629
      break;
      }
    if(status.GetReturnInvoked())
      {
      // Exit early due to return command.
630
      break;
631
      }
632
    }
633
  }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
634

635
636
  // If this is the directory-level CMakeLists.txt file then perform
  // some extra checks.
637
638
  if(this->ListFileStack.size() == 1)
    {
639
    this->EnforceDirectoryLevelRules();
640
641
    }

642
643
  return true;
}
644

645
//----------------------------------------------------------------------------
646
void cmMakefile::EnforceDirectoryLevelRules() const
647
648
649
650
{
  // Diagnose a violation of CMP0000 if necessary.
  if(this->CheckCMP0000)
    {
651
    std::ostringstream msg;
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
    msg << "No cmake_minimum_required command is present.  "
        << "A line of code such as\n"
        << "  cmake_minimum_required(VERSION "
        << cmVersion::GetMajorVersion() << "."
        << cmVersion::GetMinorVersion()
        << ")\n"
        << "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\".";
    switch (this->GetPolicyStatus(cmPolicies::CMP0000))
      {
      case cmPolicies::WARN:
        // Warn because the user did not provide a mimimum required
        // version.
Stephen Kelly's avatar
Stephen Kelly committed
668
        this->IssueMessage(cmake::AUTHOR_WARNING, msg.str());
669
670
671
672
673
674
675
676
      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.
Stephen Kelly's avatar
Stephen Kelly committed
677
        this->IssueMessage(cmake::FATAL_ERROR, msg.str());
678
679
680
681
682
        cmSystemTools::SetFatalErrorOccured();
        return;
      }
    }
}
683

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

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

701
  // give all the commands a chance to do something
702
  // after the file has been parsed before generation
703
704
  for(std::vector<cmCommand*>::iterator i = this->FinalPassCommands.begin();
      i != this->FinalPassCommands.end(); ++i)
705
706
    {
    (*i)->FinalPass();
707
    }
708

709
710
711
712
713
714
715
  //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

  //remove_if will move all items that don't have a valid file name to the
  //back of the vector
716
717
718
719
  std::vector<std::string>::iterator new_output_files_end = std::remove_if(
                                                     this->OutputFiles.begin(),
                                                     this->OutputFiles.end(),
                                                     file_not_persistent() );
720
  //we just have to erase all items at the back
721
722
723
724
725
726
727
728
729
  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
  std::vector<std::string>::iterator new_list_files_end = std::remove_if(
                                                   this->ListFiles.begin(),
                                                   this->ListFiles.end(),
                                                   file_not_persistent() );
730

731
  this->ListFiles.erase(new_list_files_end, this->ListFiles.end() );
732
733
}

Bill Hoffman's avatar
Bill Hoffman committed
734
// Generate the output file
735
void cmMakefile::ConfigureFinalPass()
736
737
{
  this->FinalPass();
738
739
  const char* oldValue
    = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
740
741
  if (oldValue && cmSystemTools::VersionCompare(
        cmSystemTools::OP_LESS, oldValue, "2.4"))
742
    {
743
744
745
746
747
748
    this->IssueMessage(
      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 "
      "use any CMake 2.8.x release or lower.");
749
    }
Ken Martin's avatar
Ken Martin committed
750
751
  for (cmTargets::iterator l = this->Targets.begin();
       l != this->Targets.end(); l++)
752
    {
753
754
755
756
    if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY)
      {
      continue;
      }
757
    l->second.FinishConfigure();
758
    }
759
760
}

761
762
//----------------------------------------------------------------------------
void
763
cmMakefile::AddCustomCommandToTarget(const std::string& target,
764
                                   const std::vector<std::string>& byproducts,
765
766
767
                                     const std::vector<std::string>& depends,
                                     const cmCustomCommandLines& commandLines,
                                     cmTarget::CustomCommandType type,
768
                                     const char* comment,
769
                                     const char* workingDir,
770
                                     bool escapeOldStyle,
771
                                     bool uses_terminal)
772
{
773
  // Find the target to which to add the custom command.
Ken Martin's avatar
Ken Martin committed
774
  cmTargets::iterator ti = this->Targets.find(target);
775
776

  if(ti == this->Targets.end())
777
    {
778
779
    cmake::MessageType messageType = cmake::AUTHOR_WARNING;
    bool issueMessage = false;
780
    std::ostringstream e;
781
    switch(this->GetPolicyStatus(cmPolicies::CMP0040))
Brad King's avatar
Brad King committed
782
      {
783
      case cmPolicies::WARN:
784
785
        e << (this->GetPolicies()
          ->GetPolicyWarning(cmPolicies::CMP0040)) << "\n";
786
787
788
789
790
791
792
793
        issueMessage = true;
      case cmPolicies::OLD:
        break;
      case cmPolicies::NEW:
      case cmPolicies::REQUIRED_IF_USED:
      case cmPolicies::REQUIRED_ALWAYS:
        issueMessage = true;
        messageType = cmake::FATAL_ERROR;
Brad King's avatar
Brad King committed
794
      }
795
796

    if(issueMessage)
797
      {
798
      e << "The target name \"" << target << "\" is unknown in this context.";
Stephen Kelly's avatar
Stephen Kelly committed
799
      IssueMessage(messageType, e.str());
800
      }
801
802
803
804
805
806

      return;
    }

  if(ti->second.GetType() == cmTarget::OBJECT_LIBRARY)
    {
807
    std::ostringstream e;
808
809
810
811
812
    e << "Target \"" << target << "\" is an OBJECT library "
      "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
    }
813
814
  if(ti->second.GetType() == cmTarget::INTERFACE_LIBRARY)
    {
815
    std::ostringstream e;
816
817
818
819
820
    e << "Target \"" << target << "\" is an INTERFACE library "
      "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
    this->IssueMessage(cmake::FATAL_ERROR, e.str());
    return;
    }
821
822
823
824
825
826
827
828
829
830
831

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

832
833
  // Add the command to the appropriate build step for the target.
  std::vector<std::string> no_output;
834
  cmCustomCommand cc(this, no_output, byproducts, depends,
835
836
837
                     commandLines, comment, workingDir);
  cc.SetEscapeOldStyle(escapeOldStyle);
  cc.SetEscapeAllowMakeVars(true);
838
  cc.SetUsesTerminal(uses_terminal);
839
840
841
842
843
844
845
846
847
848
849
  switch(type)
    {
    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;
850
851
852
    }
}

853
//----------------------------------------------------------------------------
854
cmSourceFile*
855
cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
856
                                  const std::vector<std::string>& byproducts,
857
                                     const std::vector<std::string>& depends,
858
                                     const std::string& main_dependency,
859
860
                                     const cmCustomCommandLines& commandLines,
                                     const char* comment,
861
                                     const char* workingDir,
862
                                     bool replace,
863
864
                                     bool escapeOldStyle,
                                     bool uses_terminal)
865
{
866
867
868
869
  // Make sure there is at least one output.
  if(outputs.empty())
    {
    cmSystemTools::Error("Attempt to add a custom rule with no output!");
870
    return 0;
871
872
    }

873
874
875
876
877
878
879
  // Validate custom commands.  TODO: More strict?
  for(cmCustomCommandLines::const_iterator i=commandLines.begin();
      i != commandLines.end(); ++i)
    {
    cmCustomCommandLine const& cl = *i;
    if(!cl.empty() && !cl[0].empty() && cl[0][0] == '"')
      {
880
      std::ostringstream e;
881
882
      e << "COMMAND may not contain literal quotes:\n  " << cl[0] << "\n";
      this->IssueMessage(cmake::FATAL_ERROR, e.str());
883
      return 0;
884
885
886
      }
    }

887
888
  // Choose a source file on which to store the custom command.
  cmSourceFile* file = 0;
889
  if(!commandLines.empty() && !main_dependency.empty())
890
891
892
893
894
    {
    // The main dependency was specified.  Use it unless a different
    // custom command already used it.
    file = this->GetSource(main_dependency);
    if(file && file->GetCustomCommand() && !replace)
895
      {
896
897
      // The main dependency already has a custom command.
      if(commandLines == file->GetCustomCommand()->GetCommandLines())
898
        {
899
900
        // The existing custom command is identical.  Silently ignore
        // the duplicate.
901
        return file;
902
903
904
        }
      else
        {
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
        std::ostringstream e;
        cmake::MessageType messageType = cmake::AUTHOR_WARNING;
        bool issueMessage = false;

        switch(this->GetPolicyStatus(cmPolicies::CMP0057))
          {
          case cmPolicies::WARN:
            e << (this->GetPolicies()->
              GetPolicyWarning(cmPolicies::CMP0057)) << "\n";
            issueMessage = true;
          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 << "\"" << main_dependency << "\" can only be specified as a "
            "custom command MAIN_DEPENDENCY once.";
          IssueMessage(messageType, e.str());
          }

932
933
934
        // The existing custom command is different.  We need to
        // generate a rule file for this new command.
        file = 0;
935
        }
936
      }
937
    else if (!file)
938
      {
939
      file = this->CreateSource(main_dependency);
940
941
942
      }
    }

943
944
  // Generate a rule file if the main dependency is not available.
  if(!file)
945
    {
946
947
    cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();

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

951
    // Check if the rule file already exists.
Stephen Kelly's avatar
Stephen Kelly committed
952
    file = this->GetSource(outName);
953
    if(file && file->GetCustomCommand() && !replace)
954
      {
955
956
      // The rule file already exists.
      if(commandLines != file->GetCustomCommand()->GetCommandLines())
957
        {
958
        cmSystemTools::Error("Attempt to add a custom rule to output \"",
959
960
                             outName.c_str(),
                             "\" which already has a custom rule.");