cmake.cxx 49.6 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

Will Schroeder's avatar
Will Schroeder committed
12
13
14
     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.
Ken Martin's avatar
Ken Martin committed
15
16
17

=========================================================================*/
#include "cmake.h"
Ken Martin's avatar
Ken Martin committed
18
#include "time.h"
Ken Martin's avatar
Ken Martin committed
19
#include "cmCacheManager.h"
Ken Martin's avatar
Ken Martin committed
20
21
#include "cmMakefile.h"
#include "cmLocalGenerator.h"
Ken Martin's avatar
Ken Martin committed
22
23
#include "cmCommands.h"
#include "cmCommand.h"
Ken Martin's avatar
Ken Martin committed
24

25
#if defined(CMAKE_BUILD_WITH_CMAKE)
26
# include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
27
28
29
# include "cmVariableWatch.h"
# include "cmVersion.h"
#endif
30

31
32
33
34
35
36
37
38
// only build kdevelop generator on non-windows platforms
// when not bootstrapping cmake
#if !defined(_WIN32)
# if defined(CMAKE_BUILD_WITH_CMAKE)
#   define CMAKE_USE_KDEVELOP
# endif
#endif

Ken Martin's avatar
Ken Martin committed
39
40
// include the generator
#if defined(_WIN32) && !defined(__CYGWIN__)
41
42
43
44
45
46
47
48
49
#  include "cmGlobalVisualStudio6Generator.h"
#  if !defined(__MINGW32__)
#    include "cmGlobalVisualStudio7Generator.h"
#    include "cmGlobalVisualStudio71Generator.h"
#    include "cmGlobalVisualStudio8Generator.h"
#  endif
#  include "cmGlobalBorlandMakefileGenerator.h"
#  include "cmGlobalNMakeMakefileGenerator.h"
#  include "cmWin32ProcessExecution.h"
Ken Martin's avatar
Ken Martin committed
50
#else
Ken Martin's avatar
Ken Martin committed
51
#endif
Ken Martin's avatar
Ken Martin committed
52
#include "cmGlobalUnixMakefileGenerator3.h"
53
54
55
56

#ifdef CMAKE_USE_KDEVELOP
# include "cmGlobalKdevelopGenerator.h"
#endif
Ken Martin's avatar
Ken Martin committed
57

58
#include <stdlib.h> // required for atoi
59

60
#ifdef __APPLE__
61
62
#  include "cmGlobalXCodeGenerator.h"
#  define CMAKE_USE_XCODE 1
63
64
65
#  include <sys/types.h>
#  include <sys/time.h>
#  include <sys/resource.h>
Ken Martin's avatar
Ken Martin committed
66
#endif
67

68
69
#include <sys/stat.h> // struct stat

Andy Cedilnik's avatar
Andy Cedilnik committed
70
#include <memory> // auto_ptr
71
72

void cmNeedBackwardsCompatibility(const std::string& variable, 
Ken Martin's avatar
Ken Martin committed
73
                                  int access_type, void* )
74
{
75
#ifdef CMAKE_BUILD_WITH_CMAKE
76
77
  if (access_type == cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS)
    {
Brad King's avatar
Brad King committed
78
    std::string message = "An attempt was made to access a variable: ";
79
    message += variable;
Andy Cedilnik's avatar
Andy Cedilnik committed
80
81
82
83
84
85
    message += " that has not been defined. Some variables were always defined "
      "by CMake in versions prior to 1.6. To fix this you might need to set the "
      "cache value of CMAKE_BACKWARDS_COMPATIBILITY to 1.4 or less. If you are "
      "writing a CMakeList file, (or have already set "
      "CMAKE_BACKWARDS_COMPATABILITY to 1.4 or less) then you probably need to "
      "include a CMake module to test for the feature this variable defines.";
86
87
    cmSystemTools::Error(message.c_str());
    }
88
89
90
91
#else
  (void)variable;
  (void)access_type;
#endif
92
93
}

Bill Hoffman's avatar
Bill Hoffman committed
94
95
cmake::cmake()
{
96
  m_DebugTryCompile = false;
97
98
  m_ClearBuildSystem = false;
  
99
100
101
102
103
104
105
106
107
108
109
110
#ifdef __APPLE__
  struct rlimit rlp;
  if(!getrlimit(RLIMIT_STACK, &rlp))
    {
    if(rlp.rlim_cur != rlp.rlim_max)
      {
        rlp.rlim_cur = rlp.rlim_max;
         setrlimit(RLIMIT_STACK, &rlp);
      }
    }
#endif

111
112
113
114
115
116
117
  // If MAKEFLAGS are given in the environment, remove the environment
  // variable.  This will prevent try-compile from succeeding when it
  // should fail (if "-i" is an option).  We cannot simply test
  // whether "-i" is given and remove it because some make programs
  // encode the MAKEFLAGS variable in a strange way.
  if(getenv("MAKEFLAGS"))
    {
Bill Hoffman's avatar
Bill Hoffman committed
118
    cmSystemTools::PutEnv("MAKEFLAGS=");
119
120
    }  
  
Bill Hoffman's avatar
Bill Hoffman committed
121
  m_Verbose = false;
122
  m_InTryCompile = false;
Ken Martin's avatar
Ken Martin committed
123
124
  m_CacheManager = new cmCacheManager;
  m_GlobalGenerator = 0;
Ken Martin's avatar
Ken Martin committed
125
126
  m_ProgressCallback = 0;
  m_ProgressCallbackClientData = 0;
127
  m_ScriptMode = false;
Ken Martin's avatar
Ken Martin committed
128

129
130
#ifdef CMAKE_BUILD_WITH_CMAKE
  m_VariableWatch = new cmVariableWatch;
131
132
133
134
135
136
  m_VariableWatch->AddWatch("CMAKE_WORDS_BIGENDIAN",
                            cmNeedBackwardsCompatibility);
  m_VariableWatch->AddWatch("CMAKE_SIZEOF_INT",
                            cmNeedBackwardsCompatibility);
  m_VariableWatch->AddWatch("CMAKE_X_LIBS",
                            cmNeedBackwardsCompatibility);
137
138
139
140
141
#endif

  this->AddDefaultGenerators();
  this->AddDefaultCommands();

Bill Hoffman's avatar
Bill Hoffman committed
142
143
}

144
145
cmake::~cmake()
{
Ken Martin's avatar
Ken Martin committed
146
147
  delete m_CacheManager;
  if (m_GlobalGenerator)
148
    {
Ken Martin's avatar
Ken Martin committed
149
150
    delete m_GlobalGenerator;
    m_GlobalGenerator = 0;
151
    }
Ken Martin's avatar
Ken Martin committed
152
153
154
155
156
  for(RegisteredCommandsMap::iterator j = m_Commands.begin();
      j != m_Commands.end(); ++j)
    {
    delete (*j).second;
    }
157
#ifdef CMAKE_BUILD_WITH_CMAKE
158
  delete m_VariableWatch;
159
#endif
Ken Martin's avatar
Ken Martin committed
160
161
}

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
void cmake::CleanupCommandsAndMacros()
{
  std::vector<cmCommand*> commands;
  for(RegisteredCommandsMap::iterator j = m_Commands.begin();
      j != m_Commands.end(); ++j)
    {
    if ( !j->second->IsA("cmMacroHelperCommand") )
      {
      commands.push_back(j->second);
      }
    else
      {
      delete j->second;
      }
    }
  m_Commands.erase(m_Commands.begin(), m_Commands.end());
  std::vector<cmCommand*>::iterator it;
  for ( it = commands.begin(); it != commands.end();
    ++ it )
    {
    m_Commands[cmSystemTools::LowerCase((*it)->GetName())] = *it;
    }
}

Ken Martin's avatar
Ken Martin committed
186
187
bool cmake::CommandExists(const char* name) const
{
188
189
  std::string sName = cmSystemTools::LowerCase(name);
  return (m_Commands.find(sName) != m_Commands.end());
190
191
}

Ken Martin's avatar
Ken Martin committed
192
193
194
cmCommand *cmake::GetCommand(const char *name) 
{
  cmCommand* rm = 0;
195
196
  std::string sName = cmSystemTools::LowerCase(name);
  RegisteredCommandsMap::iterator pos = m_Commands.find(sName);
Ken Martin's avatar
Ken Martin committed
197
198
199
200
201
202
203
  if (pos != m_Commands.end())
    {
    rm = (*pos).second;
    }
  return rm;
}

204
205
206
void cmake::RenameCommand(const char*oldName, const char* newName)
{
  // if the command already exists, free the old one
207
208
209
  std::string sOldName = cmSystemTools::LowerCase(oldName);
  std::string sNewName = cmSystemTools::LowerCase(newName);
  RegisteredCommandsMap::iterator pos = m_Commands.find(sOldName);
210
211
212
213
  if ( pos == m_Commands.end() )
    {
    return;
    }
214
  cmCommand* cmd = pos->second;
215

216
217
218
219
220
221
222
223
  pos = m_Commands.find(sNewName);
  if (pos != m_Commands.end())
    {
    delete pos->second;
    m_Commands.erase(pos);
    }
  m_Commands.insert(RegisteredCommandsMap::value_type(sNewName, cmd));
  pos = m_Commands.find(sOldName);
224
225
226
  m_Commands.erase(pos);
}

Ken Martin's avatar
Ken Martin committed
227
228
void cmake::AddCommand(cmCommand* wg)
{
229
  std::string name = cmSystemTools::LowerCase(wg->GetName());
Ken Martin's avatar
Ken Martin committed
230
231
232
233
234
235
236
  // if the command already exists, free the old one
  RegisteredCommandsMap::iterator pos = m_Commands.find(name);
  if (pos != m_Commands.end())
    {
    delete pos->second;
    m_Commands.erase(pos);
    }
Ken Martin's avatar
Ken Martin committed
237
238
  m_Commands.insert( RegisteredCommandsMap::value_type(name, wg));
}
239

240
// Parse the args
241
bool cmake::SetCacheArgs(const std::vector<std::string>& args)
242
243
244
245
246
247
248
{ 
  for(unsigned int i=1; i < args.size(); ++i)
    {
    std::string arg = args[i];
    if(arg.find("-D",0) == 0)
      {
      std::string entry = arg.substr(2);
249
250
251
252
      if(entry.size() == 0)
        {
        entry = args[++i];
        }
253
      std::string var, value;
254
255
256
      cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
      if(cmCacheManager::ParseEntry(entry.c_str(), var, value, type) ||
        cmCacheManager::ParseEntry(entry.c_str(), var, value))
257
        {
258
259
260
        this->m_CacheManager->AddCacheEntry(var.c_str(), value.c_str(),
          "No help, variable specified on the command line.",
          type);
261
262
263
264
265
        }
      else
        {
        std::cerr << "Parse error in command line argument: " << arg << "\n"
                  << "Should be: VAR:type=value\n";
266
267
        cmSystemTools::Error("No cmake scrpt provided.");
        return false;
268
269
        }        
      }
270
271
272
    else if(arg.find("-C",0) == 0)
      {
      std::string path = arg.substr(2);
273
274
      if ( path.size() == 0 )
        {
275
        path = args[++i];
276
        }
277
      std::cerr << "loading initial cache file " << path.c_str() << "\n";
Ken Martin's avatar
Ken Martin committed
278
279
      this->ReadListFile(path.c_str());
      }
280
    else if(arg.find("-P",0) == 0)
281
      {
282
283
      i++;
      std::string path = args[i];
284
285
286
287
288
289
290
291
      if ( path.size() == 0 )
        {
        cmSystemTools::Error("No cmake scrpt provided.");
        return false;
        }
      std::cerr << "Running cmake script file " << path.c_str() << "\n";
      this->ReadListFile(path.c_str());
      }
Ken Martin's avatar
Ken Martin committed
292
    }
293
  return true;
Ken Martin's avatar
Ken Martin committed
294
295
296
297
298
299
}

void cmake::ReadListFile(const char *path)
{
  // if a generator was not yet created, temporarily create one
  cmGlobalGenerator *gg = this->GetGlobalGenerator();
Ken Martin's avatar
Ken Martin committed
300
  bool created = false;
Ken Martin's avatar
Ken Martin committed
301
302
303
304
305
306
307
308
309
310
311
312
  
  // if a generator was not specified use a generic one
  if (!gg)
    {
    gg = new cmGlobalGenerator;
    gg->SetCMakeInstance(this);
    created = true;
    }

  // read in the list file to fill the cache
  if(path)
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
313
    std::auto_ptr<cmLocalGenerator> lg(gg->CreateLocalGenerator());
Ken Martin's avatar
Ken Martin committed
314
    lg->SetGlobalGenerator(gg);
315
    if (!lg->GetMakefile()->ReadListFile(0, path))
Ken Martin's avatar
Ken Martin committed
316
317
318
      {
      std::cerr << "Error in reading cmake initial cache file:"
                << path << "\n";
319
      }
320
    }
Ken Martin's avatar
Ken Martin committed
321
322
323
324
325
326
  
  // free generic one if generated
  if (created)
    {
    delete gg;
    }
327
328
}

Ken Martin's avatar
Ken Martin committed
329
// Parse the args
Ken Martin's avatar
Ken Martin committed
330
void cmake::SetArgs(const std::vector<std::string>& args)
Ken Martin's avatar
Ken Martin committed
331
{
Bill Hoffman's avatar
Bill Hoffman committed
332
  bool directoriesSet = false;
Brad King's avatar
Brad King committed
333
  for(unsigned int i=1; i < args.size(); ++i)
Ken Martin's avatar
Ken Martin committed
334
    {
335
    std::string arg = args[i];
Ken Martin's avatar
Ken Martin committed
336
    if(arg.find("-H",0) == 0)
Ken Martin's avatar
Ken Martin committed
337
      {
Bill Hoffman's avatar
Bill Hoffman committed
338
      directoriesSet = true;
Ken Martin's avatar
Ken Martin committed
339
      std::string path = arg.substr(2);
340
341
      path = cmSystemTools::CollapseFullPath(path.c_str());
      cmSystemTools::ConvertToUnixSlashes(path);
Ken Martin's avatar
Ken Martin committed
342
      this->SetHomeDirectory(path.c_str());
Ken Martin's avatar
Ken Martin committed
343
      }
Bill Hoffman's avatar
Bill Hoffman committed
344
    else if(arg.find("-S",0) == 0)
Ken Martin's avatar
Ken Martin committed
345
      {
346
      // There is no local generate anymore.  Ignore -S option.
Ken Martin's avatar
Ken Martin committed
347
      }
Bill Hoffman's avatar
Bill Hoffman committed
348
    else if(arg.find("-O",0) == 0)
Ken Martin's avatar
Ken Martin committed
349
      {
350
      // There is no local generate anymore.  Ignore -O option.
Ken Martin's avatar
Ken Martin committed
351
      }
Bill Hoffman's avatar
Bill Hoffman committed
352
    else if(arg.find("-B",0) == 0)
Ken Martin's avatar
Ken Martin committed
353
      {
Bill Hoffman's avatar
Bill Hoffman committed
354
      directoriesSet = true;
Ken Martin's avatar
Ken Martin committed
355
      std::string path = arg.substr(2);
356
357
      path = cmSystemTools::CollapseFullPath(path.c_str());
      cmSystemTools::ConvertToUnixSlashes(path);
Ken Martin's avatar
Ken Martin committed
358
      this->SetHomeOutputDirectory(path.c_str());
Ken Martin's avatar
Ken Martin committed
359
      }
360
    else if((i < args.size()-1) && (arg.find("--check-build-system",0) == 0))
361
      {
362
      m_CheckBuildSystem = args[++i];
363
      m_ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
364
      }
Bill Hoffman's avatar
Bill Hoffman committed
365
    else if(arg.find("-V",0) == 0)
Ken Martin's avatar
Ken Martin committed
366
      {
Ken Martin's avatar
Ken Martin committed
367
        m_Verbose = true;
Ken Martin's avatar
Ken Martin committed
368
      }
369
370
371
372
    else if(arg.find("-D",0) == 0)
      {
      // skip for now
      }
373
374
375
376
    else if(arg.find("-C",0) == 0)
      {
      // skip for now
      }
377
    else if(arg.find("-P",0) == 0)
378
379
      {
      // skip for now
380
      i++;
381
      }
382
383
384
385
386
    else if(arg.find("--debug-trycompile",0) == 0)
      {
      std::cout << "debug trycompile on\n";
      this->DebugTryCompileOn();
      }
Bill Hoffman's avatar
Bill Hoffman committed
387
388
389
    else if(arg.find("-G",0) == 0)
      {
      std::string value = arg.substr(2);
390
391
392
393
      if(value.size() == 0)
        {
        value = args[++i];
        }
Ken Martin's avatar
Ken Martin committed
394
395
      cmGlobalGenerator* gen = 
        this->CreateGlobalGenerator(value.c_str());
Bill Hoffman's avatar
Bill Hoffman committed
396
397
398
399
400
401
402
      if(!gen)
        {
        cmSystemTools::Error("Could not create named generator ",
                             value.c_str());
        }
      else
        {
Ken Martin's avatar
Ken Martin committed
403
        this->SetGlobalGenerator(gen);
Bill Hoffman's avatar
Bill Hoffman committed
404
405
        }
      }
406
    // no option assume it is the path to the source
Bill Hoffman's avatar
Bill Hoffman committed
407
408
    else
      {
409
      directoriesSet = true;
410
      this->SetDirectoriesFromFile(arg.c_str());
Bill Hoffman's avatar
Bill Hoffman committed
411
412
413
414
      }
    }
  if(!directoriesSet)
    {
Ken Martin's avatar
Ken Martin committed
415
    this->SetHomeOutputDirectory
416
      (cmSystemTools::GetCurrentWorkingDirectory().c_str());
Ken Martin's avatar
Ken Martin committed
417
    this->SetStartOutputDirectory
418
      (cmSystemTools::GetCurrentWorkingDirectory().c_str());
Ken Martin's avatar
Ken Martin committed
419
    this->SetHomeDirectory
420
      (cmSystemTools::GetCurrentWorkingDirectory().c_str());
Ken Martin's avatar
Ken Martin committed
421
    this->SetStartDirectory
422
      (cmSystemTools::GetCurrentWorkingDirectory().c_str());
Ken Martin's avatar
Ken Martin committed
423
    }
424
425
426

  this->SetStartDirectory(this->GetHomeDirectory());
  this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
Ken Martin's avatar
Ken Martin committed
427
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
458
459
460
461
462
463
464
465
466
467
468
//----------------------------------------------------------------------------
void cmake::SetDirectoriesFromFile(const char* arg)
{
  // Check if the argument refers to a CMakeCache.txt or
  // CMakeLists.txt file.
  std::string listPath;
  std::string cachePath;
  bool argIsFile = false;
  if(cmSystemTools::FileIsDirectory(arg))
    {
    std::string path = cmSystemTools::CollapseFullPath(arg);
    cmSystemTools::ConvertToUnixSlashes(path);
    std::string cacheFile = path;
    cacheFile += "/CMakeCache.txt";
    std::string listFile = path;
    listFile += "/CMakeLists.txt";
    if(cmSystemTools::FileExists(cacheFile.c_str()))
      {
      cachePath = path;
      }
    if(cmSystemTools::FileExists(listFile.c_str()))
      {
      listPath = path;
      }
    }
  else if(cmSystemTools::FileExists(arg))
    {
    argIsFile = true;
    std::string fullPath = cmSystemTools::CollapseFullPath(arg);
    std::string name = cmSystemTools::GetFilenameName(fullPath.c_str());
    name = cmSystemTools::LowerCase(name);
    if(name == "cmakecache.txt")
      {
      cachePath = cmSystemTools::GetFilenamePath(fullPath.c_str());
      }
    else if(name == "cmakelists.txt")
      {
      listPath = cmSystemTools::GetFilenamePath(fullPath.c_str());
      }
    }
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  else
    {
    // Specified file or directory does not exist.  Try to set things
    // up to produce a meaningful error message.
    std::string fullPath = cmSystemTools::CollapseFullPath(arg);
    std::string name = cmSystemTools::GetFilenameName(fullPath.c_str());
    name = cmSystemTools::LowerCase(name);
    if(name == "cmakecache.txt" || name == "cmakelists.txt")
      {
      argIsFile = true;
      listPath = cmSystemTools::GetFilenamePath(fullPath.c_str());
      }
    else
      {
      listPath = fullPath;
      }
    }

487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  // If there is a CMakeCache.txt file, use its settings.
  if(cachePath.length() > 0)
    {
    cmCacheManager* cachem = this->GetCacheManager();
    cmCacheManager::CacheIterator it = cachem->NewIterator();
    if(cachem->LoadCache(cachePath.c_str()) && it.Find("CMAKE_HOME_DIRECTORY"))
      {
      this->SetHomeOutputDirectory(cachePath.c_str());      
      this->SetStartOutputDirectory(cachePath.c_str());      
      this->SetHomeDirectory(it.GetValue());
      this->SetStartDirectory(it.GetValue());
      return;
      }
    }
  
  // If there is a CMakeLists.txt file, use it as the source tree.
  if(listPath.length() > 0)
    {
    this->SetHomeDirectory(listPath.c_str());
    this->SetStartDirectory(listPath.c_str());
    
    if(argIsFile)
      {
      // Source CMakeLists.txt file given.  It was probably dropped
      // onto the executable in a GUI.  Default to an in-source build.
      this->SetHomeOutputDirectory(listPath.c_str());      
      this->SetStartOutputDirectory(listPath.c_str());      
      }
    else
      {
      // Source directory given on command line.  Use current working
      // directory as build tree.
      std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
      this->SetHomeOutputDirectory(cwd.c_str());
      this->SetStartOutputDirectory(cwd.c_str());      
      }
    return;
    }
  
  // We didn't find a CMakeLists.txt or CMakeCache.txt file from the
  // argument.  Assume it is the path to the source tree, and use the
  // current working directory as the build tree.
  std::string full = cmSystemTools::CollapseFullPath(arg);
  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
  this->SetHomeDirectory(full.c_str());
  this->SetStartDirectory(full.c_str());
  this->SetHomeOutputDirectory(cwd.c_str());
  this->SetStartOutputDirectory(cwd.c_str());      
}

537
// at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the cache
Ken Martin's avatar
Ken Martin committed
538
int cmake::AddCMakePaths(const char *arg0)
Ken Martin's avatar
Ken Martin committed
539
{
540
  // Find our own executable.
541
  std::vector<cmStdString> failures;
Ken Martin's avatar
Ken Martin committed
542
  std::string cMakeSelf = arg0;
Ken Martin's avatar
Ken Martin committed
543
  cmSystemTools::ConvertToUnixSlashes(cMakeSelf);
544
  failures.push_back(cMakeSelf);
545
  cMakeSelf = cmSystemTools::FindProgram(cMakeSelf.c_str());
546
  cmSystemTools::ConvertToUnixSlashes(cMakeSelf);
547
548
  if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
    {
549
#ifdef CMAKE_BUILD_DIR
Ken Martin's avatar
Ken Martin committed
550
551
552
553
554
  std::string intdir = ".";
#ifdef  CMAKE_INTDIR
  intdir = CMAKE_INTDIR;
#endif
  cMakeSelf = CMAKE_BUILD_DIR;
555
  cMakeSelf += "/bin/";
Ken Martin's avatar
Ken Martin committed
556
557
558
  cMakeSelf += intdir;
  cMakeSelf += "/cmake";
  cMakeSelf += cmSystemTools::GetExecutableExtension();
559
#endif
560
    }
561
#ifdef CMAKE_PREFIX
Bill Hoffman's avatar
Bill Hoffman committed
562
  if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
563
    {
564
    failures.push_back(cMakeSelf);
565
    cMakeSelf = CMAKE_PREFIX "/bin/cmake";
566
567
    }
#endif
Bill Hoffman's avatar
Bill Hoffman committed
568
  if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
569
    {
570
    failures.push_back(cMakeSelf);
571
    cmOStringStream msg;
572
    msg << "CMAKE can not find the command line program cmake.\n";
Ken Martin's avatar
Ken Martin committed
573
    msg << "  argv[0] = \"" << arg0 << "\"\n";
574
575
576
577
578
579
580
581
    msg << "  Attempted paths:\n";
    std::vector<cmStdString>::iterator i;
    for(i=failures.begin(); i != failures.end(); ++i)
      {
      msg << "    \"" << i->c_str() << "\"\n";
      }
    cmSystemTools::Error(msg.str().c_str());
    return 0;
582
    }
583
  // Save the value in the cache
Ken Martin's avatar
Ken Martin committed
584
  this->m_CacheManager->AddCacheEntry
585
    ("CMAKE_COMMAND",cMakeSelf.c_str(), "Path to CMake executable.",
Ken Martin's avatar
Ken Martin committed
586
     cmCacheManager::INTERNAL);
587

588
589
590
591
592
593
594
595
  // Find and save the command to edit the cache
  std::string editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
    "/ccmake" + cmSystemTools::GetFilenameExtension(cMakeSelf);
  if( !cmSystemTools::FileExists(editCacheCommand.c_str()))
    {
    editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
      "/CMakeSetup" + cmSystemTools::GetFilenameExtension(cMakeSelf);
    }
596
597
598
599
600
601
602
603
  std::string ctestCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
    "/ctest" + cmSystemTools::GetFilenameExtension(cMakeSelf);
  if(cmSystemTools::FileExists(ctestCommand.c_str()))
    {
    this->m_CacheManager->AddCacheEntry
      ("CMAKE_CTEST_COMMAND", ctestCommand.c_str(),
       "Path to ctest program executable.", cmCacheManager::INTERNAL);
    }
604
605
  if(cmSystemTools::FileExists(editCacheCommand.c_str()))
    {
Ken Martin's avatar
Ken Martin committed
606
    this->m_CacheManager->AddCacheEntry
607
608
609
      ("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
       "Path to cache edit program executable.", cmCacheManager::INTERNAL);
    }
610
  
Ken Martin's avatar
Ken Martin committed
611
612
  // do CMAKE_ROOT, look for the environment variable first
  std::string cMakeRoot;
613
  std::string modules;
Ken Martin's avatar
Ken Martin committed
614
615
616
  if (getenv("CMAKE_ROOT"))
    {
    cMakeRoot = getenv("CMAKE_ROOT");
617
    modules = cMakeRoot + "/Modules/CMake.cmake";
Ken Martin's avatar
Ken Martin committed
618
    }
619
  if(!cmSystemTools::FileExists(modules.c_str()))
Ken Martin's avatar
Ken Martin committed
620
621
622
623
624
625
626
627
628
    {
    // next try exe/..
    cMakeRoot  = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
    std::string::size_type slashPos = cMakeRoot.rfind("/");
    if(slashPos != std::string::npos)      
      {
      cMakeRoot = cMakeRoot.substr(0, slashPos);
      }
    // is there no Modules direcory there?
629
    modules = cMakeRoot + "/Modules/CMake.cmake"; 
630
631
    }
  
Bill Hoffman's avatar
Bill Hoffman committed
632
  if (!cmSystemTools::FileExists(modules.c_str()))
633
634
    {
    // try exe/../share/cmake
635
    cMakeRoot += CMAKE_DATA_DIR;
636
    modules = cMakeRoot + "/Modules/CMake.cmake";
637
    }
638
#ifdef CMAKE_ROOT_DIR
Bill Hoffman's avatar
Bill Hoffman committed
639
  if (!cmSystemTools::FileExists(modules.c_str()))
640
    {
Bill Hoffman's avatar
Bill Hoffman committed
641
    // try compiled in root directory
642
    cMakeRoot = CMAKE_ROOT_DIR;
643
    modules = cMakeRoot + "/Modules/CMake.cmake";
644
    }
Ken Martin's avatar
Ken Martin committed
645
#endif
646
#ifdef CMAKE_PREFIX
Bill Hoffman's avatar
Bill Hoffman committed
647
  if (!cmSystemTools::FileExists(modules.c_str()))
648
    {
Bill Hoffman's avatar
Bill Hoffman committed
649
    // try compiled in install prefix
650
    cMakeRoot = CMAKE_PREFIX CMAKE_DATA_DIR;
651
    modules = cMakeRoot + "/Modules/CMake.cmake";
652
653
    }
#endif
Bill Hoffman's avatar
Bill Hoffman committed
654
  if (!cmSystemTools::FileExists(modules.c_str()))
655
    {
Bill Hoffman's avatar
Bill Hoffman committed
656
657
    // try 
    cMakeRoot  = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
658
    cMakeRoot += CMAKE_DATA_DIR;
659
    modules = cMakeRoot +  "/Modules/CMake.cmake";
660
    }
661
662
663
664
665
  if(!cmSystemTools::FileExists(modules.c_str()))
    {
    // next try exe
    cMakeRoot  = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
    // is there no Modules direcory there?
666
    modules = cMakeRoot + "/Modules/CMake.cmake"; 
667
    }
Bill Hoffman's avatar
Bill Hoffman committed
668
  if (!cmSystemTools::FileExists(modules.c_str()))
669
670
    {
    // couldn't find modules
671
672
673
674
    cmSystemTools::Error("Could not find CMAKE_ROOT !!!\n"
                         "CMake has most likely not been installed correctly.\n"
                         "Modules directory not found in\n",
                         cMakeRoot.c_str());
675
    return 0;
Ken Martin's avatar
Ken Martin committed
676
    }
Ken Martin's avatar
Ken Martin committed
677
  this->m_CacheManager->AddCacheEntry
Ken Martin's avatar
Ken Martin committed
678
679
    ("CMAKE_ROOT", cMakeRoot.c_str(),
     "Path to CMake installation.", cmCacheManager::INTERNAL);
680
681

#ifdef _WIN32
682
  std::string comspec = "cmw9xcom.exe";
Andy Cedilnik's avatar
Andy Cedilnik committed
683
  cmSystemTools::SetWindows9xComspecSubstitute(comspec.c_str());
684
#endif
685
  return 1;
Ken Martin's avatar
Ken Martin committed
686
}
687
688
689



Ken Martin's avatar
Ken Martin committed
690
691
void CMakeCommandUsage(const char* program)
{
692
  cmOStringStream errorStream;
Ken Martin's avatar
Ken Martin committed
693

694
#ifdef CMAKE_BUILD_WITH_CMAKE
Ken Martin's avatar
Ken Martin committed
695
  errorStream 
696
    << "cmake version " << cmVersion::GetCMakeVersion() << "\n";
697
698
699
700
#else
  errorStream 
    << "cmake bootstrap\n";
#endif
Ken Martin's avatar
Ken Martin committed
701
702
703
704

  errorStream 
    << "Usage: " << program << " -E [command] [arguments ...]\n"
    << "Available commands: \n"
705
    << "  chdir dir cmd [args]... - run command in a given directory\n"
Ken Martin's avatar
Ken Martin committed
706
    << "  copy file destination   - copy file to destination (either file or directory)\n"
707
    << "  copy_if_different in-file out-file   - copy file if input has changed\n"
708
    << "  copy_directory source destination    - copy directory 'source' content to directory 'destination'\n"
709
    << "  echo [string]...        - displays arguments as text\n"
Ken Martin's avatar
Ken Martin committed
710
    << "  remove file1 file2 ...  - remove the file(s)\n"
711
    << "  time command [args] ... - run command and return elapsed time\n";
Ken Martin's avatar
Ken Martin committed
712
#if defined(_WIN32) && !defined(__CYGWIN__)
713
  errorStream
Ken Martin's avatar
Ken Martin committed
714
    << "  write_regv key value    - write registry value\n"
715
716
    << "  delete_regv key         - delete registry value\n"
    << "  comspec                 - on windows 9x use this for RunCommand\n";
Ken Martin's avatar
Ken Martin committed
717
718
#endif

719
  cmSystemTools::Error(errorStream.str().c_str());
Ken Martin's avatar
Ken Martin committed
720
721
722
723
724
725
726
727
728
}

int cmake::CMakeCommand(std::vector<std::string>& args)
{
  if (args.size() > 1)
    {
    // Copy file
    if (args[1] == "copy" && args.size() == 4)
      {
729
730
731
732
733
734
735
      if(!cmSystemTools::cmCopyFile(args[2].c_str(), args[3].c_str()))
        {
        std::cerr << "Error copying file \"" << args[2].c_str()
                  << "\" to \"" << args[3].c_str() << "\".\n";
        return 1;
        }
      return 0;
Ken Martin's avatar
Ken Martin committed
736
737
      }

738
739
740
    // Copy file if different.
    if (args[1] == "copy_if_different" && args.size() == 4)
      {
741
742
743
744
745
746
747
748
      if(!cmSystemTools::CopyFileIfDifferent(args[2].c_str(), args[3].c_str()))
        {
        std::cerr << "Error copying file (if different) from \""
                  << args[2].c_str() << "\" to \"" << args[3].c_str()
                  << "\".\n";
        return 1;
        }
      return 0;
749
750
      }

751
752
753
754
755
756
757
758
759
760
761
762
763
    // Copy directory content
    if (args[1] == "copy_directory" && args.size() == 4)
      {
      if(!cmSystemTools::CopyADirectory(args[2].c_str(), args[3].c_str()))
        {
        std::cerr << "Error copying directory from \""
                  << args[2].c_str() << "\" to \"" << args[3].c_str()
                  << "\".\n";
        return 1;
        }
      return 0;
      }

764
765
766
    // Echo string
    else if (args[1] == "echo" )
      {
Ken Martin's avatar
Ken Martin committed
767
      unsigned int cc;
768
      for ( cc = 2; cc < args.size(); cc ++ )
Ken Martin's avatar
Ken Martin committed
769
770
771
        {
        std::cout << args[cc] << " ";
        }
772
773
774
775
      std::cout << std::endl;
      return 0;
      }

Ken Martin's avatar
Ken Martin committed
776
777
778
779
    // Remove file
    else if (args[1] == "remove" && args.size() > 2)
      {
      for (std::string::size_type cc = 2; cc < args.size(); cc ++)
Ken Martin's avatar
Ken Martin committed
780
        {
Ken Martin's avatar
Ken Martin committed
781
782
783
784
785
786
787
788
        if(args[cc] != "-f")
          {
          if(args[cc] == "\\-f")
            {
            args[cc] = "-f";
            }
          cmSystemTools::RemoveFile(args[cc].c_str());
          }
Ken Martin's avatar
Ken Martin committed
789
        }
Ken Martin's avatar
Ken Martin committed
790
791
792
793
794
795
796
797
      return 0;
      }

    // Clock command
    else if (args[1] == "time" && args.size() > 2)
      {
      std::string command = args[2];
      for (std::string::size_type cc = 3; cc < args.size(); cc ++)
Ken Martin's avatar
Ken Martin committed
798
        {
Ken Martin's avatar
Ken Martin committed
799
800
        command += " ";
        command += args[cc];
Ken Martin's avatar
Ken Martin committed
801
        }
Ken Martin's avatar
Ken Martin committed
802
803
804
805
806
807
808

      clock_t clock_start, clock_finish;
      time_t time_start, time_finish;

      time(&time_start);
      clock_start = clock();
      
Andy Cedilnik's avatar
Andy Cedilnik committed
809
      cmSystemTools::RunSingleCommand(command.c_str());
Ken Martin's avatar
Ken Martin committed
810
811
812
813
814
815
816
817
818
819
820
821
822
823

      clock_finish = clock();
      time(&time_finish);

      double clocks_per_sec = (double)CLOCKS_PER_SEC;
      std::cout << "Elapsed time: " 
                << (long)(time_finish - time_start) << " s. (time)"
                << ", " 
                << (double)(clock_finish - clock_start) / clocks_per_sec 
                << " s. (clock)"
                << "\n";
      return 0;
    }

824
    // Command to change directory and run a program.
825
    else if (args[1] == "chdir" && args.size() >= 4)
826
827
      {
      std::string directory = args[2];
828
829
      if(!cmSystemTools::FileExists(directory.c_str()))
        {
830
831
832
        cmSystemTools::Error("Directory does not exist for chdir command: ",
                             args[2].c_str());
        return 0;
833
        }
834

835
      std::string command = "\"";
836
      command += args[3];
837
      command += "\"";
838
      for (std::string::size_type cc = 4; cc < args.size(); cc ++)
Ken Martin's avatar
Ken Martin committed
839
        {
840
        command += " \"";
841
        command += args[cc];
842
        command += "\"";
Ken Martin's avatar
Ken Martin committed
843
        }
844
      int retval = 0;
Andy Cedilnik's avatar
Andy Cedilnik committed
845
846
847
      int timeout = 0;
      if ( cmSystemTools::RunSingleCommand(command.c_str(), 0, &retval, 
                                           directory.c_str(), true, timeout) )
Ken Martin's avatar
Ken Martin committed
848
849
850
        {
        return retval;
        }        
851

852
      return 1;
853
854
855
856
857
858
859
860
861
862
863
864
      }

    // Internal CMake shared library support.
    else if (args[1] == "cmake_symlink_library" && args.size() == 5)
      {
      int result = 0;
      std::string realName = args[2];
      std::string soName = args[3];
      std::string name = args[4];
      if(soName != realName)
        {
        std::string fname = cmSystemTools::GetFilenameName(realName);
865
866
867
868
        if(cmSystemTools::FileExists(soName.c_str()))
          {
          cmSystemTools::RemoveFile(soName.c_str());
          }
869
870
871
872
873
874
875
876
        if(!cmSystemTools::CreateSymlink(fname.c_str(), soName.c_str()))
          {
          result = 1;
          }
        }
      if(name != soName)
        {
        std::string fname = cmSystemTools::GetFilenameName(soName);
877
878
879
880
        if(cmSystemTools::FileExists(soName.c_str()))
          {
          cmSystemTools::RemoveFile(name.c_str());
          }
881
882
883
884
885
        if(!cmSystemTools::CreateSymlink(fname.c_str(), name.c_str()))
          {
          result = 1;
          }
        }
886
      return result;
887
      }
888

889
    // Internal CMake dependency scanning support.
890
    else if (args[1] == "cmake_depends" && args.size() >= 8)
891
      {
Ken Martin's avatar
Ken Martin committed
892
893
894
895
896
897
898
      cmake cm;
      cmGlobalGenerator *ggd = cm.CreateGlobalGenerator(args[2].c_str());
      ggd->SetCMakeInstance(&cm);
      if (ggd)
        {
        std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
        lgd->SetGlobalGenerator(ggd);
899
        return lgd->ScanDependencies(args)? 0 : 2;
Ken Martin's avatar
Ken Martin committed
900
901
        }
      return 1;
902
903
      }

904
905
906
907
908
909
910
911
#if defined(CMAKE_BUILD_WITH_CMAKE)
    // Internal CMake Fortran module support.
    else if (args[1] == "cmake_copy_f90_mod" && args.size() >= 4)
      {
      return cmDependsFortran::CopyModule(args)? 0 : 1;
      }
#endif

Ken Martin's avatar
Ken Martin committed
912
913
914
915
916
917
918
919
920
921
922
923
924
#if defined(_WIN32) && !defined(__CYGWIN__)
    // Write registry value
    else if (args[1] == "write_regv" && args.size() > 3)
      {
      return cmSystemTools::WriteRegistryValue(args[2].c_str(), 
                                               args[3].c_str()) ? 0 : 1;
      }

    // Delete registry value
    else if (args[1] == "delete_regv" && args.size() > 2)
      {
      return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
      }
925
926
927
    // Remove file
    else if (args[1] == "comspec" && args.size() > 2)
      {
Ken Martin's avatar
Ken Martin committed
928
      unsigned int cc;
929
930
      std::string command = args[2];
      for ( cc = 3; cc < args.size(); cc ++ )
Ken Martin's avatar
Ken Martin committed
931
932
933
        {
        command += " " + args[cc];
        }
934
935
      return cmWin32ProcessExecution::Windows9xHack(command.c_str());
      }
Ken Martin's avatar
Ken Martin committed
936
937
938
939
940
941
#endif
    }

  ::CMakeCommandUsage(args[0].c_str());
  return 1;
}
942
943
944

void cmake::GetRegisteredGenerators(std::vector<std::string>& names)
{
945
946
947
948
949
  for(RegisteredGeneratorsMap::const_iterator i = m_Generators.begin();
      i != m_Generators.end(); ++i)
    {
    names.push_back(i->first);
    }
Ken Martin's avatar
Ken Martin committed
950
951
952
953
}

cmGlobalGenerator* cmake::CreateGlobalGenerator(const char* name)
{
954
955
  RegisteredGeneratorsMap::const_iterator i = m_Generators.find(name);
  if(i != m_Generators.end())
Ken Martin's avatar
Ken Martin committed
956
    {
957
958
959
    cmGlobalGenerator* generator = (i->second)();
    generator->SetCMakeInstance(this);
    return generator;
Ken Martin's avatar
Ken Martin committed
960
    }
961
  else
962
    {
963
    return 0;
964
965
966
    }
}

Ken Martin's avatar
Ken Martin committed
967
968
969
970
971
void cmake::SetHomeDirectory(const char* dir) 
{
  m_cmHomeDirectory = dir;
  cmSystemTools::ConvertToUnixSlashes(m_cmHomeDirectory);
}
972

Ken Martin's avatar
Ken Martin committed
973
void cmake::SetHomeOutputDirectory(const char* lib)
974
{
Ken Martin's avatar
Ken Martin committed
975
976
977
978
979
980
981
982
  m_HomeOutputDirectory = lib;
  cmSystemTools::ConvertToUnixSlashes(m_HomeOutputDirectory);
}

void cmake::SetGlobalGenerator(cmGlobalGenerator *gg)
{
  // delete the old generator
  if (m_GlobalGenerator)
983
    {
Ken Martin's avatar
Ken Martin committed
984
    delete m_GlobalGenerator;
Ken Martin's avatar
Ken Martin committed
985
986
987
    // restore the original environment variables CXX and CC
    // Restor CC
    std::string env = "CC=";
Bill Hoffman's avatar
Bill Hoffman committed
988
    if(m_CCEnvironment.size())
Ken Martin's avatar
Ken Martin committed
989
990
991
      {
      env += m_CCEnvironment;
      }
Bill Hoffman's avatar
Bill Hoffman committed
992
    cmSystemTools::PutEnv(env.c_str());
Ken Martin's avatar
Ken Martin committed
993
    env = "CXX=";
Bill Hoffman's avatar
Bill Hoffman committed
994
    if(m_CXXEnvironment.size())
Ken Martin's avatar
Ken Martin committed
995
996
997
      {
      env += m_CXXEnvironment;
      }
Bill Hoffman's avatar
Bill Hoffman committed
998
    cmSystemTools::PutEnv(env.c_str());
999
    }
Ken Martin's avatar
Ken Martin committed
1000

Ken Martin's avatar
Ken Martin committed
1001
1002
  // set the new
  m_GlobalGenerator = gg;
1003
1004
1005
1006
  // set the global flag for unix style paths on cmSystemTools as 
  // soon as the generator is set.  This allows gmake to be used
  // on windows.
  cmSystemTools::SetForceUnixPaths(m_GlobalGenerator->GetForceUnixPaths());
Ken Martin's avatar
Ken Martin committed
1007
  // Save the environment variables CXX and CC
Bill Hoffman's avatar
Bill Hoffman committed
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  const char* cxx = getenv("CXX");
  const char* cc = getenv("CC");
  if(cxx)
    {
    m_CXXEnvironment = cxx;
    }
  else
    {
    m_CXXEnvironment = "";
    }
  if(cc)
    {
    m_CCEnvironment = cc;
    }
  else
    {
    m_CCEnvironment = "";
    }
Ken Martin's avatar
Ken Martin committed
1026
1027
  // set the cmake instance just to be sure
  gg->SetCMakeInstance(this);
1028
1029
}

1030
int cmake::DoPreConfigureChecks()
1031
{
1032
1033
1034
1035
1036
  // Make sure the Start directory contains a CMakeLists.txt file.
  std::string srcList = this->GetHomeDirectory();
  srcList += "/CMakeLists.txt";
  if(!cmSystemTools::FileExists(srcList.c_str()))
    {
1037
    cmOStringStream err;
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
    if(cmSystemTools::FileIsDirectory(this->GetHomeDirectory()))
      {
      err << "The source directory \"" << this->GetHomeDirectory()
          << "\" does not appear to contain CMakeLists.txt.\n";
      }
    else if(cmSystemTools::FileExists(this->GetHomeDirectory()))
      {
      err << "The source directory \"" << this->GetHomeDirectory()
          << "\" is a file, not a directory.\n";
      }
    else
      {
      err << "The source directory \"" << this->GetHomeDirectory()
          << "\" does not exist.\n";
      }
    err << "Specify --help for usage, or press the help button on the CMake GUI.";
1054
    cmSystemTools::Error(err.str().c_str());
1055
1056
1057
    return -2;
    }
  
Ken Martin's avatar
Ken Martin committed
1058
  // do a sanity check on some values
Ken Martin's avatar
Ken Martin committed
1059
1060
1061
1062
1063
1064
1065
1066
1067
  if(m_CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY"))
    {
    std::string cacheStart = 
      m_CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY");
    cacheStart += "/CMakeLists.txt";
    std::string currentStart = this->GetHomeDirectory();
    currentStart += "/CMakeLists.txt";
    if(!cmSystemTools::SameFile(cacheStart.c_str(), currentStart.c_str()))
      {
1068
      std::string message = "The source \"";
Ken Martin's avatar
Ken Martin committed
1069
      message += currentStart;
1070
      message += "\" does not match the source \"";
Ken Martin's avatar
Ken Martin committed
1071
      message += cacheStart;
1072
1073
      message += "\" used to generate cache.  ";
      message += "Re-run cmake with a different source directory.";
Ken Martin's avatar
Ken Martin committed
1074
1075
1076
1077
1078
      cmSystemTools::Error(message.c_str());
      return -2;
      }
    }