cmGlobalGenerator.cxx 33.1 KB
Newer Older
Ken Martin's avatar
Ken Martin committed
1
2
/*=========================================================================

3
  Program:   CMake - Cross-Platform Makefile Generator
Ken Martin's avatar
Ken Martin committed
4
5
6
7
8
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

9
10
  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
Ken Martin's avatar
Ken Martin committed
11
12
13
14
15
16
17
18
19
20

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmake.h"
#include "cmMakefile.h"
21

22
#include <stdlib.h> // required for atof
Ken Martin's avatar
Ken Martin committed
23

24
25
26
27
#if defined(_WIN32) && !defined(__CYGWIN__) 
#include <windows.h>
#endif

28
29
#include <assert.h>

Andy Cedilnik's avatar
Andy Cedilnik committed
30
31
int cmGlobalGenerator::s_TryCompileTimeout = 0;

Ken Martin's avatar
updates    
Ken Martin committed
32
33
cmGlobalGenerator::cmGlobalGenerator()
{
34
35
  // by default use the native paths
  m_ForceUnixPaths = false;
Ken Martin's avatar
updates    
Ken Martin committed
36
37
}

Ken Martin's avatar
Ken Martin committed
38
cmGlobalGenerator::~cmGlobalGenerator()
39
{ 
Ken Martin's avatar
Ken Martin committed
40
  // Delete any existing cmLocalGenerators
Ken Martin's avatar
Ken Martin committed
41
  unsigned int i;
Ken Martin's avatar
Ken Martin committed
42
43
44
45
46
47
48
  for (i = 0; i < m_LocalGenerators.size(); ++i)
    {
    delete m_LocalGenerators[i];
    }
  m_LocalGenerators.clear();
}

49
50
// Find the make program for the generator, required for try compiles
void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
51
52
53
54
55
56
57
58
59
60
{
  if(m_FindMakeProgramFile.size() == 0)
    {
    cmSystemTools::Error(
      "Generator implementation error, "
      "all generators must specify m_FindMakeProgramFile");
    }
  if(!mf->GetDefinition("CMAKE_MAKE_PROGRAM")
     || cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM")))
    {
61
62
63
64
65
    std::string setMakeProgram = mf->GetModulesFile(m_FindMakeProgramFile.c_str());
    if(setMakeProgram.size())
      {
      mf->ReadListFile(0, setMakeProgram.c_str());
      }
66
67
68
69
    } 
  if(!mf->GetDefinition("CMAKE_MAKE_PROGRAM")
     || cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM")))
    {
70
71
72
73
74
    cmOStringStream err;
    err << "CMake was unable to find a build program corresponding to \""
        << this->GetName() << "\".  CMAKE_MAKE_PROGRAM is not set.  You "
        << "probably need to select a different build tool.";
    cmSystemTools::Error(err.str().c_str());
75
    cmSystemTools::SetFatalErrorOccured();
76
77
    return;
    }
78
  std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
79
80
81
  // if there are spaces in the make program use short path
  // but do not short path the actual program name, as
  // this can cause trouble with VSExpress
82
83
  if(makeProgram.find(' ') != makeProgram.npos)
    {
84
85
86
87
88
    std::string dir;
    std::string file;
    cmSystemTools::SplitProgramPath(makeProgram.c_str(),
                                    dir, file);
    std::string saveFile = file;
89
    cmSystemTools::GetShortPath(makeProgram.c_str(), makeProgram);
90
91
92
93
94
    cmSystemTools::SplitProgramPath(makeProgram.c_str(),
                                    dir, file);
    makeProgram = dir;
    makeProgram += "/";
    makeProgram += saveFile;
95
96
97
98
    this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", makeProgram.c_str(),
                                            "make program",
                                            cmCacheManager::FILEPATH);
    }
99
100
101
102
  
}

// enable the given language
103
void cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
104
105
                                       cmMakefile *mf)
{  
106
  if(languages.size() == 0)
107
108
109
110
111
    {
    cmSystemTools::Error("EnableLanguage must have a lang specified!");
    cmSystemTools::SetFatalErrorOccured();
    return;
    }
112
113

  mf->AddDefinition("RUN_CONFIGURE", true);
114
  bool needTestLanguage = false;
115
  std::string rootBin = mf->GetHomeOutputDirectory();
116
117
118
  // If the configuration files path has been set,
  // then we are in a try compile and need to copy the enable language
  // files into the try compile directory
119
120
  if(m_ConfiguredFilesPath.size())
    {
121
122
123
124
125
126
127
128
129
    std::string src = m_ConfiguredFilesPath;
    src += "/CMakeSystem.cmake";
    std::string dst = rootBin;
    dst += "/CMakeSystem.cmake";
    cmSystemTools::CopyFileIfDifferent(src.c_str(), dst.c_str());
    for(std::vector<std::string>::const_iterator l = languages.begin();
        l != languages.end(); ++l)
      {
      const char* lang = l->c_str();
Ken Martin's avatar
Ken Martin committed
130
131
132
133
134
135
136
137
      std::string src2 = m_ConfiguredFilesPath;
      src2 += "/CMake";
      src2 += lang;
      src2 += "Compiler.cmake";
      std::string dst2 = rootBin;
      dst2 += "/CMake";
      dst2 += lang;
      dst2 += "Compiler.cmake";
138
139
140
141
142
143
144
145
146
      cmSystemTools::CopyFileIfDifferent(src2.c_str(), dst2.c_str()); 
      src2 = m_ConfiguredFilesPath;
      src2 += "/CMake";
      src2 += lang;
      src2 += "Platform.cmake";
      dst2 = rootBin;
      dst2 += "/CMake";
      dst2 += lang;
      dst2 += "Platform.cmake";
Ken Martin's avatar
Ken Martin committed
147
      cmSystemTools::CopyFileIfDifferent(src2.c_str(), dst2.c_str());
148
      }
149
150
    rootBin = m_ConfiguredFilesPath;
    }
151
152
153
154

  // **** Step 1, find and make sure CMAKE_MAKE_PROGRAM is defined
  this->FindMakeProgram(mf);

155
156
157
158
159
160
161
162
163
164
  // try and load the CMakeSystem.cmake if it is there
  std::string fpath = rootBin;
  if(!mf->GetDefinition("CMAKE_SYSTEM_LOADED"))
    {
    fpath += "/CMakeSystem.cmake";
    if(cmSystemTools::FileExists(fpath.c_str()))
      {
      mf->ReadListFile(0,fpath.c_str());
      }
    }
165
166
  // **** Step 2, Load the CMakeDetermineSystem.cmake file and find out
  // what platform we are running on
167
  if (!mf->GetDefinition("CMAKE_SYSTEM_NAME"))
Andy Cedilnik's avatar
Andy Cedilnik committed
168
    {
169
170
171
172
173
174
175
176
177
178
179
#if defined(_WIN32) && !defined(__CYGWIN__) 
    /* Windows version number data.  */
    OSVERSIONINFO osvi;
    ZeroMemory(&osvi, sizeof(osvi));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx (&osvi);
    cmOStringStream windowsVersionString;
    windowsVersionString << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
    windowsVersionString.str();
    mf->AddDefinition("CMAKE_SYSTEM_VERSION", windowsVersionString.str().c_str());
#endif
Andy Cedilnik's avatar
Andy Cedilnik committed
180
    // Read the DetermineSystem file
181
    std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
Andy Cedilnik's avatar
Andy Cedilnik committed
182
183
    mf->ReadListFile(0, systemFile.c_str());
    }
184
185
  // **** Step 3, load the CMakeSystem.cmake from the binary directory
  // this file is configured by the CMakeDetermineSystem.cmake file
186
  fpath = rootBin;
187
188
189
190
191
  if(!mf->GetDefinition("CMAKE_SYSTEM_LOADED"))
    {
    fpath += "/CMakeSystem.cmake";
    mf->ReadListFile(0,fpath.c_str());
    }
192
193
194
195
196
197
198
  // **** Step 4, foreach language 
  // load the CMakeDetermine(LANG)Compiler.cmake file to find
  // the compiler 
  for(std::vector<std::string>::const_iterator l = languages.begin();
      l != languages.end(); ++l)
    {
    const char* lang = l->c_str();
199
    if(!this->GetLanguageEnabled(lang) )
200
201
202
203
204
205
206
207
      {  
      if (m_CMakeInstance->GetIsInTryCompile())
        {
        cmSystemTools::Error("This should not have happen. "
                             "If you see this message, you are probably using a "
                             "broken CMakeLists.txt file or a problematic release of "
                             "CMake");
        }
208
209
210
211
212
213
214
215
216

      // If the existing build tree was already configured with this
      // version of CMake then try to load the configured file first
      // to avoid duplicate compiler tests.
      unsigned int cacheMajor = mf->GetCacheMajorVersion();
      unsigned int cacheMinor = mf->GetCacheMinorVersion();
      unsigned int selfMajor = cmMakefile::GetMajorVersion();
      unsigned int selfMinor = cmMakefile::GetMinorVersion();
      if(selfMajor == cacheMajor && selfMinor == cacheMinor)
217
        {
218
219
220
221
        std::string loadedLang = "CMAKE_";
        loadedLang +=  lang;
        loadedLang += "_COMPILER_LOADED";
        if(!mf->GetDefinition(loadedLang.c_str()))
222
          {
223
224
225
226
227
          fpath = rootBin;
          fpath += "/CMake";
          fpath += lang;
          fpath += "Compiler.cmake";
          if(cmSystemTools::FileExists(fpath.c_str()))
228
            {
229
230
231
232
233
            if(!mf->ReadListFile(0,fpath.c_str()))
              {
              cmSystemTools::Error("Could not find cmake module file:", fpath.c_str());
              }
            this->SetLanguageEnabled(lang, mf);
234
235
236
237
            }
          }
        }
      
238
239
      needTestLanguage = true; // must test a language after finding it
      // read determine LANG compiler
240
241
242
243
      std::string determineCompiler = "CMakeDetermine";
      determineCompiler += lang;
      determineCompiler += "Compiler.cmake";
      std::string determineFile = mf->GetModulesFile(determineCompiler.c_str());
244
245
246
247
      if(!mf->ReadListFile(0,determineFile.c_str()))
        {
        cmSystemTools::Error("Could not find cmake module file:", determineFile.c_str());
        }
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
      // Some generators like visual studio should not use the env variables
      // So the global generator can specify that in this variable
      if(!mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV"))
        {
        // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER into the
        // environment, in case user scripts want to run configure, or sub cmakes
        std::string compilerName = "CMAKE_";
        compilerName += lang;
        compilerName += "_COMPILER";
        std::string compilerEnv = "CMAKE_";
        compilerEnv += lang;
        compilerEnv += "_COMPILER_ENV_VAR";
        std::string envVar = mf->GetRequiredDefinition(compilerEnv.c_str());
        std::string envVarValue = mf->GetRequiredDefinition(compilerName.c_str());
        std::string env = envVar;
        env += "=";
        env += envVarValue;
        cmSystemTools::PutEnv(env.c_str());
        }
267
      }
268
    
269
270
271
272
273
274
275
276
277
    // **** Step 5, Load the configured language compiler file, if not loaded.
    // look to see if CMAKE_(LANG)_COMPILER_LOADED is set, 
    // if not then load the CMake(LANG)Compiler.cmake file from the
    // binary tree, this is a configured file provided by
    // CMakeDetermine(LANG)Compiler.cmake
    std::string loadedLang = "CMAKE_";
    loadedLang +=  lang;
    loadedLang += "_COMPILER_LOADED";
    if(!mf->GetDefinition(loadedLang.c_str()))
278
      {
279
280
281
282
283
284
285
286
      fpath = rootBin;
      fpath += "/CMake";
      fpath += lang;
      fpath += "Compiler.cmake";
      if(!mf->ReadListFile(0,fpath.c_str()))
        {
        cmSystemTools::Error("Could not find cmake module file:", fpath.c_str());
        }
287
      this->SetLanguageEnabled(lang, mf);
288
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
289
    }
290
  
291
292
  // **** Step 6, Load the system specific information if not yet loaded
  if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED"))
Bill Hoffman's avatar
Bill Hoffman committed
293
    {
294
295
296
297
298
    fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake");
    if(!mf->ReadListFile(0,fpath.c_str()))
      {
      cmSystemTools::Error("Could not find cmake module file:", fpath.c_str());
      }
Bill Hoffman's avatar
Bill Hoffman committed
299
    }
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  for(std::vector<std::string>::const_iterator l = languages.begin();
      l != languages.end(); ++l)
    {
    const char* lang = l->c_str();
    std::string langLoadedVar = "CMAKE_";
    langLoadedVar += lang;
    langLoadedVar += "_INFORMATION_LOADED";
    if (!mf->GetDefinition(langLoadedVar.c_str()))
      { 
      fpath = "CMake";
      fpath +=  lang;
      fpath += "Information.cmake";
      fpath = mf->GetModulesFile(fpath.c_str());
      if(!mf->ReadListFile(0,fpath.c_str()))
        {
        cmSystemTools::Error("Could not find cmake module file:", fpath.c_str());
        }
317
      }
318
319
320
    // **** Step 7, Test the compiler for the language just setup
    // At this point we should have enough info for a try compile
    // which is used in the backward stuff
321
    if(needTestLanguage)
322
      {
323
      if (!m_CMakeInstance->GetIsInTryCompile())
324
        {
325
326
327
328
329
        std::string testLang = "CMakeTest";
        testLang += lang;
        testLang += "Compiler.cmake";
        std::string ifpath = mf->GetModulesFile(testLang.c_str());
        if(!mf->ReadListFile(0,ifpath.c_str()))
330
          {
331
332
333
334
335
336
337
338
339
340
          cmSystemTools::Error("Could not find cmake module file:", ifpath.c_str());
          }
        // **** Step 8, load backwards compatibility stuff for C and CXX
        // for old versions of CMake ListFiles C and CXX had some
        // backwards compatibility files they have to load
        const char* versionValue
          = mf->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
        if (atof(versionValue) <= 1.4)
          {
          if(strcmp(lang, "C") == 0)
341
            {
342
343
            ifpath =  mf->GetModulesFile("CMakeBackwardCompatibilityC.cmake");
            mf->ReadListFile(0,ifpath.c_str()); 
344
            }
345
          if(strcmp(lang, "CXX") == 0)
346
            {
347
348
            ifpath =  mf->GetModulesFile("CMakeBackwardCompatibilityCXX.cmake");
            mf->ReadListFile(0,ifpath.c_str()); 
349
            }
350
          
351
352
353
354
355
356
          }
        }
      }
    }
}

357
358
const char* cmGlobalGenerator::GetLanguageOutputExtensionForLanguage(const char* lang)
{
359
360
361
362
  if(!lang) 
    {
    return "";
    }
363
364
365
366
367
368
369
370
371
  if(m_LanguageToOutputExtension.count(lang) > 0)
    {
    return m_LanguageToOutputExtension[lang].c_str();
    }
  return "";
}

const char* cmGlobalGenerator::GetLanguageOutputExtensionFromExtension(const char* ext)
{
372
373
374
375
  if(!ext)
    {
    return "";
    }
376
  const char* lang = this->GetLanguageFromExtension(ext);
377
378
379
380
381
382
383
384
385
386
  if(!lang || *lang == 0)
    {
    // if no language is found then check to see if it is already an
    // ouput extension for some language.  In that case it should be ignored
    // and in this map, so it will not be compiled but will just be used.
    if(m_OutputExtensions.count(ext))
      {
      return ext;
      }
    }
387
388
389
390
  return this->GetLanguageOutputExtensionForLanguage(lang);
}


391
392
const char* cmGlobalGenerator::GetLanguageFromExtension(const char* ext)
{
393
394
395
396
397
398
399
  // if there is an extension and it starts with . then
  // move past the . because the extensions are not stored with a .
  // in the map
  if(ext && *ext == '.')
    {
    ++ext;
    }
400
401
402
403
404
405
  if(m_ExtensionToLanguage.count(ext) > 0)
    {
    return m_ExtensionToLanguage[ext].c_str();
    }
  return 0;
}
406

407
void cmGlobalGenerator::SetLanguageEnabled(const char* l, cmMakefile* mf)
Ken Martin's avatar
Ken Martin committed
408
{
409
410
411
412
  if(m_LanguageEnabled.count(l) > 0)
    {
    return;
    }
413
414
415
416
417
418
  std::string outputExtensionVar = std::string("CMAKE_") + 
    std::string(l) + std::string("_OUTPUT_EXTENSION");
  const char* outputExtension = mf->GetDefinition(outputExtensionVar.c_str());
  if(outputExtension)
    {
    m_LanguageToOutputExtension[l] = outputExtension;
419
420
421
422
423
    m_OutputExtensions[outputExtension] = outputExtension;
    if(outputExtension[0] == '.')
      {
      m_OutputExtensions[outputExtension+1] = outputExtension+1;
      }
424
425
426
427
428
429
430
431
432
433
434
    }
  
  std::string linkerPrefVar = std::string("CMAKE_") + 
    std::string(l) + std::string("_LINKER_PREFERENCE");
  const char* linkerPref = mf->GetDefinition(linkerPrefVar.c_str());
  if(!linkerPref)
    {
    linkerPref = "None";
    }
  m_LanguageToLinkerPreference[l] = linkerPref;
  
435
436
  std::string extensionsVar = std::string("CMAKE_") + 
    std::string(l) + std::string("_SOURCE_FILE_EXTENSIONS");
437
438
439
  std::string ignoreExtensionsVar = std::string("CMAKE_") + 
    std::string(l) + std::string("_IGNORE_EXTENSIONS");
  std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar.c_str());
440
441
442
443
444
445
446
447
  std::string exts = mf->GetSafeDefinition(extensionsVar.c_str());
  std::vector<std::string> extensionList;
  cmSystemTools::ExpandListArgument(exts, extensionList);
  for(std::vector<std::string>::iterator i = extensionList.begin();
      i != extensionList.end(); ++i)
    {
    m_ExtensionToLanguage[*i] = l;
    }
448
449
450
451
452
453
  cmSystemTools::ExpandListArgument(ignoreExts, extensionList);
  for(std::vector<std::string>::iterator i = extensionList.begin();
      i != extensionList.end(); ++i)
    {
    m_IgnoreExtensions[*i] = true;
    }
Ken Martin's avatar
Ken Martin committed
454
  m_LanguageEnabled[l] = true;
455

Ken Martin's avatar
Ken Martin committed
456
}
457
458
bool cmGlobalGenerator::IgnoreFile(const char* l)
{
459
460
461
462
  if(this->GetLanguageFromExtension(l))
    {
    return false;
    }
463
464
  return (m_IgnoreExtensions.count(l) > 0);
}
Ken Martin's avatar
Ken Martin committed
465
466
467
468
469
470
471
472
473
474
475
476
477
478

bool cmGlobalGenerator::GetLanguageEnabled(const char* l)
{
  return (m_LanguageEnabled.count(l) > 0);
}

void cmGlobalGenerator::ClearEnabledLanguages()
{
  m_LanguageEnabled.clear();
}

void cmGlobalGenerator::Configure()
{
  // Delete any existing cmLocalGenerators
Ken Martin's avatar
Ken Martin committed
479
  unsigned int i;
Ken Martin's avatar
Ken Martin committed
480
481
482
483
484
  for (i = 0; i < m_LocalGenerators.size(); ++i)
    {
    delete m_LocalGenerators[i];
    }
  m_LocalGenerators.clear();
485
486
487
488

  // Setup relative path generation.
  this->ConfigureRelativePaths();

Ken Martin's avatar
Ken Martin committed
489
490
491
492
493
  // start with this directory
  cmLocalGenerator *lg = this->CreateLocalGenerator();
  m_LocalGenerators.push_back(lg);

  // set the Start directories
494
495
496
497
  lg->GetMakefile()->SetStartDirectory
    (m_CMakeInstance->GetStartDirectory());
  lg->GetMakefile()->SetStartOutputDirectory
    (m_CMakeInstance->GetStartOutputDirectory());
Ken Martin's avatar
updates    
Ken Martin committed
498
  lg->GetMakefile()->MakeStartDirectoriesCurrent();
Ken Martin's avatar
Ken Martin committed
499
500
  
  // now do it
501
502
503
504
505
  lg->Configure();
  
  // update the cache entry for the number of local generators, this is used
  // for progress
  char num[100];
Ken Martin's avatar
Ken Martin committed
506
  sprintf(num,"%d",static_cast<int>(m_LocalGenerators.size()));
507
508
509
510
511
  this->GetCMakeInstance()->AddCacheEntry
    ("CMAKE_NUMBER_OF_LOCAL_GENERATORS", num,
     "number of local generators",
                                          cmCacheManager::INTERNAL);
  
512
  std::set<cmStdString> notFoundMap;
Ken Martin's avatar
Ken Martin committed
513
  // after it is all done do a ConfigureFinalPass
Bill Hoffman's avatar
Bill Hoffman committed
514
  cmCacheManager* manager = 0;
Ken Martin's avatar
Ken Martin committed
515
516
  for (i = 0; i < m_LocalGenerators.size(); ++i)
    {
Bill Hoffman's avatar
Bill Hoffman committed
517
    manager = m_LocalGenerators[i]->GetMakefile()->GetCacheManager();
Ken Martin's avatar
Ken Martin committed
518
    m_LocalGenerators[i]->ConfigureFinalPass();
519
520
    cmTargets const& targets = 
      m_LocalGenerators[i]->GetMakefile()->GetTargets(); 
Bill Hoffman's avatar
Bill Hoffman committed
521
522
523
524
525
526
527
    for (cmTargets::const_iterator l = targets.begin();
         l != targets.end(); l++)
      {
      cmTarget::LinkLibraries libs = l->second.GetLinkLibraries();
      for(cmTarget::LinkLibraries::iterator lib = libs.begin();
          lib != libs.end(); ++lib)
        {
528
529
        if(lib->first.size() > 9 && 
           cmSystemTools::IsNOTFOUND(lib->first.c_str()))
Bill Hoffman's avatar
Bill Hoffman committed
530
          {
Bill Hoffman's avatar
Bill Hoffman committed
531
532
          std::string varName = lib->first.substr(0, lib->first.size()-9);
          notFoundMap.insert(varName);
Bill Hoffman's avatar
Bill Hoffman committed
533
534
535
536
537
538
539
540
          }
        }
      std::vector<std::string>& incs = 
        m_LocalGenerators[i]->GetMakefile()->GetIncludeDirectories();
      
      for( std::vector<std::string>::iterator lib = incs.begin();
           lib != incs.end(); ++lib)
        {
541
542
        if(lib->size() > 9 && 
           cmSystemTools::IsNOTFOUND(lib->c_str()))
Bill Hoffman's avatar
Bill Hoffman committed
543
          {
Bill Hoffman's avatar
Bill Hoffman committed
544
545
          std::string varName = lib->substr(0, lib->size()-9); 
          notFoundMap.insert(varName);
Bill Hoffman's avatar
Bill Hoffman committed
546
547
548
          }
        }
      m_CMakeInstance->UpdateProgress("Configuring", 
549
                                      0.9f+0.1f*(i+1.0f)/m_LocalGenerators.size());
550
      m_LocalGenerators[i]->GetMakefile()->CheckInfiniteLoops();
Bill Hoffman's avatar
Bill Hoffman committed
551
552
553
554
555
556
      }
    }

  if(notFoundMap.size())
    {
    std::string notFoundVars;
557
    for(std::set<cmStdString>::iterator ii = notFoundMap.begin();
Bill Hoffman's avatar
Bill Hoffman committed
558
        ii != notFoundMap.end(); ++ii)
Bill Hoffman's avatar
Bill Hoffman committed
559
      { 
Bill Hoffman's avatar
Bill Hoffman committed
560
      notFoundVars += *ii;
Bill Hoffman's avatar
Bill Hoffman committed
561
562
563
      if(manager)
        {
        cmCacheManager::CacheIterator it = 
Bill Hoffman's avatar
Bill Hoffman committed
564
          manager->GetCacheIterator(ii->c_str());
Bill Hoffman's avatar
Bill Hoffman committed
565
566
567
568
569
570
571
572
573
574
575
        if(it.GetPropertyAsBool("ADVANCED"))
          {
          notFoundVars += " (ADVANCED)";
          }
        }
      notFoundVars += "\n";
      }
    cmSystemTools::Error("This project requires some variables to be set,\n"
                         "and cmake can not find them.\n"
                         "Please set the following variables:\n",
                         notFoundVars.c_str());
Ken Martin's avatar
Ken Martin committed
576
    }
577
578
579
  // at this point m_LocalGenerators has been filled,
  // so create the map from project name to vector of local generators
  this->FillProjectMap();
Andy Cedilnik's avatar
Andy Cedilnik committed
580
581
582
583
  if ( !m_CMakeInstance->GetScriptMode() )
    {
    m_CMakeInstance->UpdateProgress("Configuring done", -1);
    }
Ken Martin's avatar
Ken Martin committed
584
585
586
587
588
}

void cmGlobalGenerator::Generate()
{
  // For each existing cmLocalGenerator
Ken Martin's avatar
Ken Martin committed
589
  unsigned int i;
Ken Martin's avatar
Ken Martin committed
590
591
  for (i = 0; i < m_LocalGenerators.size(); ++i)
    {
592
    m_LocalGenerators[i]->Generate();
593
    m_LocalGenerators[i]->GenerateInstallRules();
Ken Martin's avatar
Ken Martin committed
594
595
    m_CMakeInstance->UpdateProgress("Generating", 
                                    (i+1.0f)/m_LocalGenerators.size());
Ken Martin's avatar
Ken Martin committed
596
    }
597
  m_CMakeInstance->UpdateProgress("Generating done", -1);
Ken Martin's avatar
Ken Martin committed
598
599
}

600
601
602
603
int cmGlobalGenerator::TryCompile(const char *srcdir, const char *bindir, 
                                  const char *projectName, 
                                  const char *target,
                                  std::string *output, cmMakefile *mf)
Ken Martin's avatar
Ken Martin committed
604
605
606
607
608
609
610
611
612
{
  std::string makeCommand = 
    m_CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM");
  if(makeCommand.size() == 0)
    {
    cmSystemTools::Error(
      "Generator cannot find the appropriate make command.");
    return 1;
    }
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640

  std::string newTarget;
  if (target && strlen(target))
    {
    newTarget += target;
#if 0
#if defined(_WIN32) || defined(__CYGWIN__)
    std::string tmp = target;
    // if the target does not already end in . something 
    // then assume .exe
    if(tmp.size() < 4 || tmp[tmp.size()-4] != '.')
      {
      newTarget += ".exe";
      }
#endif // WIN32
#endif
    }
  const char* config = mf->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
  return this->Build(srcdir,bindir,projectName,
                     newTarget.c_str(),
                     output,makeCommand.c_str(),config,false);
}
  
int cmGlobalGenerator::Build(
  const char *, const char *bindir, 
  const char *, const char *target,
  std::string *output, 
  const char *makeCommandCSTR,
Ken Martin's avatar
Ken Martin committed
641
  const char * /* config */,
642
643
644
645
646
647
  bool clean)
{
  *output += "\nTesting TryCompileWithoutMakefile\n";
  
  // now build the test
  std::string makeCommand = makeCommandCSTR;
Ken Martin's avatar
Ken Martin committed
648
649
650
651
652
653
654
  makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());

  /**
   * Run an executable command and put the stdout in output.
   */
  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
  cmSystemTools::ChangeDirectory(bindir);
655
656
657
658
659
660
661

  // Since we have full control over the invocation of nmake, let us
  // make it quiet.
  if ( strcmp(this->GetName(), "NMake Makefiles") == 0 )
    {
    makeCommand += " /NOLOGO ";
    }
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686

  int retVal;
  int timeout = cmGlobalGenerator::s_TryCompileTimeout;
  bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
  cmSystemTools::SetRunCommandHideConsole(true);

  // should we do a clean first?
  if (clean)
    {
    std::string cleanCommand = makeCommand + " clean";
    if (!cmSystemTools::RunSingleCommand(cleanCommand.c_str(), output, 
                                         &retVal, 0, false, timeout))
      {
      cmSystemTools::SetRunCommandHideConsole(hideconsole);
      cmSystemTools::Error("Generator: execution of make clean failed.");
      if (output)
        {
        *output += "\nGenerator: execution of make clean failed.\n";
        }
      
      // return to the original directory
      cmSystemTools::ChangeDirectory(cwd.c_str());
      return 1;
      }
    }
Ken Martin's avatar
Ken Martin committed
687
688
  
  // now build
689
  if (target && strlen(target))
Ken Martin's avatar
Ken Martin committed
690
691
692
693
694
695
696
697
    {
    makeCommand += " ";
    makeCommand += target;
    }
  else
    {
    makeCommand += " all";
    }
698

Andy Cedilnik's avatar
Andy Cedilnik committed
699
  if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output, 
700
                                       &retVal, 0, false, timeout))
Ken Martin's avatar
Ken Martin committed
701
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
702
    cmSystemTools::SetRunCommandHideConsole(hideconsole);
Ken Martin's avatar
Ken Martin committed
703
    cmSystemTools::Error("Generator: execution of make failed.");
704
705
706
707
708
    if (output)
      {
      *output += "\nGenerator: execution of make failed.\n";
      }
    
Ken Martin's avatar
Ken Martin committed
709
710
711
712
    // return to the original directory
    cmSystemTools::ChangeDirectory(cwd.c_str());
    return 1;
    }
713

Andy Cedilnik's avatar
Andy Cedilnik committed
714
  cmSystemTools::SetRunCommandHideConsole(hideconsole);
715
716
717
718
719
720
721
722
723
  
  // The SGI MipsPro 7.3 compiler does not return an error code when
  // the source has a #error in it!  This is a work-around for such
  // compilers.
  if((retVal == 0) && (output->find("#error") != std::string::npos))
    {
    retVal = 1;
    }
  
Ken Martin's avatar
Ken Martin committed
724
  cmSystemTools::ChangeDirectory(cwd.c_str());
Ken Martin's avatar
Ken Martin committed
725
  return retVal;
Ken Martin's avatar
Ken Martin committed
726
727
}

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg)
{
  m_LocalGenerators.push_back(lg); 

  // update progress
  // estimate how many lg there will be
  const char *numGenC = 
    m_CMakeInstance->GetCacheManager()->GetCacheValue
    ("CMAKE_NUMBER_OF_LOCAL_GENERATORS");
  
  if (!numGenC)
    {
    return;
    }
  
  int numGen = atoi(numGenC);
  float prog = 0.9f*m_LocalGenerators.size()/numGen;
  if (prog > 0.9f)
    {
    prog = 0.9f;
    }
  m_CMakeInstance->UpdateProgress("Configuring", prog);
}

Ken Martin's avatar
Ken Martin committed
752
753
754
755
756
757
cmLocalGenerator *cmGlobalGenerator::CreateLocalGenerator()
{
  cmLocalGenerator *lg = new cmLocalGenerator;
  lg->SetGlobalGenerator(this);
  return lg;
}
758

759
void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator *gen )
760
{
761
762
763
764
765
766
767
  this->SetConfiguredFilesPath(
    gen->GetCMakeInstance()->GetHomeOutputDirectory());
  const char* make =
    gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
  this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", make,
                                          "make program",
                                          cmCacheManager::FILEPATH);
768
769
770
  // copy the enabled languages
  this->m_LanguageEnabled = gen->m_LanguageEnabled;
  this->m_ExtensionToLanguage = gen->m_ExtensionToLanguage;
771
772
773
  this->m_IgnoreExtensions = gen->m_IgnoreExtensions;
  this->m_LanguageToOutputExtension = gen->m_LanguageToOutputExtension;
  this->m_LanguageToLinkerPreference = gen->m_LanguageToLinkerPreference;
774
  this->m_OutputExtensions = gen->m_OutputExtensions;
775
776
}

777
778
779
780
781
782
783
//----------------------------------------------------------------------------
void cmGlobalGenerator::GetDocumentation(cmDocumentationEntry& entry) const
{
  entry.name = this->GetName();
  entry.brief = "";
  entry.full = "";
}
784
785

bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, 
786
                                   cmLocalGenerator* gen)
787
788
789
790
791
792
793
794
795
796
797
798
799
800
{
  cmLocalGenerator* cur = gen->GetParent();
  while(cur && cur != root)
    {
    if(cur->GetExcludeAll())
      {
      return true;
      }
    cur = cur->GetParent();
    }
  return false;
}


801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
void cmGlobalGenerator::GetEnabledLanguages(std::vector<std::string>& lang)
{
  for(std::map<cmStdString, bool>::iterator i = m_LanguageEnabled.begin(); 
      i != m_LanguageEnabled.end(); ++i)
    {
    lang.push_back(i->first);
    }
}

const char* cmGlobalGenerator::GetLinkerPreference(const char* lang)
{
  if(m_LanguageToLinkerPreference.count(lang))
    {
    return m_LanguageToLinkerPreference[lang].c_str();
    }
  return "None";
}
818
819
820


void cmGlobalGenerator::FillProjectMap()
821
822
{ 
  m_ProjectMap.clear(); // make sure we start with a clean map
823
824
825
  unsigned int i;
  for(i = 0; i < m_LocalGenerators.size(); ++i)
    {
Ken Martin's avatar
Ken Martin committed
826
827
828
829
    // for each local generator add all projects 
    cmLocalGenerator *lg = m_LocalGenerators[i];
    std::string name;
    do 
830
      {
Ken Martin's avatar
Ken Martin committed
831
832
833
834
835
836
      if (name != lg->GetMakefile()->GetProjectName())
        {
        name = lg->GetMakefile()->GetProjectName();
        m_ProjectMap[name].push_back(m_LocalGenerators[i]);
        }
      lg = lg->GetParent();
837
      }
Ken Martin's avatar
Ken Martin committed
838
    while (lg);
839
840
    }
}
841

Bill Hoffman's avatar
Bill Hoffman committed
842

843
844
cmTarget* cmGlobalGenerator::FindTarget(const char* project, 
                                        const char* name)
845
{
846
847
  std::vector<cmLocalGenerator*>* gens = &m_LocalGenerators;
  if(project)
848
    {
849
850
851
852
853
    gens = &m_ProjectMap[project];
    }
  for(unsigned int i = 0; i < gens->size(); ++i)
    {
    cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name);
Bill Hoffman's avatar
Bill Hoffman committed
854
    if(ret)
855
      {
Bill Hoffman's avatar
Bill Hoffman committed
856
      return ret;
857
858
859
860
861
      }
    }
  return 0;
}

862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
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
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
//----------------------------------------------------------------------------
void cmGlobalGenerator::ConfigureRelativePaths()
{
  // Identify the longest shared path component between the source
  // directory and the build directory.
  std::vector<std::string> source;
  std::vector<std::string> binary;
  cmSystemTools::SplitPath(m_CMakeInstance->GetHomeDirectory(), source);
  cmSystemTools::SplitPath(m_CMakeInstance->GetHomeOutputDirectory(), binary);
  unsigned int common=0;
  while(common < source.size() && common < binary.size() &&
        cmSystemTools::ComparePath(source[common].c_str(),
                                   binary[common].c_str()))
    {
    ++common;
    }

  // Require more than just the root portion of the path to be in
  // common before allowing relative paths.  Also disallow relative
  // paths if the build tree is a network path.  The current working
  // directory on Windows cannot be a network path.  Therefore
  // relative paths cannot work with network paths.
  if(common > 1 && source[0] != "//")
    {
    // Build the minimum prefix required of a path to be converted to
    // a relative path.
    source.erase(source.begin()+common, source.end());
    m_RelativePathTop = cmSystemTools::JoinPath(source);
    }
  else
    {
    // Disable relative paths.
    m_RelativePathTop = "";
    }
}

//----------------------------------------------------------------------------
std::string
cmGlobalGenerator::ConvertToRelativePath(const std::vector<std::string>& local,
                                         const char* in_remote)
{
  // The path should never be quoted.
  assert(in_remote[0] != '\"');

  // The local path should never have a trailing slash.
  assert(local.size() > 0 && !(local[local.size()-1] == ""));

  // If the path is already relative or relative paths are disabled
  // then just return the path.
  if(m_RelativePathTop.size() == 0 ||
     !cmSystemTools::FileIsFullPath(in_remote))
    {
    return in_remote;
    }

  // If the path does not begin with the minimum relative path prefix
  // then do not convert it.
  std::string original = in_remote;
  if(original.size() < m_RelativePathTop.size() ||
     !cmSystemTools::ComparePath(
       original.substr(0, m_RelativePathTop.size()).c_str(),
       m_RelativePathTop.c_str()))
    {
    return in_remote;
    }

  // Identify the longest shared path component between the remote
  // path and the local path.
  std::vector<std::string> remote;
  cmSystemTools::SplitPath(in_remote, remote);
  unsigned int common=0;
  while(common < remote.size() &&
        common < local.size() &&
        cmSystemTools::ComparePath(remote[common].c_str(),
                                   local[common].c_str()))
    {
    ++common;
    }

  // If the entire path is in common then just return a ".".
  if(common == remote.size() &&
     common == local.size())
    {
    return ".";
    }

  // If the entire path is in common except for a trailing slash then
  // just return a "./".
  if(common+1 == remote.size() &&
     remote[common].size() == 0 &&
     common == local.size())
    {
    return "./";
    }

  // Construct the relative path.
  std::string relative;

  // First add enough ../ to get up to the level of the shared portion
  // of the path.  Leave off the trailing slash.  Note that the last
  // component of local will never be empty because local should never
  // have a trailing slash.
  for(unsigned int i=common; i < local.size(); ++i)
    {
    relative += "..";
    if(i < local.size()-1)
      {
      relative += "/";
      }
    }

  // Now add the portion of the destination path that is not included
  // in the shared portion of the path.  Add a slash the first time
  // only if there was already something in the path.  If there was a
  // trailing slash in the input then the last iteration of the loop
  // will add a slash followed by an empty string which will preserve
  // the trailing slash in the output.
  for(unsigned int i=common; i < remote.size(); ++i)
    {
    if(relative.size() > 0)
      {
      relative += "/";
      }
    relative += remote[i];
    }

  // Finally return the path.
  return relative;
}

992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
inline std::string removeQuotes(const std::string& s)
{
  if(s[0] == '\"' && s[s.size()-1] == '\"')
    {
    return s.substr(1, s.size()-2);
    }
  return s;
}

void cmGlobalGenerator::SetupTests()
{
  std::string ctest = 
    m_LocalGenerators[0]->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND");
  ctest = removeQuotes(ctest);
  ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
  ctest += "/";
  ctest += "ctest";
  ctest += cmSystemTools::GetExecutableExtension();
  if(!cmSystemTools::FileExists(ctest.c_str()))
    {
    ctest =     
      m_LocalGenerators[0]->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND");
    ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
    ctest += "/Debug/";
    ctest += "ctest";
    ctest += cmSystemTools::GetExecutableExtension();
    }
  if(!cmSystemTools::FileExists(ctest.c_str()))
    {
    ctest =     
      m_LocalGenerators[0]->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND");
    ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
    ctest += "/Release/";
    ctest += "ctest";
    ctest += cmSystemTools::GetExecutableExtension();
    }
  // if we found ctest
  if (cmSystemTools::FileExists(ctest.c_str()))
    {
    // Create a full path filename for output Testfile
    std::string fname;
    fname = m_CMakeInstance->GetStartOutputDirectory();
    fname += "/";
1035
    if ( m_LocalGenerators[0]->GetMakefile()->IsSet("CTEST_NEW_FORMAT") )
1036
      {
1037
      fname += "CTestTestfile.txt";
1038
1039
1040
      }
    else
      {
1041
      fname += "DartTestfile.txt";
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
      }
    
    // If the file doesn't exist, then ENABLE_TESTING hasn't been run
    if (cmSystemTools::FileExists(fname.c_str()))
      {
      const char* no_output = 0;
      std::vector<std::string> no_depends;
      std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
      for(it = m_ProjectMap.begin(); it!= m_ProjectMap.end(); ++it)
        {
        std::vector<cmLocalGenerator*>& gen = it->second;
        // add the ALL_BUILD to the first local generator of each project
        if(gen.size())
          {
          gen[0]->GetMakefile()->
            AddUtilityCommand("RUN_TESTS", false, no_output, no_depends,
                              ctest.c_str(), "-C", "$(IntDir)");
          }
        }
      }
    }
}