Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmake.cxx
blob9fc346fcfc4053ee74c1aa841f31ff42eaccc8a5
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmake.cxx,v $
5 Language: C++
6 Date: $Date: 2008-04-04 20:02:50 $
7 Version: $Revision: 1.382 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmake.h"
18 #include "cmDocumentVariables.h"
19 #include "time.h"
20 #include "cmCacheManager.h"
21 #include "cmMakefile.h"
22 #include "cmLocalGenerator.h"
23 #include "cmExternalMakefileProjectGenerator.h"
24 #include "cmCommands.h"
25 #include "cmCommand.h"
26 #include "cmFileTimeComparison.h"
27 #include "cmGeneratedFileStream.h"
28 #include "cmSourceFile.h"
29 #include "cmVersion.h"
30 #include "cmTest.h"
31 #include "cmDocumentationFormatterText.h"
33 #if defined(CMAKE_BUILD_WITH_CMAKE)
34 # include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
35 # include "cmVariableWatch.h"
36 # include <cmsys/Terminal.h>
37 #endif
39 #include <cmsys/Directory.hxx>
40 #include <cmsys/Process.h>
41 #include <cmsys/Glob.hxx>
42 #include <cmsys/RegularExpression.hxx>
44 // only build kdevelop generator on non-windows platforms
45 // when not bootstrapping cmake
46 #if !defined(_WIN32)
47 # if defined(CMAKE_BUILD_WITH_CMAKE)
48 # define CMAKE_USE_KDEVELOP
49 # endif
50 #endif
52 #if defined(CMAKE_BUILD_WITH_CMAKE)
53 # define CMAKE_USE_ECLIPSE
54 #endif
56 #if defined(__MINGW32__) && !defined(CMAKE_BUILD_WITH_CMAKE)
57 # define CMAKE_BOOT_MINGW
58 #endif
60 // include the generator
61 #if defined(_WIN32) && !defined(__CYGWIN__)
62 # if !defined(CMAKE_BOOT_MINGW)
63 # include "cmGlobalVisualStudio6Generator.h"
64 # include "cmGlobalVisualStudio7Generator.h"
65 # include "cmGlobalVisualStudio71Generator.h"
66 # include "cmGlobalVisualStudio8Generator.h"
67 # include "cmGlobalVisualStudio9Generator.h"
68 # include "cmGlobalVisualStudio9Win64Generator.h"
69 # include "cmGlobalVisualStudio8Win64Generator.h"
70 # include "cmGlobalBorlandMakefileGenerator.h"
71 # include "cmGlobalNMakeMakefileGenerator.h"
72 # include "cmGlobalWatcomWMakeGenerator.h"
73 # define CMAKE_HAVE_VS_GENERATORS
74 # endif
75 # include "cmGlobalMSYSMakefileGenerator.h"
76 # include "cmGlobalMinGWMakefileGenerator.h"
77 # include "cmWin32ProcessExecution.h"
78 #else
79 #endif
80 #include "cmGlobalUnixMakefileGenerator3.h"
82 #if defined(CMAKE_HAVE_VS_GENERATORS)
83 #include "cmCallVisualStudioMacro.h"
84 #endif
86 #if !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
87 # include "cmExtraCodeBlocksGenerator.h"
88 #endif
90 #ifdef CMAKE_USE_KDEVELOP
91 # include "cmGlobalKdevelopGenerator.h"
92 #endif
94 #ifdef CMAKE_USE_ECLIPSE
95 # include "cmExtraEclipseCDT4Generator.h"
96 #endif
98 #include <stdlib.h> // required for atoi
100 #if defined( __APPLE__ )
101 # if defined(CMAKE_BUILD_WITH_CMAKE)
102 # include "cmGlobalXCodeGenerator.h"
103 # define CMAKE_USE_XCODE 1
104 # endif
105 # include <sys/types.h>
106 # include <sys/time.h>
107 # include <sys/resource.h>
108 #endif
110 #include <sys/stat.h> // struct stat
112 #include <memory> // auto_ptr
114 static bool cmakeCheckStampFile(const char* stampName);
115 static bool cmakeCheckStampList(const char* stampName);
117 void cmNeedBackwardsCompatibility(const std::string& variable,
118 int access_type, void*, const char*, const cmMakefile*)
120 #ifdef CMAKE_BUILD_WITH_CMAKE
121 if (access_type == cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS)
123 std::string message = "An attempt was made to access a variable: ";
124 message += variable;
125 message +=
126 " that has not been defined. Some variables were always defined "
127 "by CMake in versions prior to 1.6. To fix this you might need to set "
128 "the cache value of CMAKE_BACKWARDS_COMPATIBILITY to 1.4 or less. If "
129 "you are writing a CMakeList file, (or have already set "
130 "CMAKE_BACKWARDS_COMPATABILITY to 1.4 or less) then you probably need "
131 "to include a CMake module to test for the feature this variable "
132 "defines.";
133 cmSystemTools::Error(message.c_str());
135 #else
136 (void)variable;
137 (void)access_type;
138 #endif
141 cmake::cmake()
143 this->SuppressDevWarnings = false;
144 this->DoSuppressDevWarnings = false;
145 this->DebugOutput = false;
146 this->DebugTryCompile = false;
147 this->ClearBuildSystem = false;
148 this->FileComparison = new cmFileTimeComparison;
150 this->Policies = new cmPolicies();
151 this->InitializeProperties();
153 #ifdef __APPLE__
154 struct rlimit rlp;
155 if(!getrlimit(RLIMIT_STACK, &rlp))
157 if(rlp.rlim_cur != rlp.rlim_max)
159 rlp.rlim_cur = rlp.rlim_max;
160 setrlimit(RLIMIT_STACK, &rlp);
163 #endif
165 // If MAKEFLAGS are given in the environment, remove the environment
166 // variable. This will prevent try-compile from succeeding when it
167 // should fail (if "-i" is an option). We cannot simply test
168 // whether "-i" is given and remove it because some make programs
169 // encode the MAKEFLAGS variable in a strange way.
170 if(getenv("MAKEFLAGS"))
172 cmSystemTools::PutEnv("MAKEFLAGS=");
175 this->Verbose = false;
176 this->InTryCompile = false;
177 this->CacheManager = new cmCacheManager;
178 this->GlobalGenerator = 0;
179 this->ProgressCallback = 0;
180 this->ProgressCallbackClientData = 0;
181 this->ScriptMode = false;
183 #ifdef CMAKE_BUILD_WITH_CMAKE
184 this->VariableWatch = new cmVariableWatch;
185 this->VariableWatch->AddWatch("CMAKE_WORDS_BIGENDIAN",
186 cmNeedBackwardsCompatibility);
187 this->VariableWatch->AddWatch("CMAKE_SIZEOF_INT",
188 cmNeedBackwardsCompatibility);
189 this->VariableWatch->AddWatch("CMAKE_X_LIBS",
190 cmNeedBackwardsCompatibility);
191 #endif
193 this->AddDefaultGenerators();
194 this->AddDefaultExtraGenerators();
195 this->AddDefaultCommands();
197 // Make sure we can capture the build tool output.
198 cmSystemTools::EnableVSConsoleOutput();
201 cmake::~cmake()
203 delete this->CacheManager;
204 delete this->Policies;
205 if (this->GlobalGenerator)
207 delete this->GlobalGenerator;
208 this->GlobalGenerator = 0;
210 for(RegisteredCommandsMap::iterator j = this->Commands.begin();
211 j != this->Commands.end(); ++j)
213 delete (*j).second;
215 #ifdef CMAKE_BUILD_WITH_CMAKE
216 delete this->VariableWatch;
217 #endif
218 delete this->FileComparison;
221 void cmake::InitializeProperties()
223 this->Properties.clear();
224 this->Properties.SetCMakeInstance(this);
225 this->AccessedProperties.clear();
226 this->PropertyDefinitions.clear();
228 // initialize properties
229 cmSourceFile::DefineProperties(this);
230 cmTarget::DefineProperties(this);
231 cmMakefile::DefineProperties(this);
232 cmTest::DefineProperties(this);
233 cmake::DefineProperties(this);
236 void cmake::CleanupCommandsAndMacros()
238 this->InitializeProperties();
239 std::vector<cmCommand*> commands;
240 for(RegisteredCommandsMap::iterator j = this->Commands.begin();
241 j != this->Commands.end(); ++j)
243 if ( !j->second->IsA("cmMacroHelperCommand") &&
244 !j->second->IsA("cmFunctionHelperCommand"))
246 commands.push_back(j->second);
248 else
250 delete j->second;
253 this->Commands.erase(this->Commands.begin(), this->Commands.end());
254 std::vector<cmCommand*>::iterator it;
255 for ( it = commands.begin(); it != commands.end();
256 ++ it )
258 this->Commands[cmSystemTools::LowerCase((*it)->GetName())] = *it;
262 bool cmake::CommandExists(const char* name) const
264 std::string sName = cmSystemTools::LowerCase(name);
265 return (this->Commands.find(sName) != this->Commands.end());
268 cmCommand *cmake::GetCommand(const char *name)
270 cmCommand* rm = 0;
271 std::string sName = cmSystemTools::LowerCase(name);
272 RegisteredCommandsMap::iterator pos = this->Commands.find(sName);
273 if (pos != this->Commands.end())
275 rm = (*pos).second;
277 return rm;
280 void cmake::RenameCommand(const char*oldName, const char* newName)
282 // if the command already exists, free the old one
283 std::string sOldName = cmSystemTools::LowerCase(oldName);
284 std::string sNewName = cmSystemTools::LowerCase(newName);
285 RegisteredCommandsMap::iterator pos = this->Commands.find(sOldName);
286 if ( pos == this->Commands.end() )
288 return;
290 cmCommand* cmd = pos->second;
292 pos = this->Commands.find(sNewName);
293 if (pos != this->Commands.end())
295 delete pos->second;
296 this->Commands.erase(pos);
298 this->Commands.insert(RegisteredCommandsMap::value_type(sNewName, cmd));
299 pos = this->Commands.find(sOldName);
300 this->Commands.erase(pos);
303 void cmake::RemoveCommand(const char* name)
305 std::string sName = cmSystemTools::LowerCase(name);
306 RegisteredCommandsMap::iterator pos = this->Commands.find(sName);
307 if ( pos != this->Commands.end() )
309 delete pos->second;
310 this->Commands.erase(pos);
314 void cmake::AddCommand(cmCommand* wg)
316 std::string name = cmSystemTools::LowerCase(wg->GetName());
317 // if the command already exists, free the old one
318 RegisteredCommandsMap::iterator pos = this->Commands.find(name);
319 if (pos != this->Commands.end())
321 delete pos->second;
322 this->Commands.erase(pos);
324 this->Commands.insert( RegisteredCommandsMap::value_type(name, wg));
328 void cmake::RemoveUnscriptableCommands()
330 std::vector<std::string> unscriptableCommands;
331 cmake::RegisteredCommandsMap* commands = this->GetCommands();
332 for (cmake::RegisteredCommandsMap::const_iterator pos = commands->begin();
333 pos != commands->end();
334 ++pos)
336 if (!pos->second->IsScriptable())
338 unscriptableCommands.push_back(pos->first);
342 for(std::vector<std::string>::const_iterator it=unscriptableCommands.begin();
343 it != unscriptableCommands.end();
344 ++it)
346 this->RemoveCommand(it->c_str());
350 // Parse the args
351 bool cmake::SetCacheArgs(const std::vector<std::string>& args)
353 for(unsigned int i=1; i < args.size(); ++i)
355 std::string arg = args[i];
356 if(arg.find("-D",0) == 0)
358 std::string entry = arg.substr(2);
359 if(entry.size() == 0)
361 ++i;
362 if(i < args.size())
364 entry = args[i];
366 else
368 cmSystemTools::Error("-D must be followed with VAR=VALUE.");
369 return false;
372 std::string var, value;
373 cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
374 if(cmCacheManager::ParseEntry(entry.c_str(), var, value, type) ||
375 cmCacheManager::ParseEntry(entry.c_str(), var, value))
377 this->CacheManager->AddCacheEntry(var.c_str(), value.c_str(),
378 "No help, variable specified on the command line.", type);
380 else
382 std::cerr << "Parse error in command line argument: " << arg << "\n"
383 << "Should be: VAR:type=value\n";
384 cmSystemTools::Error("No cmake scrpt provided.");
385 return false;
388 else if(arg.find("-Wno-dev",0) == 0)
390 this->SuppressDevWarnings = true;
391 this->DoSuppressDevWarnings = true;
393 else if(arg.find("-Wdev",0) == 0)
395 this->SuppressDevWarnings = false;
396 this->DoSuppressDevWarnings = true;
398 else if(arg.find("-U",0) == 0)
400 std::string entryPattern = arg.substr(2);
401 if(entryPattern.size() == 0)
403 ++i;
404 if(i < args.size())
406 entryPattern = args[i];
408 else
410 cmSystemTools::Error("-U must be followed with VAR.");
411 return false;
414 cmsys::RegularExpression regex(
415 cmsys::Glob::PatternToRegex(entryPattern.c_str(), true).c_str());
416 //go through all cache entries and collect the vars which will be removed
417 std::vector<std::string> entriesToDelete;
418 cmCacheManager::CacheIterator it =
419 this->CacheManager->GetCacheIterator();
420 for ( it.Begin(); !it.IsAtEnd(); it.Next() )
422 cmCacheManager::CacheEntryType t = it.GetType();
423 if(t != cmCacheManager::STATIC)
425 std::string entryName = it.GetName();
426 if (regex.find(entryName.c_str()))
428 entriesToDelete.push_back(entryName);
433 // now remove them from the cache
434 for(std::vector<std::string>::const_iterator currentEntry =
435 entriesToDelete.begin();
436 currentEntry != entriesToDelete.end();
437 ++currentEntry)
439 this->CacheManager->RemoveCacheEntry(currentEntry->c_str());
442 else if(arg.find("-C",0) == 0)
444 std::string path = arg.substr(2);
445 if ( path.size() == 0 )
447 ++i;
448 if(i < args.size())
450 path = args[i];
452 else
454 cmSystemTools::Error("-C must be followed by a file name.");
455 return false;
458 std::cerr << "loading initial cache file " << path.c_str() << "\n";
459 this->ReadListFile(path.c_str());
461 else if(arg.find("-P",0) == 0)
463 i++;
464 if(i >= args.size())
466 cmSystemTools::Error("-P must be followed by a file name.");
467 return false;
469 std::string path = args[i];
470 if ( path.size() == 0 )
472 cmSystemTools::Error("No cmake script provided.");
473 return false;
475 this->ReadListFile(path.c_str());
478 return true;
481 void cmake::ReadListFile(const char *path)
483 // if a generator was not yet created, temporarily create one
484 cmGlobalGenerator *gg = this->GetGlobalGenerator();
485 bool created = false;
487 // if a generator was not specified use a generic one
488 if (!gg)
490 gg = new cmGlobalGenerator;
491 gg->SetCMakeInstance(this);
492 created = true;
495 // read in the list file to fill the cache
496 if(path)
498 std::auto_ptr<cmLocalGenerator> lg(gg->CreateLocalGenerator());
499 lg->SetGlobalGenerator(gg);
500 lg->GetMakefile()->SetHomeOutputDirectory
501 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
502 lg->GetMakefile()->SetStartOutputDirectory
503 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
504 lg->GetMakefile()->SetHomeDirectory
505 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
506 lg->GetMakefile()->SetStartDirectory
507 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
508 if (!lg->GetMakefile()->ReadListFile(0, path))
510 cmSystemTools::Error("Error processing file:", path);
514 // free generic one if generated
515 if (created)
517 delete gg;
521 // Parse the args
522 void cmake::SetArgs(const std::vector<std::string>& args)
524 bool directoriesSet = false;
525 for(unsigned int i=1; i < args.size(); ++i)
527 std::string arg = args[i];
528 if(arg.find("-H",0) == 0)
530 directoriesSet = true;
531 std::string path = arg.substr(2);
532 path = cmSystemTools::CollapseFullPath(path.c_str());
533 cmSystemTools::ConvertToUnixSlashes(path);
534 this->SetHomeDirectory(path.c_str());
536 else if(arg.find("-S",0) == 0)
538 // There is no local generate anymore. Ignore -S option.
540 else if(arg.find("-O",0) == 0)
542 // There is no local generate anymore. Ignore -O option.
544 else if(arg.find("-B",0) == 0)
546 directoriesSet = true;
547 std::string path = arg.substr(2);
548 path = cmSystemTools::CollapseFullPath(path.c_str());
549 cmSystemTools::ConvertToUnixSlashes(path);
550 this->SetHomeOutputDirectory(path.c_str());
552 else if((i < args.size()-1) && (arg.find("--check-build-system",0) == 0))
554 this->CheckBuildSystemArgument = args[++i];
555 this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
557 else if((i < args.size()-1) && (arg.find("--check-stamp-file",0) == 0))
559 this->CheckStampFile = args[++i];
561 else if((i < args.size()-1) && (arg.find("--check-stamp-list",0) == 0))
563 this->CheckStampList = args[++i];
565 #if defined(CMAKE_HAVE_VS_GENERATORS)
566 else if((i < args.size()-1) && (arg.find("--vs-solution-file",0) == 0))
568 this->VSSolutionFile = args[++i];
570 #endif
571 else if(arg.find("-V",0) == 0)
573 this->Verbose = true;
575 else if(arg.find("-D",0) == 0)
577 // skip for now
579 else if(arg.find("-U",0) == 0)
581 // skip for now
583 else if(arg.find("-C",0) == 0)
585 // skip for now
587 else if(arg.find("-P",0) == 0)
589 // skip for now
590 i++;
592 else if(arg.find("-Wno-dev",0) == 0)
594 // skip for now
595 i++;
597 else if(arg.find("-Wdev",0) == 0)
599 // skip for now
600 i++;
602 else if(arg.find("--graphviz=",0) == 0)
604 std::string path = arg.substr(strlen("--graphviz="));
605 path = cmSystemTools::CollapseFullPath(path.c_str());
606 cmSystemTools::ConvertToUnixSlashes(path);
607 this->GraphVizFile = path;
608 if ( this->GraphVizFile.empty() )
610 cmSystemTools::Error("No file specified for --graphviz");
613 else if(arg.find("--debug-trycompile",0) == 0)
615 std::cout << "debug trycompile on\n";
616 this->DebugTryCompileOn();
618 else if(arg.find("--debug-output",0) == 0)
620 std::cout << "Running with debug output on.\n";
621 this->SetDebugOutputOn(true);
623 else if(arg.find("-G",0) == 0)
625 std::string value = arg.substr(2);
626 if(value.size() == 0)
628 ++i;
629 if(i >= args.size())
631 cmSystemTools::Error("No generator specified for -G");
632 return;
634 value = args[i];
636 cmGlobalGenerator* gen =
637 this->CreateGlobalGenerator(value.c_str());
638 if(!gen)
640 cmSystemTools::Error("Could not create named generator ",
641 value.c_str());
643 else
645 this->SetGlobalGenerator(gen);
648 // no option assume it is the path to the source
649 else
651 directoriesSet = true;
652 this->SetDirectoriesFromFile(arg.c_str());
655 if(!directoriesSet)
657 this->SetHomeOutputDirectory
658 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
659 this->SetStartOutputDirectory
660 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
661 this->SetHomeDirectory
662 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
663 this->SetStartDirectory
664 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
667 this->SetStartDirectory(this->GetHomeDirectory());
668 this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
671 //----------------------------------------------------------------------------
672 void cmake::SetDirectoriesFromFile(const char* arg)
674 // Check if the argument refers to a CMakeCache.txt or
675 // CMakeLists.txt file.
676 std::string listPath;
677 std::string cachePath;
678 bool argIsFile = false;
679 if(cmSystemTools::FileIsDirectory(arg))
681 std::string path = cmSystemTools::CollapseFullPath(arg);
682 cmSystemTools::ConvertToUnixSlashes(path);
683 std::string cacheFile = path;
684 cacheFile += "/CMakeCache.txt";
685 std::string listFile = path;
686 listFile += "/CMakeLists.txt";
687 if(cmSystemTools::FileExists(cacheFile.c_str()))
689 cachePath = path;
691 if(cmSystemTools::FileExists(listFile.c_str()))
693 listPath = path;
696 else if(cmSystemTools::FileExists(arg))
698 argIsFile = true;
699 std::string fullPath = cmSystemTools::CollapseFullPath(arg);
700 std::string name = cmSystemTools::GetFilenameName(fullPath.c_str());
701 name = cmSystemTools::LowerCase(name);
702 if(name == "cmakecache.txt")
704 cachePath = cmSystemTools::GetFilenamePath(fullPath.c_str());
706 else if(name == "cmakelists.txt")
708 listPath = cmSystemTools::GetFilenamePath(fullPath.c_str());
711 else
713 // Specified file or directory does not exist. Try to set things
714 // up to produce a meaningful error message.
715 std::string fullPath = cmSystemTools::CollapseFullPath(arg);
716 std::string name = cmSystemTools::GetFilenameName(fullPath.c_str());
717 name = cmSystemTools::LowerCase(name);
718 if(name == "cmakecache.txt" || name == "cmakelists.txt")
720 argIsFile = true;
721 listPath = cmSystemTools::GetFilenamePath(fullPath.c_str());
723 else
725 listPath = fullPath;
729 // If there is a CMakeCache.txt file, use its settings.
730 if(cachePath.length() > 0)
732 cmCacheManager* cachem = this->GetCacheManager();
733 cmCacheManager::CacheIterator it = cachem->NewIterator();
734 if(cachem->LoadCache(cachePath.c_str()) &&
735 it.Find("CMAKE_HOME_DIRECTORY"))
737 this->SetHomeOutputDirectory(cachePath.c_str());
738 this->SetStartOutputDirectory(cachePath.c_str());
739 this->SetHomeDirectory(it.GetValue());
740 this->SetStartDirectory(it.GetValue());
741 return;
745 // If there is a CMakeLists.txt file, use it as the source tree.
746 if(listPath.length() > 0)
748 this->SetHomeDirectory(listPath.c_str());
749 this->SetStartDirectory(listPath.c_str());
751 if(argIsFile)
753 // Source CMakeLists.txt file given. It was probably dropped
754 // onto the executable in a GUI. Default to an in-source build.
755 this->SetHomeOutputDirectory(listPath.c_str());
756 this->SetStartOutputDirectory(listPath.c_str());
758 else
760 // Source directory given on command line. Use current working
761 // directory as build tree.
762 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
763 this->SetHomeOutputDirectory(cwd.c_str());
764 this->SetStartOutputDirectory(cwd.c_str());
766 return;
769 // We didn't find a CMakeLists.txt or CMakeCache.txt file from the
770 // argument. Assume it is the path to the source tree, and use the
771 // current working directory as the build tree.
772 std::string full = cmSystemTools::CollapseFullPath(arg);
773 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
774 this->SetHomeDirectory(full.c_str());
775 this->SetStartDirectory(full.c_str());
776 this->SetHomeOutputDirectory(cwd.c_str());
777 this->SetStartOutputDirectory(cwd.c_str());
780 // at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the
781 // cache
782 int cmake::AddCMakePaths()
784 // Find the cmake executable
785 std::string cMakeSelf = cmSystemTools::GetExecutableDirectory();
786 cMakeSelf = cmSystemTools::GetRealPath(cMakeSelf.c_str());
787 cMakeSelf += "/cmake";
788 cMakeSelf += cmSystemTools::GetExecutableExtension();
789 #if __APPLE__
790 // on the apple this might be the gui bundle
791 if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
793 cMakeSelf = cmSystemTools::GetExecutableDirectory();
794 cMakeSelf = cmSystemTools::GetRealPath(cMakeSelf.c_str());
795 cMakeSelf += "../../../..";
796 cMakeSelf = cmSystemTools::GetRealPath(cMakeSelf.c_str());
797 cMakeSelf = cmSystemTools::CollapseFullPath(cMakeSelf.c_str());
798 cMakeSelf += "/cmake";
799 std::cerr << cMakeSelf.c_str() << "\n";
801 #endif
802 if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
804 cmSystemTools::Error("CMake executable cannot be found at ",
805 cMakeSelf.c_str());
806 return 0;
808 // Save the value in the cache
809 this->CacheManager->AddCacheEntry
810 ("CMAKE_COMMAND",cMakeSelf.c_str(), "Path to CMake executable.",
811 cmCacheManager::INTERNAL);
812 // if the edit command is not yet in the cache,
813 // or if CMakeEditCommand has been set on this object,
814 // then set the CMAKE_EDIT_COMMAND in the cache
815 // This will mean that the last gui to edit the cache
816 // will be the one that make edit_cache uses.
817 if(!this->GetCacheDefinition("CMAKE_EDIT_COMMAND")
818 || !this->CMakeEditCommand.empty())
820 // Find and save the command to edit the cache
821 std::string editCacheCommand;
822 if(!this->CMakeEditCommand.empty())
824 editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf)
825 + std::string("/")
826 + this->CMakeEditCommand
827 + cmSystemTools::GetFilenameExtension(cMakeSelf);
829 if( !cmSystemTools::FileExists(editCacheCommand.c_str()))
831 editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
832 "/ccmake" + cmSystemTools::GetFilenameExtension(cMakeSelf);
834 if( !cmSystemTools::FileExists(editCacheCommand.c_str()))
836 editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
837 "/CMakeSetup" + cmSystemTools::GetFilenameExtension(cMakeSelf);
839 if(cmSystemTools::FileExists(editCacheCommand.c_str()))
841 this->CacheManager->AddCacheEntry
842 ("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
843 "Path to cache edit program executable.", cmCacheManager::INTERNAL);
846 std::string ctestCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
847 "/ctest" + cmSystemTools::GetFilenameExtension(cMakeSelf);
848 if(cmSystemTools::FileExists(ctestCommand.c_str()))
850 this->CacheManager->AddCacheEntry
851 ("CMAKE_CTEST_COMMAND", ctestCommand.c_str(),
852 "Path to ctest program executable.", cmCacheManager::INTERNAL);
854 std::string cpackCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
855 "/cpack" + cmSystemTools::GetFilenameExtension(cMakeSelf);
856 if(cmSystemTools::FileExists(ctestCommand.c_str()))
858 this->CacheManager->AddCacheEntry
859 ("CMAKE_CPACK_COMMAND", cpackCommand.c_str(),
860 "Path to cpack program executable.", cmCacheManager::INTERNAL);
863 // do CMAKE_ROOT, look for the environment variable first
864 std::string cMakeRoot;
865 std::string modules;
866 if (getenv("CMAKE_ROOT"))
868 cMakeRoot = getenv("CMAKE_ROOT");
869 modules = cMakeRoot + "/Modules/CMake.cmake";
871 if(!cmSystemTools::FileExists(modules.c_str()))
873 // next try exe/..
874 cMakeRoot = cmSystemTools::GetRealPath(cMakeSelf.c_str());
875 cMakeRoot = cmSystemTools::GetProgramPath(cMakeRoot.c_str());
876 std::string::size_type slashPos = cMakeRoot.rfind("/");
877 if(slashPos != std::string::npos)
879 cMakeRoot = cMakeRoot.substr(0, slashPos);
881 // is there no Modules direcory there?
882 modules = cMakeRoot + "/Modules/CMake.cmake";
885 if (!cmSystemTools::FileExists(modules.c_str()))
887 // try exe/../share/cmake
888 cMakeRoot += CMAKE_DATA_DIR;
889 modules = cMakeRoot + "/Modules/CMake.cmake";
891 #ifdef CMAKE_ROOT_DIR
892 if (!cmSystemTools::FileExists(modules.c_str()))
894 // try compiled in root directory
895 cMakeRoot = CMAKE_ROOT_DIR;
896 modules = cMakeRoot + "/Modules/CMake.cmake";
898 #endif
899 if (!cmSystemTools::FileExists(modules.c_str()))
901 // try
902 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
903 cMakeRoot += CMAKE_DATA_DIR;
904 modules = cMakeRoot + "/Modules/CMake.cmake";
906 if(!cmSystemTools::FileExists(modules.c_str()))
908 // next try exe
909 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
910 // is there no Modules direcory there?
911 modules = cMakeRoot + "/Modules/CMake.cmake";
913 if (!cmSystemTools::FileExists(modules.c_str()))
915 // couldn't find modules
916 cmSystemTools::Error("Could not find CMAKE_ROOT !!!\n"
917 "CMake has most likely not been installed correctly.\n"
918 "Modules directory not found in\n",
919 cMakeRoot.c_str());
920 return 0;
922 this->CacheManager->AddCacheEntry
923 ("CMAKE_ROOT", cMakeRoot.c_str(),
924 "Path to CMake installation.", cmCacheManager::INTERNAL);
926 #ifdef _WIN32
927 std::string comspec = "cmw9xcom.exe";
928 cmSystemTools::SetWindows9xComspecSubstitute(comspec.c_str());
929 #endif
930 return 1;
935 void CMakeCommandUsage(const char* program)
937 cmOStringStream errorStream;
939 #ifdef CMAKE_BUILD_WITH_CMAKE
940 errorStream
941 << "cmake version " << cmVersion::GetCMakeVersion() << "\n";
942 #else
943 errorStream
944 << "cmake bootstrap\n";
945 #endif
947 errorStream
948 << "Usage: " << program << " -E [command] [arguments ...]\n"
949 << "Available commands: \n"
950 << " chdir dir cmd [args]... - run command in a given directory\n"
951 << " copy file destination - copy file to destination (either file "
952 "or directory)\n"
953 << " copy_if_different in-file out-file - copy file if input has "
954 "changed\n"
955 << " copy_directory source destination - copy directory 'source' "
956 "content to directory 'destination'\n"
957 << " compare_files file1 file2 - check if file1 is same as file2\n"
958 << " echo [string]... - displays arguments as text\n"
959 << " echo_append [string]... - displays arguments as text but no new "
960 "line\n"
961 << " environment - display the current enviroment\n"
962 << " make_directory dir - create a directory\n"
963 << " md5sum file1 [...] - compute md5sum of files\n"
964 << " remove_directory dir - remove a directory and its contents\n"
965 << " remove [-f] file1 file2 ... - remove the file(s), use -f to force "
966 "it\n"
967 << " tar [cxt][vfz] file.tar file/dir1 file/dir2 ... - create a tar "
968 "archive\n"
969 << " time command [args] ... - run command and return elapsed time\n"
970 << " touch file - touch a file.\n"
971 << " touch_nocreate file - touch a file but do not create it.\n"
972 #if defined(_WIN32) && !defined(__CYGWIN__)
973 << " write_regv key value - write registry value\n"
974 << " delete_regv key - delete registry value\n"
975 << " comspec - on windows 9x use this for RunCommand\n"
976 #else
977 << " create_symlink old new - create a symbolic link new -> old\n"
978 #endif
981 cmSystemTools::Error(errorStream.str().c_str());
984 int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
986 if (args.size() > 1)
988 // Copy file
989 if (args[1] == "copy" && args.size() == 4)
991 if(!cmSystemTools::cmCopyFile(args[2].c_str(), args[3].c_str()))
993 std::cerr << "Error copying file \"" << args[2].c_str()
994 << "\" to \"" << args[3].c_str() << "\".\n";
995 return 1;
997 return 0;
1000 // Copy file if different.
1001 if (args[1] == "copy_if_different" && args.size() == 4)
1003 if(!cmSystemTools::CopyFileIfDifferent(args[2].c_str(),
1004 args[3].c_str()))
1006 std::cerr << "Error copying file (if different) from \""
1007 << args[2].c_str() << "\" to \"" << args[3].c_str()
1008 << "\".\n";
1009 return 1;
1011 return 0;
1014 // Copy directory content
1015 if (args[1] == "copy_directory" && args.size() == 4)
1017 if(!cmSystemTools::CopyADirectory(args[2].c_str(), args[3].c_str()))
1019 std::cerr << "Error copying directory from \""
1020 << args[2].c_str() << "\" to \"" << args[3].c_str()
1021 << "\".\n";
1022 return 1;
1024 return 0;
1027 // Compare files
1028 if (args[1] == "compare_files" && args.size() == 4)
1030 if(cmSystemTools::FilesDiffer(args[2].c_str(), args[3].c_str()))
1032 std::cerr << "Files \""
1033 << args[2].c_str() << "\" to \"" << args[3].c_str()
1034 << "\" are different.\n";
1035 return 1;
1037 return 0;
1040 // Echo string
1041 else if (args[1] == "echo" )
1043 unsigned int cc;
1044 const char* space = "";
1045 for ( cc = 2; cc < args.size(); cc ++ )
1047 std::cout << space << args[cc];
1048 space = " ";
1050 std::cout << std::endl;
1051 return 0;
1054 // Echo string no new line
1055 else if (args[1] == "echo_append" )
1057 unsigned int cc;
1058 const char* space = "";
1059 for ( cc = 2; cc < args.size(); cc ++ )
1061 std::cout << space << args[cc];
1062 space = " ";
1064 return 0;
1067 #if defined(CMAKE_BUILD_WITH_CMAKE)
1068 // Command to create a symbolic link. Fails on platforms not
1069 // supporting them.
1070 else if (args[1] == "environment" )
1072 std::vector<std::string> env = cmSystemTools::GetEnvironmentVariables();
1073 std::vector<std::string>::iterator it;
1074 for ( it = env.begin(); it != env.end(); ++ it )
1076 std::cout << it->c_str() << std::endl;
1078 return 0;
1080 #endif
1082 else if (args[1] == "make_directory" && args.size() == 3)
1084 if(!cmSystemTools::MakeDirectory(args[2].c_str()))
1086 std::cerr << "Error making directory \"" << args[2].c_str()
1087 << "\".\n";
1088 return 1;
1090 return 0;
1093 else if (args[1] == "remove_directory" && args.size() == 3)
1095 if(cmSystemTools::FileIsDirectory(args[2].c_str()) &&
1096 !cmSystemTools::RemoveADirectory(args[2].c_str()))
1098 std::cerr << "Error removing directory \"" << args[2].c_str()
1099 << "\".\n";
1100 return 1;
1102 return 0;
1105 // Remove file
1106 else if (args[1] == "remove" && args.size() > 2)
1108 bool force = false;
1109 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1111 if(args[cc] == "\\-f" || args[cc] == "-f")
1113 force = true;
1115 else
1117 // Complain if the file could not be removed, still exists,
1118 // and the -f option was not given.
1119 if(!cmSystemTools::RemoveFile(args[cc].c_str()) && !force &&
1120 cmSystemTools::FileExists(args[cc].c_str()))
1122 return 1;
1126 return 0;
1128 // Touch file
1129 else if (args[1] == "touch" && args.size() > 2)
1131 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1133 // Complain if the file could not be removed, still exists,
1134 // and the -f option was not given.
1135 if(!cmSystemTools::Touch(args[cc].c_str(), true))
1137 return 1;
1140 return 0;
1142 // Touch file
1143 else if (args[1] == "touch_nocreate" && args.size() > 2)
1145 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1147 // Complain if the file could not be removed, still exists,
1148 // and the -f option was not given.
1149 if(!cmSystemTools::Touch(args[cc].c_str(), false))
1151 return 1;
1154 return 0;
1157 // Clock command
1158 else if (args[1] == "time" && args.size() > 2)
1160 std::string command = args[2];
1161 for (std::string::size_type cc = 3; cc < args.size(); cc ++)
1163 command += " ";
1164 command += args[cc];
1167 clock_t clock_start, clock_finish;
1168 time_t time_start, time_finish;
1170 time(&time_start);
1171 clock_start = clock();
1173 cmSystemTools::RunSingleCommand(command.c_str());
1175 clock_finish = clock();
1176 time(&time_finish);
1178 double clocks_per_sec = static_cast<double>(CLOCKS_PER_SEC);
1179 std::cout << "Elapsed time: "
1180 << static_cast<long>(time_finish - time_start) << " s. (time)"
1181 << ", "
1182 << static_cast<double>(clock_finish - clock_start) / clocks_per_sec
1183 << " s. (clock)"
1184 << "\n";
1185 return 0;
1188 // Command to calculate the md5sum of a file
1189 else if (args[1] == "md5sum" && args.size() >= 3)
1191 char md5out[32];
1192 int retval = 0;
1193 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1195 const char *filename = args[cc].c_str();
1196 // Cannot compute md5sum of a directory
1197 if(cmSystemTools::FileIsDirectory(filename))
1199 std::cerr << "Error: " << filename << " is a directory" << std::endl;
1200 retval++;
1202 else if(!cmSystemTools::ComputeFileMD5(filename, md5out))
1204 // To mimic md5sum behavior in a shell:
1205 std::cerr << filename << ": No such file or directory" << std::endl;
1206 retval++;
1208 else
1210 std::cout << std::string(md5out,32) << " " << filename << std::endl;
1213 return retval;
1216 // Command to change directory and run a program.
1217 else if (args[1] == "chdir" && args.size() >= 4)
1219 std::string directory = args[2];
1220 if(!cmSystemTools::FileExists(directory.c_str()))
1222 cmSystemTools::Error("Directory does not exist for chdir command: ",
1223 args[2].c_str());
1224 return 0;
1227 std::string command = "\"";
1228 command += args[3];
1229 command += "\"";
1230 for (std::string::size_type cc = 4; cc < args.size(); cc ++)
1232 command += " \"";
1233 command += args[cc];
1234 command += "\"";
1236 int retval = 0;
1237 int timeout = 0;
1238 if ( cmSystemTools::RunSingleCommand(command.c_str(), 0, &retval,
1239 directory.c_str(), true, timeout) )
1241 return retval;
1244 return 1;
1247 // Command to start progress for a build
1248 else if (args[1] == "cmake_progress_start" && args.size() == 4)
1250 // bascially remove the directory
1251 std::string dirName = args[2];
1252 dirName += "/Progress";
1253 cmSystemTools::RemoveADirectory(dirName.c_str());
1255 // is the last argument a filename that exists?
1256 FILE *countFile = fopen(args[3].c_str(),"r");
1257 int count;
1258 if (countFile)
1260 fscanf(countFile,"%i",&count);
1261 fclose(countFile);
1263 else
1265 count = atoi(args[3].c_str());
1267 if (count)
1269 cmSystemTools::MakeDirectory(dirName.c_str());
1270 // write the count into the directory
1271 std::string fName = dirName;
1272 fName += "/count.txt";
1273 FILE *progFile = fopen(fName.c_str(),"w");
1274 if (progFile)
1276 fprintf(progFile,"%i\n",count);
1277 fclose(progFile);
1280 return 0;
1283 // Command to report progress for a build
1284 else if (args[1] == "cmake_progress_report" && args.size() >= 3)
1286 std::string dirName = args[2];
1287 dirName += "/Progress";
1288 std::string fName;
1289 FILE *progFile;
1291 // read the count
1292 fName = dirName;
1293 fName += "/count.txt";
1294 progFile = fopen(fName.c_str(),"r");
1295 int count = 0;
1296 if (!progFile)
1298 return 0;
1300 else
1302 fscanf(progFile,"%i",&count);
1303 fclose(progFile);
1305 unsigned int i;
1306 for (i = 3; i < args.size(); ++i)
1308 fName = dirName;
1309 fName += "/";
1310 fName += args[i];
1311 progFile = fopen(fName.c_str(),"w");
1312 if (progFile)
1314 fprintf(progFile,"empty");
1315 fclose(progFile);
1318 int fileNum = static_cast<int>
1319 (cmsys::Directory::GetNumberOfFilesInDirectory(dirName.c_str()));
1320 if (count > 0)
1322 // print the progress
1323 fprintf(stdout,"[%3i%%] ",((fileNum-3)*100)/count);
1325 return 0;
1328 // Command to create a symbolic link. Fails on platforms not
1329 // supporting them.
1330 else if (args[1] == "create_symlink" && args.size() == 4)
1332 const char* destinationFileName = args[3].c_str();
1333 if ( cmSystemTools::FileExists(destinationFileName) )
1335 if ( cmSystemTools::FileIsSymlink(destinationFileName) )
1337 if ( !cmSystemTools::RemoveFile(destinationFileName) ||
1338 cmSystemTools::FileExists(destinationFileName) )
1340 return 0;
1343 else
1345 return 0;
1348 return cmSystemTools::CreateSymlink(args[2].c_str(),
1349 args[3].c_str())? 0:1;
1352 // Internal CMake shared library support.
1353 else if (args[1] == "cmake_symlink_library" && args.size() == 5)
1355 int result = 0;
1356 std::string realName = args[2];
1357 std::string soName = args[3];
1358 std::string name = args[4];
1359 if(soName != realName)
1361 std::string fname = cmSystemTools::GetFilenameName(realName);
1362 if(cmSystemTools::FileExists(soName.c_str()))
1364 cmSystemTools::RemoveFile(soName.c_str());
1366 if(!cmSystemTools::CreateSymlink(fname.c_str(), soName.c_str()))
1368 result = 1;
1371 if(name != soName)
1373 std::string fname = cmSystemTools::GetFilenameName(soName);
1374 if(cmSystemTools::FileExists(soName.c_str()))
1376 cmSystemTools::RemoveFile(name.c_str());
1378 if(!cmSystemTools::CreateSymlink(fname.c_str(), name.c_str()))
1380 result = 1;
1383 return result;
1385 // Internal CMake versioned executable support.
1386 else if (args[1] == "cmake_symlink_executable" && args.size() == 4)
1388 int result = 0;
1389 std::string realName = args[2];
1390 std::string name = args[3];
1391 if(name != realName)
1393 std::string fname = cmSystemTools::GetFilenameName(realName);
1394 if(cmSystemTools::FileExists(realName.c_str()))
1396 cmSystemTools::RemoveFile(name.c_str());
1398 if(!cmSystemTools::CreateSymlink(fname.c_str(), name.c_str()))
1400 result = 1;
1403 return result;
1406 #if defined(CMAKE_HAVE_VS_GENERATORS)
1407 // Internal CMake support for calling Visual Studio macros.
1408 else if (args[1] == "cmake_call_visual_studio_macro" && args.size() >= 4)
1410 // args[2] = full path to .sln file or "ALL"
1411 // args[3] = name of Visual Studio macro to call
1412 // args[4..args.size()-1] = [optional] args for Visual Studio macro
1414 std::string macroArgs;
1416 if (args.size() > 4)
1418 macroArgs = args[4];
1420 for (size_t i = 5; i < args.size(); ++i)
1422 macroArgs += " ";
1423 macroArgs += args[i];
1427 return cmCallVisualStudioMacro::CallMacro(args[2], args[3], macroArgs);
1429 #endif
1431 // Internal CMake dependency scanning support.
1432 else if (args[1] == "cmake_depends" && args.size() >= 6)
1434 // Use the make system's VERBOSE environment variable to enable
1435 // verbose output.
1436 bool verbose = cmSystemTools::GetEnv("VERBOSE") != 0;
1438 // Create a cmake object instance to process dependencies.
1439 cmake cm;
1440 std::string gen;
1441 std::string homeDir;
1442 std::string startDir;
1443 std::string homeOutDir;
1444 std::string startOutDir;
1445 std::string depInfo;
1446 bool color = true;
1447 if(args.size() >= 8)
1449 // Full signature:
1451 // -E cmake_depends <generator>
1452 // <home-src-dir> <start-src-dir>
1453 // <home-out-dir> <start-out-dir>
1454 // <dep-info> [--color=$(COLOR)]
1456 // All paths are provided.
1457 gen = args[2];
1458 homeDir = args[3];
1459 startDir = args[4];
1460 homeOutDir = args[5];
1461 startOutDir = args[6];
1462 depInfo = args[7];
1463 if(args.size() >= 9 &&
1464 args[8].length() > 8 &&
1465 args[8].substr(0, 8) == "--color=")
1467 // Enable or disable color based on the switch value.
1468 color = cmSystemTools::IsOn(args[8].substr(8).c_str());
1471 else
1473 // Support older signature for existing makefiles:
1475 // -E cmake_depends <generator>
1476 // <home-out-dir> <start-out-dir>
1477 // <dep-info>
1479 // Just pretend the source directories are the same as the
1480 // binary directories so at least scanning will work.
1481 gen = args[2];
1482 homeDir = args[3];
1483 startDir = args[4];
1484 homeOutDir = args[3];
1485 startOutDir = args[3];
1486 depInfo = args[5];
1489 // Create a local generator configured for the directory in
1490 // which dependencies will be scanned.
1491 homeDir = cmSystemTools::CollapseFullPath(homeDir.c_str());
1492 startDir = cmSystemTools::CollapseFullPath(startDir.c_str());
1493 homeOutDir = cmSystemTools::CollapseFullPath(homeOutDir.c_str());
1494 startOutDir = cmSystemTools::CollapseFullPath(startOutDir.c_str());
1495 cm.SetHomeDirectory(homeDir.c_str());
1496 cm.SetStartDirectory(startDir.c_str());
1497 cm.SetHomeOutputDirectory(homeOutDir.c_str());
1498 cm.SetStartOutputDirectory(startOutDir.c_str());
1499 if(cmGlobalGenerator* ggd = cm.CreateGlobalGenerator(gen.c_str()))
1501 cm.SetGlobalGenerator(ggd);
1502 std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
1503 lgd->SetGlobalGenerator(ggd);
1504 lgd->GetMakefile()->SetStartDirectory(startDir.c_str());
1505 lgd->GetMakefile()->SetStartOutputDirectory(startOutDir.c_str());
1506 lgd->GetMakefile()->MakeStartDirectoriesCurrent();
1508 // Actually scan dependencies.
1509 return lgd->UpdateDependencies(depInfo.c_str(),
1510 verbose, color)? 0 : 2;
1512 return 1;
1515 // Internal CMake link script support.
1516 else if (args[1] == "cmake_link_script" && args.size() >= 3)
1518 return cmake::ExecuteLinkScript(args);
1521 // Internal CMake unimplemented feature notification.
1522 else if (args[1] == "cmake_unimplemented_variable")
1524 std::cerr << "Feature not implemented for this platform.";
1525 if(args.size() == 3)
1527 std::cerr << " Variable " << args[2] << " is not set.";
1529 std::cerr << std::endl;
1530 return 1;
1532 else if (args[1] == "vs_link_exe")
1534 return cmake::VisualStudioLink(args, 1);
1536 else if (args[1] == "vs_link_dll")
1538 return cmake::VisualStudioLink(args, 2);
1540 #ifdef CMAKE_BUILD_WITH_CMAKE
1541 // Internal CMake color makefile support.
1542 else if (args[1] == "cmake_echo_color")
1544 return cmake::ExecuteEchoColor(args);
1546 #endif
1548 // Tar files
1549 else if (args[1] == "tar" && args.size() > 3)
1551 std::string flags = args[2];
1552 std::string outFile = args[3];
1553 std::vector<cmStdString> files;
1554 for (std::string::size_type cc = 4; cc < args.size(); cc ++)
1556 files.push_back(args[cc]);
1558 bool gzip = false;
1559 bool verbose = false;
1560 if ( flags.find_first_of('z') != flags.npos )
1562 gzip = true;
1564 if ( flags.find_first_of('v') != flags.npos )
1566 verbose = true;
1569 if ( flags.find_first_of('t') != flags.npos )
1571 if ( !cmSystemTools::ListTar(outFile.c_str(), files, gzip, verbose) )
1573 cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
1574 return 1;
1577 else if ( flags.find_first_of('c') != flags.npos )
1579 if ( !cmSystemTools::CreateTar(
1580 outFile.c_str(), files, gzip, verbose) )
1582 cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
1583 return 1;
1586 else if ( flags.find_first_of('x') != flags.npos )
1588 if ( !cmSystemTools::ExtractTar(
1589 outFile.c_str(), files, gzip, verbose) )
1591 cmSystemTools::Error("Problem extracting tar: ", outFile.c_str());
1592 return 1;
1595 return 0;
1598 #if defined(CMAKE_BUILD_WITH_CMAKE)
1599 // Internal CMake Fortran module support.
1600 else if (args[1] == "cmake_copy_f90_mod" && args.size() >= 4)
1602 return cmDependsFortran::CopyModule(args)? 0 : 1;
1604 #endif
1606 #if defined(_WIN32) && !defined(__CYGWIN__)
1607 // Write registry value
1608 else if (args[1] == "write_regv" && args.size() > 3)
1610 return cmSystemTools::WriteRegistryValue(args[2].c_str(),
1611 args[3].c_str()) ? 0 : 1;
1614 // Delete registry value
1615 else if (args[1] == "delete_regv" && args.size() > 2)
1617 return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
1619 // Remove file
1620 else if (args[1] == "comspec" && args.size() > 2)
1622 unsigned int cc;
1623 std::string command = args[2];
1624 for ( cc = 3; cc < args.size(); cc ++ )
1626 command += " " + args[cc];
1628 return cmWin32ProcessExecution::Windows9xHack(command.c_str());
1630 #endif
1633 ::CMakeCommandUsage(args[0].c_str());
1634 return 1;
1637 void cmake::AddExtraGenerator(const char* name,
1638 CreateExtraGeneratorFunctionType newFunction)
1640 cmExternalMakefileProjectGenerator* extraGenerator = newFunction();
1641 const std::vector<std::string>& supportedGlobalGenerators =
1642 extraGenerator->GetSupportedGlobalGenerators();
1644 for(std::vector<std::string>::const_iterator
1645 it = supportedGlobalGenerators.begin();
1646 it != supportedGlobalGenerators.end();
1647 ++it )
1649 std::string fullName = cmExternalMakefileProjectGenerator::
1650 CreateFullGeneratorName(it->c_str(), name);
1651 this->ExtraGenerators[fullName.c_str()] = newFunction;
1653 delete extraGenerator;
1656 void cmake::AddDefaultExtraGenerators()
1658 #if defined(CMAKE_BUILD_WITH_CMAKE)
1659 #if defined(_WIN32) && !defined(__CYGWIN__)
1660 // e.g. kdevelop4 ?
1661 #endif
1663 #if !defined(__CYGWIN__)
1664 this->AddExtraGenerator(cmExtraCodeBlocksGenerator::GetActualName(),
1665 &cmExtraCodeBlocksGenerator::New);
1666 #endif
1668 #ifdef CMAKE_USE_ECLIPSE
1669 this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(),
1670 &cmExtraEclipseCDT4Generator::New);
1671 #endif
1673 #ifdef CMAKE_USE_KDEVELOP
1674 this->AddExtraGenerator(cmGlobalKdevelopGenerator::GetActualName(),
1675 &cmGlobalKdevelopGenerator::New);
1676 // for kdevelop also add the generator with just the name of the
1677 // extra generator, since it was this way since cmake 2.2
1678 this->ExtraGenerators[cmGlobalKdevelopGenerator::GetActualName()]
1679 = &cmGlobalKdevelopGenerator::New;
1680 #endif
1682 #endif
1686 //----------------------------------------------------------------------------
1687 void cmake::GetRegisteredGenerators(std::vector<std::string>& names)
1689 for(RegisteredGeneratorsMap::const_iterator i = this->Generators.begin();
1690 i != this->Generators.end(); ++i)
1692 names.push_back(i->first);
1694 for(RegisteredExtraGeneratorsMap::const_iterator
1695 i = this->ExtraGenerators.begin();
1696 i != this->ExtraGenerators.end(); ++i)
1698 names.push_back(i->first);
1702 cmGlobalGenerator* cmake::CreateGlobalGenerator(const char* name)
1704 cmGlobalGenerator* generator = 0;
1705 cmExternalMakefileProjectGenerator* extraGenerator = 0;
1706 RegisteredGeneratorsMap::const_iterator genIt = this->Generators.find(name);
1707 if(genIt == this->Generators.end())
1709 RegisteredExtraGeneratorsMap::const_iterator extraGenIt =
1710 this->ExtraGenerators.find(name);
1711 if (extraGenIt == this->ExtraGenerators.end())
1713 return 0;
1715 extraGenerator = (extraGenIt->second)();
1716 genIt=this->Generators.find(extraGenerator->GetGlobalGeneratorName(name));
1717 if(genIt == this->Generators.end())
1719 delete extraGenerator;
1720 return 0;
1724 generator = (genIt->second)();
1725 generator->SetCMakeInstance(this);
1726 generator->SetExternalMakefileProjectGenerator(extraGenerator);
1727 return generator;
1730 void cmake::SetHomeDirectory(const char* dir)
1732 this->cmHomeDirectory = dir;
1733 cmSystemTools::ConvertToUnixSlashes(this->cmHomeDirectory);
1736 void cmake::SetHomeOutputDirectory(const char* lib)
1738 this->HomeOutputDirectory = lib;
1739 cmSystemTools::ConvertToUnixSlashes(this->HomeOutputDirectory);
1742 void cmake::SetGlobalGenerator(cmGlobalGenerator *gg)
1744 if(!gg)
1746 cmSystemTools::Error("Error SetGlobalGenerator called with null");
1747 return;
1749 // delete the old generator
1750 if (this->GlobalGenerator)
1752 delete this->GlobalGenerator;
1753 // restore the original environment variables CXX and CC
1754 // Restor CC
1755 std::string env = "CC=";
1756 if(this->CCEnvironment.size())
1758 env += this->CCEnvironment;
1760 cmSystemTools::PutEnv(env.c_str());
1761 env = "CXX=";
1762 if(this->CXXEnvironment.size())
1764 env += this->CXXEnvironment;
1766 cmSystemTools::PutEnv(env.c_str());
1769 // set the new
1770 this->GlobalGenerator = gg;
1772 // set the global flag for unix style paths on cmSystemTools as soon as
1773 // the generator is set. This allows gmake to be used on windows.
1774 cmSystemTools::SetForceUnixPaths
1775 (this->GlobalGenerator->GetForceUnixPaths());
1777 // Save the environment variables CXX and CC
1778 const char* cxx = getenv("CXX");
1779 const char* cc = getenv("CC");
1780 if(cxx)
1782 this->CXXEnvironment = cxx;
1784 else
1786 this->CXXEnvironment = "";
1788 if(cc)
1790 this->CCEnvironment = cc;
1792 else
1794 this->CCEnvironment = "";
1796 // set the cmake instance just to be sure
1797 gg->SetCMakeInstance(this);
1800 int cmake::DoPreConfigureChecks()
1802 // Make sure the Start directory contains a CMakeLists.txt file.
1803 std::string srcList = this->GetHomeDirectory();
1804 srcList += "/CMakeLists.txt";
1805 if(!cmSystemTools::FileExists(srcList.c_str()))
1807 cmOStringStream err;
1808 if(cmSystemTools::FileIsDirectory(this->GetHomeDirectory()))
1810 err << "The source directory \"" << this->GetHomeDirectory()
1811 << "\" does not appear to contain CMakeLists.txt.\n";
1813 else if(cmSystemTools::FileExists(this->GetHomeDirectory()))
1815 err << "The source directory \"" << this->GetHomeDirectory()
1816 << "\" is a file, not a directory.\n";
1818 else
1820 err << "The source directory \"" << this->GetHomeDirectory()
1821 << "\" does not exist.\n";
1823 err << "Specify --help for usage, or press the help button on the CMake "
1824 "GUI.";
1825 cmSystemTools::Error(err.str().c_str());
1826 return -2;
1829 // do a sanity check on some values
1830 if(this->CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY"))
1832 std::string cacheStart =
1833 this->CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY");
1834 cacheStart += "/CMakeLists.txt";
1835 std::string currentStart = this->GetHomeDirectory();
1836 currentStart += "/CMakeLists.txt";
1837 if(!cmSystemTools::SameFile(cacheStart.c_str(), currentStart.c_str()))
1839 std::string message = "The source \"";
1840 message += currentStart;
1841 message += "\" does not match the source \"";
1842 message += cacheStart;
1843 message += "\" used to generate cache. ";
1844 message += "Re-run cmake with a different source directory.";
1845 cmSystemTools::Error(message.c_str());
1846 return -2;
1849 else
1851 return 0;
1853 return 1;
1855 struct SaveCacheEntry
1857 std::string key;
1858 std::string value;
1859 std::string help;
1860 cmCacheManager::CacheEntryType type;
1863 int cmake::HandleDeleteCacheVariables(const char* var)
1865 std::vector<std::string> argsSplit;
1866 cmSystemTools::ExpandListArgument(std::string(var), argsSplit);
1867 // erase the property to avoid infinite recursion
1868 this->SetProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", "");
1870 cmCacheManager::CacheIterator ci = this->CacheManager->NewIterator();
1871 std::vector<SaveCacheEntry> saved;
1872 cmOStringStream warning;
1873 warning
1874 << "You have changed variables that require your cache to be deleted.\n"
1875 << "Configure will be re-run and you may have to reset some variables.\n"
1876 << "The following variables have changed:\n";
1877 for(std::vector<std::string>::iterator i = argsSplit.begin();
1878 i != argsSplit.end(); ++i)
1880 SaveCacheEntry save;
1881 save.key = *i;
1882 warning << *i << "= ";
1883 i++;
1884 save.value = *i;
1885 warning << *i << "\n";
1886 if(ci.Find(save.key.c_str()))
1888 save.type = ci.GetType();
1889 save.help = ci.GetProperty("HELPSTRING");
1891 saved.push_back(save);
1894 // remove the cache
1895 this->CacheManager->DeleteCache(this->GetStartOutputDirectory());
1896 // load the empty cache
1897 this->LoadCache();
1898 // restore the changed compilers
1899 for(std::vector<SaveCacheEntry>::iterator i = saved.begin();
1900 i != saved.end(); ++i)
1902 this->AddCacheEntry(i->key.c_str(), i->value.c_str(),
1903 i->help.c_str(), i->type);
1905 cmSystemTools::Message(warning.str().c_str());
1906 // avoid reconfigure if there were errors
1907 if(!cmSystemTools::GetErrorOccuredFlag())
1909 // re-run configure
1910 return this->Configure();
1912 return 0;
1915 int cmake::Configure()
1917 if(this->DoSuppressDevWarnings)
1919 if(this->SuppressDevWarnings)
1921 this->CacheManager->
1922 AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE",
1923 "Suppress Warnings that are meant for"
1924 " the author of the CMakeLists.txt files.",
1925 cmCacheManager::INTERNAL);
1927 else
1929 this->CacheManager->
1930 AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "FALSE",
1931 "Suppress Warnings that are meant for"
1932 " the author of the CMakeLists.txt files.",
1933 cmCacheManager::INTERNAL);
1936 int ret = this->ActualConfigure();
1937 const char* delCacheVars =
1938 this->GetProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_");
1939 if(delCacheVars && delCacheVars[0] != 0)
1941 return this->HandleDeleteCacheVariables(delCacheVars);
1943 return ret;
1947 int cmake::ActualConfigure()
1949 // Construct right now our path conversion table before it's too late:
1950 this->UpdateConversionPathTable();
1951 this->CleanupCommandsAndMacros();
1953 int res = 0;
1954 if ( !this->ScriptMode )
1956 res = this->DoPreConfigureChecks();
1958 if ( res < 0 )
1960 return -2;
1962 if ( !res )
1964 this->CacheManager->AddCacheEntry
1965 ("CMAKE_HOME_DIRECTORY",
1966 this->GetHomeDirectory(),
1967 "Start directory with the top level CMakeLists.txt file for this "
1968 "project",
1969 cmCacheManager::INTERNAL);
1972 // no generator specified on the command line
1973 if(!this->GlobalGenerator)
1975 const char* genName =
1976 this->CacheManager->GetCacheValue("CMAKE_GENERATOR");
1977 const char* extraGenName =
1978 this->CacheManager->GetCacheValue("CMAKE_EXTRA_GENERATOR");
1979 if(genName)
1981 std::string fullName = cmExternalMakefileProjectGenerator::
1982 CreateFullGeneratorName(genName, extraGenName);
1983 this->GlobalGenerator = this->CreateGlobalGenerator(fullName.c_str());
1985 if(this->GlobalGenerator)
1987 // set the global flag for unix style paths on cmSystemTools as
1988 // soon as the generator is set. This allows gmake to be used
1989 // on windows.
1990 cmSystemTools::SetForceUnixPaths
1991 (this->GlobalGenerator->GetForceUnixPaths());
1993 else
1995 #if defined(__BORLANDC__) && defined(_WIN32)
1996 this->SetGlobalGenerator(new cmGlobalBorlandMakefileGenerator);
1997 #elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
1998 std::string installedCompiler;
1999 std::string mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
2000 "\\VisualStudio\\8.0\\Setup;Dbghelp_path]";
2001 cmSystemTools::ExpandRegistryValues(mp);
2002 if (!(mp == "/registry"))
2004 installedCompiler = "Visual Studio 8 2005";
2006 else
2008 mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
2009 "\\VisualStudio\\7.1;InstallDir]";
2010 cmSystemTools::ExpandRegistryValues(mp);
2011 if (!(mp == "/registry"))
2013 installedCompiler = "Visual Studio 7 .NET 2003";
2015 else
2017 mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
2018 "\\VisualStudio\\7.0;InstallDir]";
2019 cmSystemTools::ExpandRegistryValues(mp);
2020 if (!(mp == "/registry"))
2022 installedCompiler = "Visual Studio 7";
2024 else
2026 installedCompiler = "Visual Studio 6";
2030 cmGlobalGenerator* gen
2031 = this->CreateGlobalGenerator(installedCompiler.c_str());
2032 if(!gen)
2034 gen = new cmGlobalNMakeMakefileGenerator;
2036 this->SetGlobalGenerator(gen);
2037 #else
2038 this->SetGlobalGenerator(new cmGlobalUnixMakefileGenerator3);
2039 #endif
2041 if(!this->GlobalGenerator)
2043 cmSystemTools::Error("Could not create generator");
2044 return -1;
2048 const char* genName = this->CacheManager->GetCacheValue("CMAKE_GENERATOR");
2049 if(genName)
2051 if(strcmp(this->GlobalGenerator->GetName(), genName) != 0)
2053 std::string message = "Error: generator : ";
2054 message += this->GlobalGenerator->GetName();
2055 message += "\nDoes not match the generator used previously: ";
2056 message += genName;
2057 message +=
2058 "\nEither remove the CMakeCache.txt file or choose a different"
2059 " binary directory.";
2060 cmSystemTools::Error(message.c_str());
2061 return -2;
2064 if(!this->CacheManager->GetCacheValue("CMAKE_GENERATOR"))
2066 this->CacheManager->AddCacheEntry("CMAKE_GENERATOR",
2067 this->GlobalGenerator->GetName(),
2068 "Name of generator.",
2069 cmCacheManager::INTERNAL);
2070 this->CacheManager->AddCacheEntry("CMAKE_EXTRA_GENERATOR",
2071 this->GlobalGenerator->GetExtraGeneratorName(),
2072 "Name of external makefile project generator.",
2073 cmCacheManager::INTERNAL);
2076 // reset any system configuration information, except for when we are
2077 // InTryCompile. With TryCompile the system info is taken from the parent's
2078 // info to save time
2079 if (!this->InTryCompile)
2081 this->GlobalGenerator->ClearEnabledLanguages();
2084 this->CleanupWrittenFiles();
2086 // Truncate log files
2087 if (!this->InTryCompile)
2089 this->TruncateOutputLog("CMakeOutput.log");
2090 this->TruncateOutputLog("CMakeError.log");
2093 // actually do the configure
2094 this->GlobalGenerator->Configure();
2095 // Before saving the cache
2096 // if the project did not define one of the entries below, add them now
2097 // so users can edit the values in the cache:
2098 // LIBRARY_OUTPUT_PATH
2099 // EXECUTABLE_OUTPUT_PATH
2100 if(!this->CacheManager->GetCacheValue("LIBRARY_OUTPUT_PATH"))
2102 this->CacheManager->AddCacheEntry
2103 ("LIBRARY_OUTPUT_PATH", "",
2104 "Single output directory for building all libraries.",
2105 cmCacheManager::PATH);
2107 if(!this->CacheManager->GetCacheValue("EXECUTABLE_OUTPUT_PATH"))
2109 this->CacheManager->AddCacheEntry
2110 ("EXECUTABLE_OUTPUT_PATH", "",
2111 "Single output directory for building all executables.",
2112 cmCacheManager::PATH);
2114 if(!this->CacheManager->GetCacheValue("CMAKE_USE_RELATIVE_PATHS"))
2116 this->CacheManager->AddCacheEntry
2117 ("CMAKE_USE_RELATIVE_PATHS", false,
2118 "If true, cmake will use relative paths in makefiles and projects.");
2119 cmCacheManager::CacheIterator it =
2120 this->CacheManager->GetCacheIterator("CMAKE_USE_RELATIVE_PATHS");
2121 if ( !it.PropertyExists("ADVANCED") )
2123 it.SetProperty("ADVANCED", "1");
2127 if(cmSystemTools::GetFatalErrorOccured() &&
2128 (!this->CacheManager->GetCacheValue("CMAKE_MAKE_PROGRAM") ||
2129 cmSystemTools::IsOff(this->CacheManager->
2130 GetCacheValue("CMAKE_MAKE_PROGRAM"))))
2132 // We must have a bad generator selection. Wipe the cache entry so the
2133 // user can select another.
2134 this->CacheManager->RemoveCacheEntry("CMAKE_GENERATOR");
2135 this->CacheManager->RemoveCacheEntry("CMAKE_EXTRA_GENERATOR");
2137 // only save the cache if there were no fatal errors
2138 if ( !this->ScriptMode )
2140 this->CacheManager->SaveCache(this->GetHomeOutputDirectory());
2142 if ( !this->GraphVizFile.empty() )
2144 std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
2145 this->GenerateGraphViz(this->GraphVizFile.c_str());
2147 if(cmSystemTools::GetErrorOccuredFlag())
2149 return -1;
2151 return 0;
2154 bool cmake::CacheVersionMatches()
2156 const char* majv =
2157 this->CacheManager->GetCacheValue("CMAKE_CACHE_MAJOR_VERSION");
2158 const char* minv =
2159 this->CacheManager->GetCacheValue("CMAKE_CACHE_MINOR_VERSION");
2160 const char* relv =
2161 this->CacheManager->GetCacheValue("CMAKE_CACHE_RELEASE_VERSION");
2162 bool cacheSameCMake = false;
2163 if(majv &&
2164 atoi(majv) == static_cast<int>(cmVersion::GetMajorVersion())
2165 && minv &&
2166 atoi(minv) == static_cast<int>(cmVersion::GetMinorVersion())
2167 && relv && (strcmp(relv, cmVersion::GetReleaseVersion().c_str()) == 0))
2169 cacheSameCMake = true;
2171 return cacheSameCMake;
2174 void cmake::PreLoadCMakeFiles()
2176 std::string pre_load = this->GetHomeDirectory();
2177 if ( pre_load.size() > 0 )
2179 pre_load += "/PreLoad.cmake";
2180 if ( cmSystemTools::FileExists(pre_load.c_str()) )
2182 this->ReadListFile(pre_load.c_str());
2185 pre_load = this->GetHomeOutputDirectory();
2186 if ( pre_load.size() > 0 )
2188 pre_load += "/PreLoad.cmake";
2189 if ( cmSystemTools::FileExists(pre_load.c_str()) )
2191 this->ReadListFile(pre_load.c_str());
2196 // handle a command line invocation
2197 int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
2199 // Process the arguments
2200 this->SetArgs(args);
2201 if(cmSystemTools::GetErrorOccuredFlag())
2203 return -1;
2206 // If we are given a stamp list file check if it is really out of date.
2207 if(!this->CheckStampList.empty() &&
2208 cmakeCheckStampList(this->CheckStampList.c_str()))
2210 return 0;
2213 // If we are given a stamp file check if it is really out of date.
2214 if(!this->CheckStampFile.empty() &&
2215 cmakeCheckStampFile(this->CheckStampFile.c_str()))
2217 return 0;
2220 // set the cmake command
2221 this->CMakeCommand = args[0];
2223 if ( !this->ScriptMode )
2225 // load the cache
2226 if(this->LoadCache() < 0)
2228 cmSystemTools::Error("Error executing cmake::LoadCache(). Aborting.\n");
2229 return -1;
2232 else
2234 this->AddCMakePaths();
2236 // Add any cache args
2237 if ( !this->SetCacheArgs(args) )
2239 cmSystemTools::Error("Problem processing arguments. Aborting.\n");
2240 return -1;
2243 // In script mode we terminate after running the script.
2244 if(this->ScriptMode)
2246 if(cmSystemTools::GetErrorOccuredFlag())
2248 return -1;
2250 else
2252 return 0;
2256 this->PreLoadCMakeFiles();
2258 std::string systemFile = this->GetHomeOutputDirectory();
2259 systemFile += "/CMakeSystem.cmake";
2261 if ( noconfigure )
2263 return 0;
2266 // now run the global generate
2267 // Check the state of the build system to see if we need to regenerate.
2268 if(!this->CheckBuildSystem())
2270 return 0;
2273 // If we are doing global generate, we better set start and start
2274 // output directory to the root of the project.
2275 std::string oldstartdir = this->GetStartDirectory();
2276 std::string oldstartoutputdir = this->GetStartOutputDirectory();
2277 this->SetStartDirectory(this->GetHomeDirectory());
2278 this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
2279 int ret = this->Configure();
2280 if (ret || this->ScriptMode)
2282 #if defined(CMAKE_HAVE_VS_GENERATORS)
2283 if(!this->VSSolutionFile.empty() && this->GlobalGenerator)
2285 // CMake is running to regenerate a Visual Studio build tree
2286 // during a build from the VS IDE. The build files cannot be
2287 // regenerated, so we should stop the build.
2288 cmSystemTools::Message(
2289 "CMake Configure step failed. "
2290 "Build files cannot be regenerated correctly. "
2291 "Attempting to stop IDE build.");
2292 cmGlobalVisualStudioGenerator* gg =
2293 static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
2294 gg->CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
2295 this->VSSolutionFile.c_str());
2297 #endif
2298 return ret;
2300 ret = this->Generate();
2301 std::string message = "Build files have been written to: ";
2302 message += this->GetHomeOutputDirectory();
2303 this->UpdateProgress(message.c_str(), -1);
2304 if(ret)
2306 return ret;
2308 this->SetStartDirectory(oldstartdir.c_str());
2309 this->SetStartOutputDirectory(oldstartoutputdir.c_str());
2311 return ret;
2314 int cmake::Generate()
2316 if(!this->GlobalGenerator)
2318 return -1;
2320 this->GlobalGenerator->Generate();
2321 if(cmSystemTools::GetErrorOccuredFlag())
2323 return -1;
2325 if (this->GetProperty("REPORT_UNDEFINED_PROPERTIES"))
2327 this->ReportUndefinedPropertyAccesses
2328 (this->GetProperty("REPORT_UNDEFINED_PROPERTIES"));
2330 return 0;
2333 void cmake::AddCacheEntry(const char* key, const char* value,
2334 const char* helpString,
2335 int type)
2337 this->CacheManager->AddCacheEntry(key, value,
2338 helpString,
2339 cmCacheManager::CacheEntryType(type));
2342 const char* cmake::GetCacheDefinition(const char* name) const
2344 return this->CacheManager->GetCacheValue(name);
2347 int cmake::DumpDocumentationToFile(std::ostream& f)
2349 #ifdef CMAKE_BUILD_WITH_CMAKE
2350 // Loop over all registered commands and print out documentation
2351 const char *name;
2352 const char *terse;
2353 const char *full;
2354 char tmp[1024];
2355 sprintf(tmp,"Version %d.%d (%s)", cmVersion::GetMajorVersion(),
2356 cmVersion::GetMinorVersion(),
2357 cmVersion::GetReleaseVersion().c_str());
2358 f << "<html>\n";
2359 f << "<h1>Documentation for commands of CMake " << tmp << "</h1>\n";
2360 f << "<ul>\n";
2361 for(RegisteredCommandsMap::iterator j = this->Commands.begin();
2362 j != this->Commands.end(); ++j)
2364 name = (*j).second->GetName();
2365 terse = (*j).second->GetTerseDocumentation();
2366 full = (*j).second->GetFullDocumentation();
2367 f << "<li><b>" << name << "</b> - " << terse << std::endl
2368 << "<br><i>Usage:</i> " << full << "</li>" << std::endl << std::endl;
2370 f << "</ul></html>\n";
2371 #else
2372 (void)f;
2373 #endif
2374 return 1;
2377 void cmake::AddDefaultCommands()
2379 std::list<cmCommand*> commands;
2380 GetBootstrapCommands(commands);
2381 GetPredefinedCommands(commands);
2382 for(std::list<cmCommand*>::iterator i = commands.begin();
2383 i != commands.end(); ++i)
2385 this->AddCommand(*i);
2389 void cmake::AddDefaultGenerators()
2391 #if defined(_WIN32) && !defined(__CYGWIN__)
2392 # if !defined(CMAKE_BOOT_MINGW)
2393 this->Generators[cmGlobalVisualStudio6Generator::GetActualName()] =
2394 &cmGlobalVisualStudio6Generator::New;
2395 this->Generators[cmGlobalVisualStudio7Generator::GetActualName()] =
2396 &cmGlobalVisualStudio7Generator::New;
2397 this->Generators[cmGlobalVisualStudio71Generator::GetActualName()] =
2398 &cmGlobalVisualStudio71Generator::New;
2399 this->Generators[cmGlobalVisualStudio8Generator::GetActualName()] =
2400 &cmGlobalVisualStudio8Generator::New;
2401 this->Generators[cmGlobalVisualStudio9Generator::GetActualName()] =
2402 &cmGlobalVisualStudio9Generator::New;
2403 this->Generators[cmGlobalVisualStudio9Win64Generator::GetActualName()] =
2404 &cmGlobalVisualStudio9Win64Generator::New;
2405 this->Generators[cmGlobalVisualStudio8Win64Generator::GetActualName()] =
2406 &cmGlobalVisualStudio8Win64Generator::New;
2407 this->Generators[cmGlobalBorlandMakefileGenerator::GetActualName()] =
2408 &cmGlobalBorlandMakefileGenerator::New;
2409 this->Generators[cmGlobalNMakeMakefileGenerator::GetActualName()] =
2410 &cmGlobalNMakeMakefileGenerator::New;
2411 this->Generators[cmGlobalWatcomWMakeGenerator::GetActualName()] =
2412 &cmGlobalWatcomWMakeGenerator::New;
2413 # endif
2414 this->Generators[cmGlobalMSYSMakefileGenerator::GetActualName()] =
2415 &cmGlobalMSYSMakefileGenerator::New;
2416 this->Generators[cmGlobalMinGWMakefileGenerator::GetActualName()] =
2417 &cmGlobalMinGWMakefileGenerator::New;
2418 #endif
2419 this->Generators[cmGlobalUnixMakefileGenerator3::GetActualName()] =
2420 &cmGlobalUnixMakefileGenerator3::New;
2421 #ifdef CMAKE_USE_XCODE
2422 this->Generators[cmGlobalXCodeGenerator::GetActualName()] =
2423 &cmGlobalXCodeGenerator::New;
2424 #endif
2427 int cmake::LoadCache()
2429 // could we not read the cache
2430 if (!this->CacheManager->LoadCache(this->GetHomeOutputDirectory()))
2432 // if it does exist, but isn;t readable then warn the user
2433 std::string cacheFile = this->GetHomeOutputDirectory();
2434 cacheFile += "/CMakeCache.txt";
2435 if(cmSystemTools::FileExists(cacheFile.c_str()))
2437 cmSystemTools::Error(
2438 "There is a CMakeCache.txt file for the current binary tree but "
2439 "cmake does not have permission to read it. Please check the "
2440 "permissions of the directory you are trying to run CMake on.");
2441 return -1;
2445 if (this->CMakeCommand.size() < 2)
2447 cmSystemTools::Error(
2448 "cmake command was not specified prior to loading the cache in "
2449 "cmake.cxx");
2450 return -1;
2453 // setup CMAKE_ROOT and CMAKE_COMMAND
2454 if(!this->AddCMakePaths())
2456 return -3;
2458 return 0;
2461 void cmake::SetProgressCallback(ProgressCallbackType f, void *cd)
2463 this->ProgressCallback = f;
2464 this->ProgressCallbackClientData = cd;
2467 void cmake::UpdateProgress(const char *msg, float prog)
2469 if(this->ProgressCallback && !this->InTryCompile)
2471 (*this->ProgressCallback)(msg, prog, this->ProgressCallbackClientData);
2472 return;
2476 void cmake::GetCommandDocumentation(std::vector<cmDocumentationEntry>& v,
2477 bool withCurrentCommands,
2478 bool withCompatCommands) const
2480 for(RegisteredCommandsMap::const_iterator j = this->Commands.begin();
2481 j != this->Commands.end(); ++j)
2483 if ((( withCompatCommands == false) && ( (*j).second->IsDiscouraged()))
2484 || ((withCurrentCommands == false) && (!(*j).second->IsDiscouraged())))
2486 continue;
2489 cmDocumentationEntry e((*j).second->GetName(),
2490 (*j).second->GetTerseDocumentation(),
2491 (*j).second->GetFullDocumentation());
2492 v.push_back(e);
2496 void cmake::GetPolicyDocumentation(std::vector<cmDocumentationEntry>& v)
2498 this->Policies->GetDocumentation(v);
2501 void cmake::GetPropertiesDocumentation(std::map<std::string,
2502 cmDocumentationSection *>& v)
2504 // loop over the properties and put them into the doc structure
2505 std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::iterator i;
2506 i = this->PropertyDefinitions.begin();
2507 for (;i != this->PropertyDefinitions.end(); ++i)
2509 i->second.GetPropertiesDocumentation(v);
2513 void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v)
2515 for(RegisteredGeneratorsMap::const_iterator i = this->Generators.begin();
2516 i != this->Generators.end(); ++i)
2518 cmDocumentationEntry e;
2519 cmGlobalGenerator* generator = (i->second)();
2520 generator->GetDocumentation(e);
2521 delete generator;
2522 v.push_back(e);
2524 for(RegisteredExtraGeneratorsMap::const_iterator
2525 i = this->ExtraGenerators.begin(); i != this->ExtraGenerators.end(); ++i)
2527 cmDocumentationEntry e;
2528 cmExternalMakefileProjectGenerator* generator = (i->second)();
2529 generator->GetDocumentation(e, i->first.c_str());
2530 e.Name = i->first;
2531 delete generator;
2532 v.push_back(e);
2536 void cmake::AddWrittenFile(const char* file)
2538 this->WrittenFiles.insert(file);
2541 bool cmake::HasWrittenFile(const char* file)
2543 return this->WrittenFiles.find(file) != this->WrittenFiles.end();
2546 void cmake::CleanupWrittenFiles()
2548 this->WrittenFiles.clear();
2551 void cmake::UpdateConversionPathTable()
2553 // Update the path conversion table with any specified file:
2554 const char* tablepath =
2555 this->CacheManager->GetCacheValue("CMAKE_PATH_TRANSLATION_FILE");
2557 if(tablepath)
2559 std::ifstream table( tablepath );
2560 if(!table)
2562 cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to ", tablepath,
2563 ". CMake can not open file.");
2564 cmSystemTools::ReportLastSystemError("CMake can not open file.");
2566 else
2568 std::string a, b;
2569 while(!table.eof())
2571 // two entries per line
2572 table >> a; table >> b;
2573 cmSystemTools::AddTranslationPath( a.c_str(), b.c_str());
2579 //----------------------------------------------------------------------------
2580 int cmake::CheckBuildSystem()
2582 // We do not need to rerun CMake. Check dependency integrity. Use
2583 // the make system's VERBOSE environment variable to enable verbose
2584 // output.
2585 bool verbose = cmSystemTools::GetEnv("VERBOSE") != 0;
2587 // This method will check the integrity of the build system if the
2588 // option was given on the command line. It reads the given file to
2589 // determine whether CMake should rerun.
2591 // If no file is provided for the check, we have to rerun.
2592 if(this->CheckBuildSystemArgument.size() == 0)
2594 if(verbose)
2596 cmOStringStream msg;
2597 msg << "Re-run cmake no build system arguments\n";
2598 cmSystemTools::Stdout(msg.str().c_str());
2600 return 1;
2603 // If the file provided does not exist, we have to rerun.
2604 if(!cmSystemTools::FileExists(this->CheckBuildSystemArgument.c_str()))
2606 if(verbose)
2608 cmOStringStream msg;
2609 msg << "Re-run cmake missing file: "
2610 << this->CheckBuildSystemArgument.c_str() << "\n";
2611 cmSystemTools::Stdout(msg.str().c_str());
2613 return 1;
2616 // Read the rerun check file and use it to decide whether to do the
2617 // global generate.
2618 cmake cm;
2619 cmGlobalGenerator gg;
2620 gg.SetCMakeInstance(&cm);
2621 std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
2622 lg->SetGlobalGenerator(&gg);
2623 cmMakefile* mf = lg->GetMakefile();
2624 if(!mf->ReadListFile(0, this->CheckBuildSystemArgument.c_str()) ||
2625 cmSystemTools::GetErrorOccuredFlag())
2627 if(verbose)
2629 cmOStringStream msg;
2630 msg << "Re-run cmake error reading : "
2631 << this->CheckBuildSystemArgument.c_str() << "\n";
2632 cmSystemTools::Stdout(msg.str().c_str());
2634 // There was an error reading the file. Just rerun.
2635 return 1;
2638 if(this->ClearBuildSystem)
2640 // Get the generator used for this build system.
2641 const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
2642 if(!genName || genName[0] == '\0')
2644 genName = "Unix Makefiles";
2647 // Create the generator and use it to clear the dependencies.
2648 std::auto_ptr<cmGlobalGenerator>
2649 ggd(this->CreateGlobalGenerator(genName));
2650 if(ggd.get())
2652 std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
2653 lgd->SetGlobalGenerator(ggd.get());
2654 lgd->ClearDependencies(mf, verbose);
2658 // Get the set of dependencies and outputs.
2659 std::vector<std::string> depends;
2660 std::vector<std::string> outputs;
2661 const char* dependsStr = mf->GetDefinition("CMAKE_MAKEFILE_DEPENDS");
2662 const char* outputsStr = mf->GetDefinition("CMAKE_MAKEFILE_OUTPUTS");
2663 if(dependsStr && outputsStr)
2665 cmSystemTools::ExpandListArgument(dependsStr, depends);
2666 cmSystemTools::ExpandListArgument(outputsStr, outputs);
2668 if(depends.empty() || outputs.empty())
2670 // Not enough information was provided to do the test. Just rerun.
2671 if(verbose)
2673 cmOStringStream msg;
2674 msg << "Re-run cmake no CMAKE_MAKEFILE_DEPENDS "
2675 "or CMAKE_MAKEFILE_OUTPUTS :\n";
2676 cmSystemTools::Stdout(msg.str().c_str());
2678 return 1;
2681 // Find find the newest dependency.
2682 std::vector<std::string>::iterator dep = depends.begin();
2683 std::string dep_newest = *dep++;
2684 for(;dep != depends.end(); ++dep)
2686 int result = 0;
2687 if(this->FileComparison->FileTimeCompare(dep_newest.c_str(),
2688 dep->c_str(), &result))
2690 if(result < 0)
2692 dep_newest = *dep;
2695 else
2697 if(verbose)
2699 cmOStringStream msg;
2700 msg << "Re-run cmake: build system dependency is missing\n";
2701 cmSystemTools::Stdout(msg.str().c_str());
2703 return 1;
2707 // Find find the oldest output.
2708 std::vector<std::string>::iterator out = outputs.begin();
2709 std::string out_oldest = *out++;
2710 for(;out != outputs.end(); ++out)
2712 int result = 0;
2713 if(this->FileComparison->FileTimeCompare(out_oldest.c_str(),
2714 out->c_str(), &result))
2716 if(result > 0)
2718 out_oldest = *out;
2721 else
2723 if(verbose)
2725 cmOStringStream msg;
2726 msg << "Re-run cmake: build system output is missing\n";
2727 cmSystemTools::Stdout(msg.str().c_str());
2729 return 1;
2733 // If any output is older than any dependency then rerun.
2735 int result = 0;
2736 if(!this->FileComparison->FileTimeCompare(out_oldest.c_str(),
2737 dep_newest.c_str(),
2738 &result) ||
2739 result < 0)
2741 if(verbose)
2743 cmOStringStream msg;
2744 msg << "Re-run cmake file: " << out_oldest.c_str()
2745 << " older than: " << dep_newest.c_str() << "\n";
2746 cmSystemTools::Stdout(msg.str().c_str());
2748 return 1;
2752 // No need to rerun.
2753 return 0;
2756 //----------------------------------------------------------------------------
2757 void cmake::TruncateOutputLog(const char* fname)
2759 std::string fullPath = this->GetHomeOutputDirectory();
2760 fullPath += "/";
2761 fullPath += fname;
2762 struct stat st;
2763 if ( ::stat(fullPath.c_str(), &st) )
2765 return;
2767 if ( !this->CacheManager->GetCacheValue("CMAKE_CACHEFILE_DIR") )
2769 cmSystemTools::RemoveFile(fullPath.c_str());
2770 return;
2772 off_t fsize = st.st_size;
2773 const off_t maxFileSize = 50 * 1024;
2774 if ( fsize < maxFileSize )
2776 //TODO: truncate file
2777 return;
2781 inline std::string removeQuotes(const std::string& s)
2783 if(s[0] == '\"' && s[s.size()-1] == '\"')
2785 return s.substr(1, s.size()-2);
2787 return s;
2790 std::string cmake::FindCMakeProgram(const char* name) const
2792 std::string path;
2793 if ((name) && (*name))
2795 const cmMakefile* mf
2796 = this->GetGlobalGenerator()->GetLocalGenerators()[0]->GetMakefile();
2797 #ifdef CMAKE_BUILD_WITH_CMAKE
2798 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2799 path = removeQuotes(path);
2800 path = cmSystemTools::GetFilenamePath(path.c_str());
2801 path += "/";
2802 path += name;
2803 path += cmSystemTools::GetExecutableExtension();
2804 if(!cmSystemTools::FileExists(path.c_str()))
2806 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2807 path = cmSystemTools::GetFilenamePath(path.c_str());
2808 path += "/Debug/";
2809 path += name;
2810 path += cmSystemTools::GetExecutableExtension();
2812 if(!cmSystemTools::FileExists(path.c_str()))
2814 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2815 path = cmSystemTools::GetFilenamePath(path.c_str());
2816 path += "/Release/";
2817 path += name;
2818 path += cmSystemTools::GetExecutableExtension();
2820 #else
2821 // Only for bootstrap
2822 path += mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
2823 path += "/";
2824 path += name;
2825 path += cmSystemTools::GetExecutableExtension();
2826 #endif
2828 return path;
2831 const char* cmake::GetCTestCommand()
2833 if ( this->CTestCommand.empty() )
2835 this->CTestCommand = this->FindCMakeProgram("ctest");
2837 if ( this->CTestCommand.empty() )
2839 cmSystemTools::Error("Cannot find the CTest executable");
2840 this->CTestCommand = "CTEST-COMMAND-NOT-FOUND";
2842 return this->CTestCommand.c_str();
2845 const char* cmake::GetCPackCommand()
2847 if ( this->CPackCommand.empty() )
2849 this->CPackCommand = this->FindCMakeProgram("cpack");
2851 if ( this->CPackCommand.empty() )
2853 cmSystemTools::Error("Cannot find the CPack executable");
2854 this->CPackCommand = "CPACK-COMMAND-NOT-FOUND";
2856 return this->CPackCommand.c_str();
2859 void cmake::GenerateGraphViz(const char* fileName) const
2861 cmGeneratedFileStream str(fileName);
2862 if ( !str )
2864 return;
2866 cmake cm;
2867 cmGlobalGenerator ggi;
2868 ggi.SetCMakeInstance(&cm);
2869 std::auto_ptr<cmLocalGenerator> lg(ggi.CreateLocalGenerator());
2870 lg->SetGlobalGenerator(&ggi);
2871 cmMakefile *mf = lg->GetMakefile();
2873 std::string infile = this->GetHomeOutputDirectory();
2874 infile += "/CMakeGraphVizOptions.cmake";
2875 if ( !cmSystemTools::FileExists(infile.c_str()) )
2877 infile = this->GetHomeDirectory();
2878 infile += "/CMakeGraphVizOptions.cmake";
2879 if ( !cmSystemTools::FileExists(infile.c_str()) )
2881 infile = "";
2885 if ( !infile.empty() )
2887 if ( !mf->ReadListFile(0, infile.c_str()) )
2889 cmSystemTools::Error("Problem opening GraphViz options file: ",
2890 infile.c_str());
2891 return;
2893 std::cout << "Read GraphViz options file: " << infile.c_str()
2894 << std::endl;
2897 #define __set_if_not_set(var, value, cmakeDefinition) \
2898 const char* var = mf->GetDefinition(cmakeDefinition); \
2899 if ( !var ) \
2901 var = value; \
2903 __set_if_not_set(graphType, "digraph", "GRAPHVIZ_GRAPH_TYPE");
2904 __set_if_not_set(graphName, "GG", "GRAPHVIZ_GRAPH_NAME");
2905 __set_if_not_set(graphHeader, "node [\n fontsize = \"12\"\n];",
2906 "GRAPHVIZ_GRAPH_HEADER");
2907 __set_if_not_set(graphNodePrefix, "node", "GRAPHVIZ_NODE_PREFIX");
2908 const char* ignoreTargets = mf->GetDefinition("GRAPHVIZ_IGNORE_TARGETS");
2909 std::set<cmStdString> ignoreTargetsSet;
2910 if ( ignoreTargets )
2912 std::vector<std::string> ignoreTargetsVector;
2913 cmSystemTools::ExpandListArgument(ignoreTargets,ignoreTargetsVector);
2914 std::vector<std::string>::iterator itvIt;
2915 for ( itvIt = ignoreTargetsVector.begin();
2916 itvIt != ignoreTargetsVector.end();
2917 ++ itvIt )
2919 ignoreTargetsSet.insert(itvIt->c_str());
2923 str << graphType << " " << graphName << " {" << std::endl;
2924 str << graphHeader << std::endl;
2926 const cmGlobalGenerator* gg = this->GetGlobalGenerator();
2927 const std::vector<cmLocalGenerator*>& localGenerators =
2928 gg->GetLocalGenerators();
2929 std::vector<cmLocalGenerator*>::const_iterator lit;
2930 // for target deps
2931 // 1 - cmake target
2932 // 2 - external target
2933 // 0 - no deps
2934 std::map<cmStdString, int> targetDeps;
2935 std::map<cmStdString, const cmTarget*> targetPtrs;
2936 std::map<cmStdString, cmStdString> targetNamesNodes;
2937 int cnt = 0;
2938 // First pass get the list of all cmake targets
2939 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2941 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
2942 cmTargets::const_iterator tit;
2943 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
2945 const char* realTargetName = tit->first.c_str();
2946 if ( ignoreTargetsSet.find(realTargetName) != ignoreTargetsSet.end() )
2948 // Skip ignored targets
2949 continue;
2951 //std::cout << "Found target: " << tit->first.c_str() << std::endl;
2952 cmOStringStream ostr;
2953 ostr << graphNodePrefix << cnt++;
2954 targetNamesNodes[realTargetName] = ostr.str();
2955 targetPtrs[realTargetName] = &tit->second;
2958 // Ok, now find all the stuff we link to that is not in cmake
2959 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2961 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
2962 cmTargets::const_iterator tit;
2963 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
2965 const cmTarget::LinkLibraryVectorType* ll
2966 = &(tit->second.GetOriginalLinkLibraries());
2967 cmTarget::LinkLibraryVectorType::const_iterator llit;
2968 const char* realTargetName = tit->first.c_str();
2969 if ( ignoreTargetsSet.find(realTargetName) != ignoreTargetsSet.end() )
2971 // Skip ignored targets
2972 continue;
2974 if ( ll->size() > 0 )
2976 targetDeps[realTargetName] = 1;
2978 for ( llit = ll->begin(); llit != ll->end(); ++ llit )
2980 const char* libName = llit->first.c_str();
2981 std::map<cmStdString, cmStdString>::const_iterator tarIt
2982 = targetNamesNodes.find(libName);
2983 if ( ignoreTargetsSet.find(libName) != ignoreTargetsSet.end() )
2985 // Skip ignored targets
2986 continue;
2988 if ( tarIt == targetNamesNodes.end() )
2990 cmOStringStream ostr;
2991 ostr << graphNodePrefix << cnt++;
2992 targetDeps[libName] = 2;
2993 targetNamesNodes[libName] = ostr.str();
2994 //str << " \"" << ostr.c_str() << "\" [ label=\"" << libName
2995 //<< "\" shape=\"ellipse\"];" << std::endl;
2997 else
2999 std::map<cmStdString, int>::const_iterator depIt
3000 = targetDeps.find(libName);
3001 if ( depIt == targetDeps.end() )
3003 targetDeps[libName] = 1;
3010 // Write out nodes
3011 std::map<cmStdString, int>::const_iterator depIt;
3012 for ( depIt = targetDeps.begin(); depIt != targetDeps.end(); ++ depIt )
3014 const char* newTargetName = depIt->first.c_str();
3015 std::map<cmStdString, cmStdString>::const_iterator tarIt
3016 = targetNamesNodes.find(newTargetName);
3017 if ( tarIt == targetNamesNodes.end() )
3019 // We should not be here.
3020 std::cout << __LINE__ << " Cannot find library: " << newTargetName
3021 << " even though it was added in the previous pass" << std::endl;
3022 abort();
3025 str << " \"" << tarIt->second.c_str() << "\" [ label=\""
3026 << newTargetName << "\" shape=\"";
3027 if ( depIt->second == 1 )
3029 std::map<cmStdString, const cmTarget*>::const_iterator tarTypeIt =
3030 targetPtrs.find(newTargetName);
3031 if ( tarTypeIt == targetPtrs.end() )
3033 // We should not be here.
3034 std::cout << __LINE__ << " Cannot find library: " << newTargetName
3035 << " even though it was added in the previous pass" << std::endl;
3036 abort();
3038 const cmTarget* tg = tarTypeIt->second;
3039 switch ( tg->GetType() )
3041 case cmTarget::EXECUTABLE:
3042 str << "house";
3043 break;
3044 case cmTarget::STATIC_LIBRARY:
3045 str << "diamond";
3046 break;
3047 case cmTarget::SHARED_LIBRARY:
3048 str << "polygon";
3049 break;
3050 case cmTarget::MODULE_LIBRARY:
3051 str << "octagon";
3052 break;
3053 default:
3054 str << "box";
3057 else
3059 str << "ellipse";
3061 str << "\"];" << std::endl;
3064 // Now generate the connectivity
3065 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
3067 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
3068 cmTargets::const_iterator tit;
3069 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
3071 std::map<cmStdString, int>::iterator dependIt
3072 = targetDeps.find(tit->first.c_str());
3073 if ( dependIt == targetDeps.end() )
3075 continue;
3077 std::map<cmStdString, cmStdString>::iterator cmakeTarIt
3078 = targetNamesNodes.find(tit->first.c_str());
3079 const cmTarget::LinkLibraryVectorType* ll
3080 = &(tit->second.GetOriginalLinkLibraries());
3081 cmTarget::LinkLibraryVectorType::const_iterator llit;
3082 for ( llit = ll->begin(); llit != ll->end(); ++ llit )
3084 const char* libName = llit->first.c_str();
3085 std::map<cmStdString, cmStdString>::const_iterator tarIt
3086 = targetNamesNodes.find(libName);
3087 if ( tarIt == targetNamesNodes.end() )
3089 // We should not be here.
3090 std::cout << __LINE__ << " Cannot find library: " << libName
3091 << " even though it was added in the previous pass" << std::endl;
3092 abort();
3094 str << " \"" << cmakeTarIt->second.c_str() << "\" -> \""
3095 << tarIt->second.c_str() << "\"" << std::endl;
3100 // TODO: Use dotted or something for external libraries
3101 //str << " \"node0\":f4 -> \"node12\"[color=\"#0000ff\" style=dotted]"
3102 //<< std::endl;
3104 str << "}" << std::endl;
3107 //----------------------------------------------------------------------------
3108 #ifdef CMAKE_BUILD_WITH_CMAKE
3109 int cmake::ExecuteEchoColor(std::vector<std::string>& args)
3111 // The arguments are
3112 // argv[0] == <cmake-executable>
3113 // argv[1] == cmake_echo_color
3115 bool enabled = true;
3116 int color = cmsysTerminal_Color_Normal;
3117 bool newline = true;
3118 for(unsigned int i=2; i < args.size(); ++i)
3120 if(args[i].find("--switch=") == 0)
3122 // Enable or disable color based on the switch value.
3123 std::string value = args[i].substr(9);
3124 if(!value.empty())
3126 if(cmSystemTools::IsOn(value.c_str()))
3128 enabled = true;
3130 else
3132 enabled = false;
3136 else if(args[i] == "--normal")
3138 color = cmsysTerminal_Color_Normal;
3140 else if(args[i] == "--black")
3142 color = cmsysTerminal_Color_ForegroundBlack;
3144 else if(args[i] == "--red")
3146 color = cmsysTerminal_Color_ForegroundRed;
3148 else if(args[i] == "--green")
3150 color = cmsysTerminal_Color_ForegroundGreen;
3152 else if(args[i] == "--yellow")
3154 color = cmsysTerminal_Color_ForegroundYellow;
3156 else if(args[i] == "--blue")
3158 color = cmsysTerminal_Color_ForegroundBlue;
3160 else if(args[i] == "--magenta")
3162 color = cmsysTerminal_Color_ForegroundMagenta;
3164 else if(args[i] == "--cyan")
3166 color = cmsysTerminal_Color_ForegroundCyan;
3168 else if(args[i] == "--white")
3170 color = cmsysTerminal_Color_ForegroundWhite;
3172 else if(args[i] == "--bold")
3174 color |= cmsysTerminal_Color_ForegroundBold;
3176 else if(args[i] == "--no-newline")
3178 newline = false;
3180 else if(args[i] == "--newline")
3182 newline = true;
3184 else
3186 // Color is enabled. Print with the current color.
3187 cmSystemTools::MakefileColorEcho(color, args[i].c_str(),
3188 newline, enabled);
3192 return 0;
3194 #else
3195 int cmake::ExecuteEchoColor(std::vector<std::string>&)
3197 return 1;
3199 #endif
3201 //----------------------------------------------------------------------------
3202 int cmake::ExecuteLinkScript(std::vector<std::string>& args)
3204 // The arguments are
3205 // argv[0] == <cmake-executable>
3206 // argv[1] == cmake_link_script
3207 // argv[2] == <link-script-name>
3208 // argv[3] == --verbose=?
3209 bool verbose = false;
3210 if(args.size() >= 4)
3212 if(args[3].find("--verbose=") == 0)
3214 if(!cmSystemTools::IsOff(args[3].substr(10).c_str()))
3216 verbose = true;
3221 // Allocate a process instance.
3222 cmsysProcess* cp = cmsysProcess_New();
3223 if(!cp)
3225 std::cerr << "Error allocating process instance in link script."
3226 << std::endl;
3227 return 1;
3230 // Children should share stdout and stderr with this process.
3231 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
3232 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
3234 // Run the command lines verbatim.
3235 cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
3237 // Read command lines from the script.
3238 std::ifstream fin(args[2].c_str());
3239 if(!fin)
3241 std::cerr << "Error opening link script \""
3242 << args[2] << "\"" << std::endl;
3243 return 1;
3246 // Run one command at a time.
3247 std::string command;
3248 int result = 0;
3249 while(result == 0 && cmSystemTools::GetLineFromStream(fin, command))
3251 // Setup this command line.
3252 const char* cmd[2] = {command.c_str(), 0};
3253 cmsysProcess_SetCommand(cp, cmd);
3255 // Report the command if verbose output is enabled.
3256 if(verbose)
3258 std::cout << command << std::endl;
3261 // Run the command and wait for it to exit.
3262 cmsysProcess_Execute(cp);
3263 cmsysProcess_WaitForExit(cp, 0);
3265 // Report failure if any.
3266 switch(cmsysProcess_GetState(cp))
3268 case cmsysProcess_State_Exited:
3270 int value = cmsysProcess_GetExitValue(cp);
3271 if(value != 0)
3273 result = value;
3276 break;
3277 case cmsysProcess_State_Exception:
3278 std::cerr << "Error running link command: "
3279 << cmsysProcess_GetExceptionString(cp) << std::endl;
3280 result = 1;
3281 break;
3282 case cmsysProcess_State_Error:
3283 std::cerr << "Error running link command: "
3284 << cmsysProcess_GetErrorString(cp) << std::endl;
3285 result = 2;
3286 break;
3287 default:
3288 break;
3292 // Free the process instance.
3293 cmsysProcess_Delete(cp);
3295 // Return the final resulting return value.
3296 return result;
3299 void cmake::DefineProperties(cmake *cm)
3301 cm->DefineProperty
3302 ("REPORT_UNDEFINED_PROPERTIES", cmProperty::GLOBAL,
3303 "If set, report any undefined properties to this file.",
3304 "If this property is set to a filename then when CMake runs "
3305 "it will report any properties or variables that were accessed "
3306 "but not defined into the filename specified in this property."
3309 cm->DefineProperty
3310 ("TARGET_SUPPORTS_SHARED_LIBS", cmProperty::GLOBAL,
3311 "Does the target platform support shared libraries.",
3312 "TARGET_SUPPORTS_SHARED_LIBS is a boolean specifying whether the target "
3313 "platform supports shared libraries. Basically all current general "
3314 "general purpose OS do so, the exception are usually embedded systems "
3315 "with no or special OSs.");
3317 cm->DefineProperty
3318 ("TARGET_ARCHIVES_MAY_BE_SHARED_LIBS", cmProperty::GLOBAL,
3319 "Set if shared libraries may be named like archives.",
3320 "On AIX shared libraries may be named \"lib<name>.a\". "
3321 "This property is set to true on such platforms.");
3323 cm->DefineProperty
3324 ("FIND_LIBRARY_USE_LIB64_PATHS", cmProperty::GLOBAL,
3325 "Whether FIND_LIBRARY should automatically search lib64 directories.",
3326 "FIND_LIBRARY_USE_LIB64_PATHS is a boolean specifying whether the "
3327 "FIND_LIBRARY command should automatically search the lib64 variant of "
3328 "directories called lib in the search path when building 64-bit "
3329 "binaries.");
3330 cm->DefineProperty
3331 ("ENABLED_FEATURES", cmProperty::GLOBAL,
3332 "List of features which are enabled during the CMake run.",
3333 "List of features which are enabled during the CMake run. Be default "
3334 "it contains the names of all packages which were found. This is "
3335 "determined using the <NAME>_FOUND variables. Packages which are "
3336 "searched QUIET are not listed. A project can add its own features to "
3337 "this list.This property is used by the macros in FeatureSummary.cmake.");
3338 cm->DefineProperty
3339 ("DISABLED_FEATURES", cmProperty::GLOBAL,
3340 "List of features which are disabled during the CMake run.",
3341 "List of features which are disabled during the CMake run. Be default "
3342 "it contains the names of all packages which were not found. This is "
3343 "determined using the <NAME>_FOUND variables. Packages which are "
3344 "searched QUIET are not listed. A project can add its own features to "
3345 "this list.This property is used by the macros in FeatureSummary.cmake.");
3346 cm->DefineProperty
3347 ("PACKAGES_FOUND", cmProperty::GLOBAL,
3348 "List of packages which were found during the CMake run.",
3349 "List of packages which were found during the CMake run. Whether a "
3350 "package has been found is determined using the <NAME>_FOUND variables.");
3351 cm->DefineProperty
3352 ("PACKAGES_NOT_FOUND", cmProperty::GLOBAL,
3353 "List of packages which were not found during the CMake run.",
3354 "List of packages which were not found during the CMake run. Whether a "
3355 "package has been found is determined using the <NAME>_FOUND variables.");
3357 cm->DefineProperty
3358 ("PACKAGES_NOT_FOUND", cmProperty::GLOBAL,
3359 "List of packages which were not found during the CMake run.",
3360 "List of packages which were not found during the CMake run. Whether a "
3361 "package has been found is determined using the <NAME>_FOUND variables.");
3362 cm->DefineProperty(
3363 "__CMAKE_DELETE_CACHE_CHANGE_VARS_", cmProperty::GLOBAL,
3364 "Internal property",
3365 "Used to detect compiler changes, Do not set.");
3367 cm->DefineProperty(
3368 "GLOBAL_DEPENDS_DEBUG_MODE", cmProperty::GLOBAL,
3369 "Enable global target dependency graph debug mode.",
3370 "CMake automatically analyzes the global inter-target dependency graph "
3371 "at the beginning of native build system generation. "
3372 "This property causes it to display details of its analysis to stderr.");
3374 cm->DefineProperty(
3375 "ALLOW_DUPLICATE_CUSTOM_TARGETS", cmProperty::GLOBAL,
3376 "Allow duplicate custom targets to be created.",
3377 "Normally CMake requires that all targets built in a project have "
3378 "globally unique logical names (see policy CMP0002). "
3379 "This is necessary to generate meaningful project file names in "
3380 "Xcode and VS IDE generators. "
3381 "It also allows the target names to be referenced unambiguously.\n"
3382 "Makefile generators are capable of supporting duplicate custom target "
3383 "names. "
3384 "For projects that care only about Makefile generators and do "
3385 "not wish to support Xcode or VS IDE generators, one may set this "
3386 "property to true to allow duplicate custom targets. "
3387 "The property allows multiple add_custom_target command calls in "
3388 "different directories to specify the same target name. "
3389 "However, setting this property will cause non-Makefile generators "
3390 "to produce an error and refuse to generate the project."
3393 cm->DefineProperty
3394 ("IN_TRY_COMPILE", cmProperty::GLOBAL,
3395 "Read-only property that is true during a try-compile configuration.",
3396 "True when building a project inside a TRY_COMPILE or TRY_RUN command.");
3398 // ================================================================
3399 // define variables as well
3400 // ================================================================
3401 cmDocumentVariables::DefineVariables(cm);
3405 void cmake::DefineProperty(const char *name, cmProperty::ScopeType scope,
3406 const char *ShortDescription,
3407 const char *FullDescription,
3408 bool chained, const char *docSection)
3410 this->PropertyDefinitions[scope].DefineProperty(name,scope,ShortDescription,
3411 FullDescription,
3412 docSection,
3413 chained);
3416 cmPropertyDefinition *cmake
3417 ::GetPropertyDefinition(const char *name,
3418 cmProperty::ScopeType scope)
3420 if (this->IsPropertyDefined(name,scope))
3422 return &(this->PropertyDefinitions[scope][name]);
3424 return 0;
3427 void cmake::RecordPropertyAccess(const char *name,
3428 cmProperty::ScopeType scope)
3430 this->AccessedProperties.insert
3431 (std::pair<cmStdString,cmProperty::ScopeType>(name,scope));
3434 void cmake::ReportUndefinedPropertyAccesses(const char *filename)
3436 FILE *progFile = fopen(filename,"w");
3437 if (!progFile || !this->GlobalGenerator)
3439 return;
3442 // what are the enabled languages?
3443 std::vector<std::string> enLangs;
3444 this->GlobalGenerator->GetEnabledLanguages(enLangs);
3446 // Common configuration names.
3447 // TODO: Compute current configuration(s).
3448 std::vector<std::string> enConfigs;
3449 enConfigs.push_back("");
3450 enConfigs.push_back("DEBUG");
3451 enConfigs.push_back("RELEASE");
3452 enConfigs.push_back("MINSIZEREL");
3453 enConfigs.push_back("RELWITHDEBINFO");
3455 // take all the defined properties and add definitions for all the enabled
3456 // languages
3457 std::set<std::pair<cmStdString,cmProperty::ScopeType> > aliasedProperties;
3458 std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::iterator i;
3459 i = this->PropertyDefinitions.begin();
3460 for (;i != this->PropertyDefinitions.end(); ++i)
3462 cmPropertyDefinitionMap::iterator j;
3463 for (j = i->second.begin(); j != i->second.end(); ++j)
3465 // TODO: What if both <LANG> and <CONFIG> appear?
3466 if (j->first.find("<CONFIG>") != std::string::npos)
3468 std::vector<std::string>::const_iterator k;
3469 for (k = enConfigs.begin(); k != enConfigs.end(); ++k)
3471 std::string tmp = j->first;
3472 cmSystemTools::ReplaceString(tmp, "<CONFIG>", k->c_str());
3473 // add alias
3474 aliasedProperties.insert
3475 (std::pair<cmStdString,cmProperty::ScopeType>(tmp,i->first));
3478 if (j->first.find("<LANG>") != std::string::npos)
3480 std::vector<std::string>::const_iterator k;
3481 for (k = enLangs.begin(); k != enLangs.end(); ++k)
3483 std::string tmp = j->first;
3484 cmSystemTools::ReplaceString(tmp, "<LANG>", k->c_str());
3485 // add alias
3486 aliasedProperties.insert
3487 (std::pair<cmStdString,cmProperty::ScopeType>(tmp,i->first));
3493 std::set<std::pair<cmStdString,cmProperty::ScopeType> >::const_iterator ap;
3494 ap = this->AccessedProperties.begin();
3495 for (;ap != this->AccessedProperties.end(); ++ap)
3497 if (!this->IsPropertyDefined(ap->first.c_str(),ap->second) &&
3498 aliasedProperties.find(std::pair<cmStdString,cmProperty::ScopeType>
3499 (ap->first,ap->second)) ==
3500 aliasedProperties.end())
3502 const char *scopeStr = "";
3503 switch (ap->second)
3505 case cmProperty::TARGET:
3506 scopeStr = "TARGET";
3507 break;
3508 case cmProperty::SOURCE_FILE:
3509 scopeStr = "SOURCE_FILE";
3510 break;
3511 case cmProperty::DIRECTORY:
3512 scopeStr = "DIRECTORY";
3513 break;
3514 case cmProperty::TEST:
3515 scopeStr = "TEST";
3516 break;
3517 case cmProperty::VARIABLE:
3518 scopeStr = "VARIABLE";
3519 break;
3520 case cmProperty::CACHED_VARIABLE:
3521 scopeStr = "CACHED_VARIABLE";
3522 break;
3523 default:
3524 scopeStr = "unknown";
3525 break;
3527 fprintf(progFile,"%s with scope %s\n",ap->first.c_str(),scopeStr);
3530 fclose(progFile);
3533 bool cmake::IsPropertyDefined(const char *name, cmProperty::ScopeType scope)
3535 return this->PropertyDefinitions[scope].IsPropertyDefined(name);
3538 bool cmake::IsPropertyChained(const char *name, cmProperty::ScopeType scope)
3540 return this->PropertyDefinitions[scope].IsPropertyChained(name);
3543 void cmake::SetProperty(const char* prop, const char* value)
3545 if (!prop)
3547 return;
3549 if (!value)
3551 value = "NOTFOUND";
3554 this->Properties.SetProperty(prop, value, cmProperty::GLOBAL);
3557 void cmake::AppendProperty(const char* prop, const char* value)
3559 if (!prop)
3561 return;
3563 this->Properties.AppendProperty(prop, value, cmProperty::GLOBAL);
3566 const char *cmake::GetProperty(const char* prop)
3568 return this->GetProperty(prop, cmProperty::GLOBAL);
3571 const char *cmake::GetProperty(const char* prop, cmProperty::ScopeType scope)
3573 bool chain = false;
3575 // watch for special properties
3576 std::string propname = prop;
3577 std::string output = "";
3578 if ( propname == "CACHE_VARIABLES" )
3580 cmCacheManager::CacheIterator cit =
3581 this->GetCacheManager()->GetCacheIterator();
3582 for ( cit.Begin(); !cit.IsAtEnd(); cit.Next() )
3584 if ( output.size() )
3586 output += ";";
3588 output += cit.GetName();
3590 this->SetProperty("CACHE_VARIABLES", output.c_str());
3592 else if ( propname == "COMMANDS" )
3594 cmake::RegisteredCommandsMap::iterator cmds
3595 = this->GetCommands()->begin();
3596 for (unsigned int cc=0 ; cmds != this->GetCommands()->end(); ++ cmds )
3598 if ( cc > 0 )
3600 output += ";";
3602 output += cmds->first.c_str();
3603 cc++;
3605 this->SetProperty("COMMANDS",output.c_str());
3607 else if ( propname == "IN_TRY_COMPILE" )
3609 this->SetProperty("IN_TRY_COMPILE",
3610 this->GetIsInTryCompile()? "1":"0");
3612 return this->Properties.GetPropertyValue(prop, scope, chain);
3615 bool cmake::GetPropertyAsBool(const char* prop)
3617 return cmSystemTools::IsOn(this->GetProperty(prop));
3620 int cmake::GetSystemInformation(std::vector<std::string>& args)
3622 // so create the directory
3623 std::string resultFile;
3624 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
3625 std::string destPath = cwd + "/__cmake_systeminformation";
3626 cmSystemTools::RemoveADirectory(destPath.c_str());
3627 if (!cmSystemTools::MakeDirectory(destPath.c_str()))
3629 std::cerr << "Error: --system-information must be run from a "
3630 "writable directory!\n";
3631 return 1;
3634 // process the arguments
3635 bool writeToStdout = true;
3636 for(unsigned int i=1; i < args.size(); ++i)
3638 std::string arg = args[i];
3639 if(arg.find("-V",0) == 0)
3641 this->Verbose = true;
3643 else if(arg.find("-G",0) == 0)
3645 std::string value = arg.substr(2);
3646 if(value.size() == 0)
3648 ++i;
3649 if(i >= args.size())
3651 cmSystemTools::Error("No generator specified for -G");
3652 return -1;
3654 value = args[i];
3656 cmGlobalGenerator* gen =
3657 this->CreateGlobalGenerator(value.c_str());
3658 if(!gen)
3660 cmSystemTools::Error("Could not create named generator ",
3661 value.c_str());
3663 else
3665 this->SetGlobalGenerator(gen);
3668 // no option assume it is the output file
3669 else
3671 if (!cmSystemTools::FileIsFullPath(arg.c_str()))
3673 resultFile = cwd;
3674 resultFile += "/";
3676 resultFile += arg;
3677 writeToStdout = false;
3682 // we have to find the module directory, so we can copy the files
3683 this->AddCMakePaths();
3684 std::string modulesPath =
3685 this->CacheManager->GetCacheValue("CMAKE_ROOT");
3686 modulesPath += "/Modules";
3687 std::string inFile = modulesPath;
3688 inFile += "/SystemInformation.cmake";
3689 std::string outFile = destPath;
3690 outFile += "/CMakeLists.txt";
3692 // Copy file
3693 if(!cmSystemTools::cmCopyFile(inFile.c_str(), outFile.c_str()))
3695 std::cerr << "Error copying file \"" << inFile.c_str()
3696 << "\" to \"" << outFile.c_str() << "\".\n";
3697 return 1;
3700 // do we write to a file or to stdout?
3701 if (resultFile.size() == 0)
3703 resultFile = cwd;
3704 resultFile += "/__cmake_systeminformation/results.txt";
3707 // now run cmake on the CMakeLists file
3708 cmSystemTools::ChangeDirectory(destPath.c_str());
3709 std::vector<std::string> args2;
3710 args2.push_back(args[0]);
3711 args2.push_back(destPath);
3712 std::string resultArg = "-DRESULT_FILE=";
3713 resultArg += resultFile;
3714 args2.push_back(resultArg);
3715 int res = this->Run(args2, false);
3717 if (res != 0)
3719 std::cerr << "Error: --system-information failed on internal CMake!\n";
3720 return res;
3723 // change back to the original directory
3724 cmSystemTools::ChangeDirectory(cwd.c_str());
3726 // echo results to stdout if needed
3727 if (writeToStdout)
3729 FILE* fin = fopen(resultFile.c_str(), "r");
3730 if(fin)
3732 const int bufferSize = 4096;
3733 char buffer[bufferSize];
3734 size_t n;
3735 while((n = fread(buffer, 1, bufferSize, fin)) > 0)
3737 for(char* c = buffer; c < buffer+n; ++c)
3739 putc(*c, stdout);
3741 fflush(stdout);
3743 fclose(fin);
3747 // clean up the directory
3748 cmSystemTools::RemoveADirectory(destPath.c_str());
3749 return 0;
3752 //----------------------------------------------------------------------------
3753 static bool cmakeCheckStampFile(const char* stampName)
3755 // If the stamp file still exists then it must really be out of
3756 // date.
3757 if(cmSystemTools::FileExists(stampName))
3759 // Notify the user why CMake is re-running. It is safe to
3760 // just print to stdout here because this code is only reachable
3761 // through an undocumented flag used by the VS generator.
3762 std::cout << "CMake is re-running due to explicit user request.\n";
3763 return false;
3766 // The stamp file does not exist. Use the stamp dependencies to
3767 // determine whether it is really out of date. This works in
3768 // conjunction with cmLocalVisualStudio7Generator to avoid
3769 // repeatedly re-running CMake when the user rebuilds the entire
3770 // solution.
3771 std::string stampDepends = stampName;
3772 stampDepends += ".depend";
3773 #if defined(_WIN32) || defined(__CYGWIN__)
3774 std::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
3775 #else
3776 std::ifstream fin(stampDepends.c_str(), std::ios::in);
3777 #endif
3778 if(!fin)
3780 // The stamp dependencies file cannot be read. Just assume the
3781 // build system is really out of date.
3782 return false;
3785 // Compare the stamp dependencies against the dependency file itself.
3786 cmFileTimeComparison ftc;
3787 std::string dep;
3788 while(cmSystemTools::GetLineFromStream(fin, dep))
3790 int result;
3791 if(dep.length() >= 1 && dep[0] != '#' &&
3792 (!ftc.FileTimeCompare(stampDepends.c_str(), dep.c_str(), &result)
3793 || result < 0))
3795 // The stamp depends file is older than this dependency. The
3796 // build system is really out of date.
3797 return false;
3801 // The build system is up to date. The stamp file has been removed
3802 // by the VS IDE due to a "rebuild" request. Just restore it.
3803 std::ofstream stamp(stampName);
3804 stamp << "# CMake generation timestamp file this directory.\n";
3805 if(stamp)
3807 // Notify the user why CMake is not re-running. It is safe to
3808 // just print to stdout here because this code is only reachable
3809 // through an undocumented flag used by the VS generator.
3810 std::cout << "CMake does not need to re-run because "
3811 << stampName << " is up-to-date.\n";
3812 return true;
3814 else
3816 cmSystemTools::Error("Cannot restore timestamp ", stampName);
3817 return false;
3821 //----------------------------------------------------------------------------
3822 static bool cmakeCheckStampList(const char* stampList)
3824 // If the stamp list does not exist CMake must rerun to generate it.
3825 if(!cmSystemTools::FileExists(stampList))
3827 std::cout << "CMake is re-running because generate.stamp.list "
3828 << "is missing.\n";
3829 return false;
3831 std::ifstream fin(stampList);
3832 if(!fin)
3834 std::cout << "CMake is re-running because generate.stamp.list "
3835 << "could not be read.\n";
3836 return false;
3839 // Check each stamp.
3840 std::string stampName;
3841 while(cmSystemTools::GetLineFromStream(fin, stampName))
3843 if(!cmakeCheckStampFile(stampName.c_str()))
3845 return false;
3848 return true;
3851 // For visual studio 2005 and newer manifest files need to be embeded into
3852 // exe and dll's. This code does that in such a way that incremental linking
3853 // still works.
3854 int cmake::VisualStudioLink(std::vector<std::string>& args, int type)
3856 if(args.size() < 2)
3858 return -1;
3860 bool verbose = false;
3861 if(cmSystemTools::GetEnv("VERBOSE"))
3863 verbose = true;
3865 std::vector<std::string> expandedArgs;
3866 for(std::vector<std::string>::iterator i = args.begin();
3867 i != args.end(); ++i)
3869 // check for nmake temporary files
3870 if((*i)[0] == '@')
3872 std::ifstream fin(i->substr(1).c_str());
3873 std::string line;
3874 while(cmSystemTools::GetLineFromStream(fin,
3875 line))
3877 cmSystemTools::ParseWindowsCommandLine(line.c_str(), expandedArgs);
3880 else
3882 expandedArgs.push_back(*i);
3885 // figure out if this is an incremental link or not and run the correct
3886 // link function.
3887 for(std::vector<std::string>::iterator i = expandedArgs.begin();
3888 i != expandedArgs.end(); ++i)
3890 if(cmSystemTools::Strucmp(i->c_str(), "/INCREMENTAL:YES") == 0)
3892 if(verbose)
3894 std::cout << "Visual Studio Incremental Link\n";
3896 return cmake::VisualStudioLinkIncremental(expandedArgs, type, verbose);
3899 if(verbose)
3901 std::cout << "Visual Studio Non-Incremental Link\n";
3903 return cmake::VisualStudioLinkNonIncremental(expandedArgs, type, verbose);
3906 int cmake::ParseVisualStudioLinkCommand(std::vector<std::string>& args,
3907 std::vector<cmStdString>& command,
3908 std::string& targetName)
3910 std::vector<std::string>::iterator i = args.begin();
3911 i++; // skip -E
3912 i++; // skip vs_link_dll or vs_link_exe
3913 command.push_back(*i);
3914 i++; // move past link command
3915 for(; i != args.end(); ++i)
3917 command.push_back(*i);
3918 if(i->find("/Fe") == 0)
3920 targetName = i->substr(3);
3922 if(i->find("/out:") == 0)
3924 targetName = i->substr(5);
3927 if(targetName.size() == 0 || command.size() == 0)
3929 return -1;
3931 return 0;
3934 bool cmake::RunCommand(const char* comment,
3935 std::vector<cmStdString>& command,
3936 bool verbose,
3937 int* retCodeOut)
3939 if(verbose)
3941 std::cout << comment << ":\n";
3942 for(std::vector<cmStdString>::iterator i = command.begin();
3943 i != command.end(); ++i)
3945 std::cout << i->c_str() << " ";
3947 std::cout << "\n";
3949 std::string output;
3950 int retCode =0;
3951 // use rc command to create .res file
3952 cmSystemTools::RunSingleCommand(command,
3953 &output,
3954 &retCode, 0, false);
3955 // always print the output of the command, unless
3956 // it is the dumb rc command banner, but if the command
3957 // returned an error code then print the output anyway as
3958 // the banner may be mixed with some other important information.
3959 if(output.find("Resource Compiler Version") == output.npos
3960 || retCode !=0)
3962 std::cout << output;
3964 // if retCodeOut is requested then always return true
3965 // and set the retCodeOut to retCode
3966 if(retCodeOut)
3968 *retCodeOut = retCode;
3969 return true;
3971 if(retCode != 0)
3973 std::cout << comment << " failed. with " << retCode << "\n";
3975 return retCode == 0;
3978 int cmake::VisualStudioLinkIncremental(std::vector<std::string>& args,
3979 int type, bool verbose)
3981 // This follows the steps listed here:
3982 // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx
3984 // 1. Compiler compiles the application and generates the *.obj files.
3985 // 2. An empty manifest file is generated if this is a clean build and if
3986 // not the previous one is reused.
3987 // 3. The resource compiler (rc.exe) compiles the *.manifest file to a
3988 // *.res file.
3989 // 4. Linker generates the binary (EXE or DLL) with the /incremental
3990 // switch and embeds the dummy manifest file. The linker also generates
3991 // the real manifest file based on the binaries that your binary depends
3992 // on.
3993 // 5. The manifest tool (mt.exe) is then used to generate the final
3994 // manifest.
3996 // If the final manifest is changed, then 6 and 7 are run, if not
3997 // they are skipped, and it is done.
3999 // 6. The resource compiler is invoked one more time.
4000 // 7. Finally, the Linker does another incremental link, but since the
4001 // only thing that has changed is the *.res file that contains the
4002 // manifest it is a short link.
4003 std::vector<cmStdString> linkCommand;
4004 std::string targetName;
4005 if(cmake::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1)
4007 return -1;
4009 std::string manifestArg = "/MANIFESTFILE:";
4010 std::vector<cmStdString> rcCommand;
4011 rcCommand.push_back(cmSystemTools::FindProgram("rc.exe"));
4012 std::vector<cmStdString> mtCommand;
4013 mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
4014 std::string tempManifest;
4015 tempManifest = targetName;
4016 tempManifest += ".intermediate.manifest";
4017 std::string resourceInputFile = targetName;
4018 resourceInputFile += ".resource.txt";
4019 if(verbose)
4021 std::cout << "Create " << resourceInputFile.c_str() << "\n";
4023 // Create input file for rc command
4024 std::ofstream fout(resourceInputFile.c_str());
4025 if(!fout)
4027 return -1;
4029 std::string manifestFile = targetName;
4030 manifestFile += ".embed.manifest";
4031 std::string fullPath= cmSystemTools::CollapseFullPath(manifestFile.c_str());
4032 fout << type << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID "
4033 "*/ 24 /* RT_MANIFEST */ " << "\"" << fullPath.c_str() << "\"";
4034 fout.close();
4035 manifestArg += tempManifest;
4036 // add the manifest arg to the linkCommand
4037 linkCommand.push_back(manifestArg);
4038 // if manifestFile is not yet created, create an
4039 // empty one
4040 if(!cmSystemTools::FileExists(manifestFile.c_str()))
4042 if(verbose)
4044 std::cout << "Create empty: " << manifestFile.c_str() << "\n";
4046 std::ofstream foutTmp(manifestFile.c_str());
4048 std::string resourceFile = manifestFile;
4049 resourceFile += ".res";
4050 // add the resource file to the end of the link command
4051 linkCommand.push_back(resourceFile);
4052 std::string outputOpt = "/fo";
4053 outputOpt += resourceFile;
4054 rcCommand.push_back(outputOpt);
4055 rcCommand.push_back(resourceInputFile);
4056 // Run rc command to create resource
4057 if(!cmake::RunCommand("RC Pass 1", rcCommand, verbose))
4059 return -1;
4061 // Now run the link command to link and create manifest
4062 if(!cmake::RunCommand("LINK Pass 1", linkCommand, verbose))
4064 return -1;
4066 // create mt command
4067 std::string outArg("/out:");
4068 outArg+= manifestFile;
4069 mtCommand.push_back("/nologo");
4070 mtCommand.push_back(outArg);
4071 mtCommand.push_back("/notify_update");
4072 mtCommand.push_back("/manifest");
4073 mtCommand.push_back(tempManifest);
4074 // now run mt.exe to create the final manifest file
4075 int mtRet =0;
4076 cmake::RunCommand("MT", mtCommand, verbose, &mtRet);
4077 // if mt returns 0, then the manifest was not changed and
4078 // we do not need to do another link step
4079 if(mtRet == 0)
4081 return 0;
4083 // check for magic mt return value if mt returns the magic number
4084 // 1090650113 then it means that it updated the manifest file and we need
4085 // to do the final link. If mt has any value other than 0 or 1090650113
4086 // then there was some problem with the command itself and there was an
4087 // error so return the error code back out of cmake so make can report it.
4088 if(mtRet != 1090650113)
4090 return mtRet;
4092 // update the resource file with the new manifest from the mt command.
4093 if(!cmake::RunCommand("RC Pass 2", rcCommand, verbose))
4095 return -1;
4097 // Run the final incremental link that will put the new manifest resource
4098 // into the file incrementally.
4099 if(!cmake::RunCommand("FINAL LINK", linkCommand, verbose))
4101 return -1;
4103 return 0;
4106 int cmake::VisualStudioLinkNonIncremental(std::vector<std::string>& args,
4107 int type,
4108 bool verbose)
4110 std::vector<cmStdString> linkCommand;
4111 std::string targetName;
4112 if(cmake::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1)
4114 return -1;
4116 // Run the link command as given
4117 if(!cmake::RunCommand("LINK", linkCommand, verbose))
4119 return -1;
4121 std::vector<cmStdString> mtCommand;
4122 mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
4123 mtCommand.push_back("/nologo");
4124 mtCommand.push_back("/manifest");
4125 std::string manifestFile = targetName;
4126 manifestFile += ".manifest";
4127 mtCommand.push_back(manifestFile);
4128 std::string outresource = "/outputresource:";
4129 outresource += targetName;
4130 outresource += ";#";
4131 if(type == 1)
4133 outresource += "1";
4135 else if(type == 2)
4137 outresource += "2";
4139 mtCommand.push_back(outresource);
4140 // Now use the mt tool to embed the manifest into the exe or dll
4141 if(!cmake::RunCommand("MT", mtCommand, verbose))
4143 return -1;
4145 return 0;
4148 //----------------------------------------------------------------------------
4149 void cmake::IssueMessage(cmake::MessageType t, std::string const& text,
4150 cmListFileBacktrace const& backtrace)
4152 cmOStringStream msg;
4153 bool isError = false;
4154 // Construct the message header.
4155 if(t == cmake::FATAL_ERROR)
4157 isError = true;
4158 msg << "CMake Error";
4160 else if(t == cmake::INTERNAL_ERROR)
4162 isError = true;
4163 msg << "CMake Internal Error (please report a bug)";
4165 else
4167 msg << "CMake Warning";
4168 if(t == cmake::AUTHOR_WARNING)
4170 // Allow suppression of these warnings.
4171 cmCacheManager::CacheIterator it = this->CacheManager
4172 ->GetCacheIterator("CMAKE_SUPPRESS_DEVELOPER_WARNINGS");
4173 if(!it.IsAtEnd() && it.GetValueAsBool())
4175 return;
4177 msg << " (dev)";
4181 // Add the immediate context.
4182 cmListFileBacktrace::const_iterator i = backtrace.begin();
4183 if(i != backtrace.end())
4185 cmListFileContext const& lfc = *i;
4186 msg << (lfc.Line? " at ": " in ") << lfc;
4187 ++i;
4190 // Add the message text.
4192 msg << ":\n";
4193 cmDocumentationFormatterText formatter;
4194 formatter.SetIndent(" ");
4195 formatter.PrintFormatted(msg, text.c_str());
4198 // Add the rest of the context.
4199 if(i != backtrace.end())
4201 msg << "Call Stack (most recent call first):\n";
4202 while(i != backtrace.end())
4204 cmListFileContext const& lfc = *i;
4205 msg << " " << lfc << "\n";
4206 ++i;
4210 // Add a note about warning suppression.
4211 if(t == cmake::AUTHOR_WARNING)
4213 msg <<
4214 "This warning is for project developers. Use -Wno-dev to suppress it.";
4217 // Add a terminating blank line.
4218 msg << "\n";
4220 // Output the message.
4221 if(isError)
4223 cmSystemTools::SetErrorOccured();
4224 cmSystemTools::Message(msg.str().c_str(), "Error");
4226 else
4228 cmSystemTools::Message(msg.str().c_str(), "Warning");