Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmake.cxx
blob1b33fdc07d9996e71e6c8222556a7333063c2e2d
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmake.cxx,v $
5 Language: C++
6 Date: $Date: 2008/01/24 19:37:48 $
7 Version: $Revision: 1.355 $
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"
32 #if defined(CMAKE_BUILD_WITH_CMAKE)
33 # include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
34 # include "cmVariableWatch.h"
35 # include <cmsys/Terminal.h>
36 #endif
38 #include <cmsys/Directory.hxx>
39 #include <cmsys/Process.h>
40 #include <cmsys/Glob.hxx>
41 #include <cmsys/RegularExpression.hxx>
43 // only build kdevelop generator on non-windows platforms
44 // when not bootstrapping cmake
45 #if !defined(_WIN32)
46 # if defined(CMAKE_BUILD_WITH_CMAKE)
47 # define CMAKE_USE_KDEVELOP
48 # endif
49 #endif
51 #if defined(CMAKE_BUILD_WITH_CMAKE)
52 # define CMAKE_USE_ECLIPSE
53 #endif
55 #if defined(__MINGW32__) && !defined(CMAKE_BUILD_WITH_CMAKE)
56 # define CMAKE_BOOT_MINGW
57 #endif
59 // include the generator
60 #if defined(_WIN32) && !defined(__CYGWIN__)
61 # if !defined(CMAKE_BOOT_MINGW)
62 # include "cmGlobalVisualStudio6Generator.h"
63 # include "cmGlobalVisualStudio7Generator.h"
64 # include "cmGlobalVisualStudio71Generator.h"
65 # include "cmGlobalVisualStudio8Generator.h"
66 # include "cmGlobalVisualStudio9Generator.h"
67 # include "cmGlobalVisualStudio9Win64Generator.h"
68 # include "cmGlobalVisualStudio8Win64Generator.h"
69 # include "cmGlobalBorlandMakefileGenerator.h"
70 # include "cmGlobalNMakeMakefileGenerator.h"
71 # include "cmGlobalWatcomWMakeGenerator.h"
72 # define CMAKE_HAVE_VS_GENERATORS
73 # endif
74 # include "cmGlobalMSYSMakefileGenerator.h"
75 # include "cmGlobalMinGWMakefileGenerator.h"
76 # include "cmWin32ProcessExecution.h"
77 #else
78 #endif
79 #include "cmGlobalUnixMakefileGenerator3.h"
81 #if defined(CMAKE_HAVE_VS_GENERATORS)
82 #include "cmCallVisualStudioMacro.h"
83 #endif
85 #if !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
86 # include "cmExtraCodeBlocksGenerator.h"
87 #endif
89 #ifdef CMAKE_USE_KDEVELOP
90 # include "cmGlobalKdevelopGenerator.h"
91 #endif
93 #ifdef CMAKE_USE_ECLIPSE
94 # include "cmExtraEclipseCDT4Generator.h"
95 #endif
97 #include <stdlib.h> // required for atoi
99 #if defined( __APPLE__ )
100 # if defined(CMAKE_BUILD_WITH_CMAKE)
101 # include "cmGlobalXCodeGenerator.h"
102 # define CMAKE_USE_XCODE 1
103 # endif
104 # include <sys/types.h>
105 # include <sys/time.h>
106 # include <sys/resource.h>
107 #endif
109 #include <sys/stat.h> // struct stat
111 #include <memory> // auto_ptr
113 static bool cmakeCheckStampFile(const char* stampName);
115 void cmNeedBackwardsCompatibility(const std::string& variable,
116 int access_type, void*, const char*, const cmMakefile*)
118 #ifdef CMAKE_BUILD_WITH_CMAKE
119 if (access_type == cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS)
121 std::string message = "An attempt was made to access a variable: ";
122 message += variable;
123 message +=
124 " that has not been defined. Some variables were always defined "
125 "by CMake in versions prior to 1.6. To fix this you might need to set "
126 "the cache value of CMAKE_BACKWARDS_COMPATIBILITY to 1.4 or less. If "
127 "you are writing a CMakeList file, (or have already set "
128 "CMAKE_BACKWARDS_COMPATABILITY to 1.4 or less) then you probably need "
129 "to include a CMake module to test for the feature this variable "
130 "defines.";
131 cmSystemTools::Error(message.c_str());
133 #else
134 (void)variable;
135 (void)access_type;
136 #endif
139 cmake::cmake()
141 this->DebugOutput = false;
142 this->DebugTryCompile = false;
143 this->ClearBuildSystem = false;
144 this->FileComparison = new cmFileTimeComparison;
146 this->Properties.SetCMakeInstance(this);
148 // initialize properties
149 cmSourceFile::DefineProperties(this);
150 cmTarget::DefineProperties(this);
151 cmMakefile::DefineProperties(this);
152 cmTest::DefineProperties(this);
153 cmake::DefineProperties(this);
155 #ifdef __APPLE__
156 struct rlimit rlp;
157 if(!getrlimit(RLIMIT_STACK, &rlp))
159 if(rlp.rlim_cur != rlp.rlim_max)
161 rlp.rlim_cur = rlp.rlim_max;
162 setrlimit(RLIMIT_STACK, &rlp);
165 #endif
167 // If MAKEFLAGS are given in the environment, remove the environment
168 // variable. This will prevent try-compile from succeeding when it
169 // should fail (if "-i" is an option). We cannot simply test
170 // whether "-i" is given and remove it because some make programs
171 // encode the MAKEFLAGS variable in a strange way.
172 if(getenv("MAKEFLAGS"))
174 cmSystemTools::PutEnv("MAKEFLAGS=");
177 this->Verbose = false;
178 this->InTryCompile = false;
179 this->CacheManager = new cmCacheManager;
180 this->GlobalGenerator = 0;
181 this->ProgressCallback = 0;
182 this->ProgressCallbackClientData = 0;
183 this->ScriptMode = false;
185 #ifdef CMAKE_BUILD_WITH_CMAKE
186 this->VariableWatch = new cmVariableWatch;
187 this->VariableWatch->AddWatch("CMAKE_WORDS_BIGENDIAN",
188 cmNeedBackwardsCompatibility);
189 this->VariableWatch->AddWatch("CMAKE_SIZEOF_INT",
190 cmNeedBackwardsCompatibility);
191 this->VariableWatch->AddWatch("CMAKE_X_LIBS",
192 cmNeedBackwardsCompatibility);
193 #endif
195 this->AddDefaultGenerators();
196 this->AddDefaultExtraGenerators();
197 this->AddDefaultCommands();
199 // Make sure we can capture the build tool output.
200 cmSystemTools::EnableVSConsoleOutput();
203 cmake::~cmake()
205 delete this->CacheManager;
206 if (this->GlobalGenerator)
208 delete this->GlobalGenerator;
209 this->GlobalGenerator = 0;
211 for(RegisteredCommandsMap::iterator j = this->Commands.begin();
212 j != this->Commands.end(); ++j)
214 delete (*j).second;
216 #ifdef CMAKE_BUILD_WITH_CMAKE
217 delete this->VariableWatch;
218 #endif
219 delete this->FileComparison;
222 void cmake::CleanupCommandsAndMacros()
224 std::vector<cmCommand*> commands;
225 for(RegisteredCommandsMap::iterator j = this->Commands.begin();
226 j != this->Commands.end(); ++j)
228 if ( !j->second->IsA("cmMacroHelperCommand") &&
229 !j->second->IsA("cmFunctionHelperCommand"))
231 commands.push_back(j->second);
233 else
235 delete j->second;
238 this->Commands.erase(this->Commands.begin(), this->Commands.end());
239 std::vector<cmCommand*>::iterator it;
240 for ( it = commands.begin(); it != commands.end();
241 ++ it )
243 this->Commands[cmSystemTools::LowerCase((*it)->GetName())] = *it;
247 bool cmake::CommandExists(const char* name) const
249 std::string sName = cmSystemTools::LowerCase(name);
250 return (this->Commands.find(sName) != this->Commands.end());
253 cmCommand *cmake::GetCommand(const char *name)
255 cmCommand* rm = 0;
256 std::string sName = cmSystemTools::LowerCase(name);
257 RegisteredCommandsMap::iterator pos = this->Commands.find(sName);
258 if (pos != this->Commands.end())
260 rm = (*pos).second;
262 return rm;
265 void cmake::RenameCommand(const char*oldName, const char* newName)
267 // if the command already exists, free the old one
268 std::string sOldName = cmSystemTools::LowerCase(oldName);
269 std::string sNewName = cmSystemTools::LowerCase(newName);
270 RegisteredCommandsMap::iterator pos = this->Commands.find(sOldName);
271 if ( pos == this->Commands.end() )
273 return;
275 cmCommand* cmd = pos->second;
277 pos = this->Commands.find(sNewName);
278 if (pos != this->Commands.end())
280 delete pos->second;
281 this->Commands.erase(pos);
283 this->Commands.insert(RegisteredCommandsMap::value_type(sNewName, cmd));
284 pos = this->Commands.find(sOldName);
285 this->Commands.erase(pos);
288 void cmake::RemoveCommand(const char* name)
290 std::string sName = cmSystemTools::LowerCase(name);
291 RegisteredCommandsMap::iterator pos = this->Commands.find(sName);
292 if ( pos != this->Commands.end() )
294 delete pos->second;
295 this->Commands.erase(pos);
299 void cmake::AddCommand(cmCommand* wg)
301 std::string name = cmSystemTools::LowerCase(wg->GetName());
302 // if the command already exists, free the old one
303 RegisteredCommandsMap::iterator pos = this->Commands.find(name);
304 if (pos != this->Commands.end())
306 delete pos->second;
307 this->Commands.erase(pos);
309 this->Commands.insert( RegisteredCommandsMap::value_type(name, wg));
313 void cmake::RemoveUnscriptableCommands()
315 std::vector<std::string> unscriptableCommands;
316 cmake::RegisteredCommandsMap* commands = this->GetCommands();
317 for (cmake::RegisteredCommandsMap::const_iterator pos = commands->begin();
318 pos != commands->end();
319 ++pos)
321 if (!pos->second->IsScriptable())
323 unscriptableCommands.push_back(pos->first);
327 for(std::vector<std::string>::const_iterator it=unscriptableCommands.begin();
328 it != unscriptableCommands.end();
329 ++it)
331 this->RemoveCommand(it->c_str());
335 // Parse the args
336 bool cmake::SetCacheArgs(const std::vector<std::string>& args)
338 for(unsigned int i=1; i < args.size(); ++i)
340 std::string arg = args[i];
341 if(arg.find("-D",0) == 0)
343 std::string entry = arg.substr(2);
344 if(entry.size() == 0)
346 ++i;
347 if(i < args.size())
349 entry = args[i];
351 else
353 cmSystemTools::Error("-D must be followed with VAR=VALUE.");
354 return false;
357 std::string var, value;
358 cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
359 if(cmCacheManager::ParseEntry(entry.c_str(), var, value, type) ||
360 cmCacheManager::ParseEntry(entry.c_str(), var, value))
362 this->CacheManager->AddCacheEntry(var.c_str(), value.c_str(),
363 "No help, variable specified on the command line.", type);
365 else
367 std::cerr << "Parse error in command line argument: " << arg << "\n"
368 << "Should be: VAR:type=value\n";
369 cmSystemTools::Error("No cmake scrpt provided.");
370 return false;
373 else if(arg.find("-U",0) == 0)
375 std::string entryPattern = arg.substr(2);
376 if(entryPattern.size() == 0)
378 ++i;
379 if(i < args.size())
381 entryPattern = args[i];
383 else
385 cmSystemTools::Error("-U must be followed with VAR.");
386 return false;
389 cmsys::RegularExpression regex(
390 cmsys::Glob::PatternToRegex(entryPattern.c_str(), true).c_str());
391 //go through all cache entries and collect the vars which will be removed
392 std::vector<std::string> entriesToDelete;
393 cmCacheManager::CacheIterator it =
394 this->CacheManager->GetCacheIterator();
395 for ( it.Begin(); !it.IsAtEnd(); it.Next() )
397 cmCacheManager::CacheEntryType t = it.GetType();
398 if(t != cmCacheManager::STATIC)
400 std::string entryName = it.GetName();
401 if (regex.find(entryName.c_str()))
403 entriesToDelete.push_back(entryName);
408 // now remove them from the cache
409 for(std::vector<std::string>::const_iterator currentEntry =
410 entriesToDelete.begin();
411 currentEntry != entriesToDelete.end();
412 ++currentEntry)
414 this->CacheManager->RemoveCacheEntry(currentEntry->c_str());
417 else if(arg.find("-C",0) == 0)
419 std::string path = arg.substr(2);
420 if ( path.size() == 0 )
422 ++i;
423 if(i < args.size())
425 path = args[i];
427 else
429 cmSystemTools::Error("-C must be followed by a file name.");
430 return false;
433 std::cerr << "loading initial cache file " << path.c_str() << "\n";
434 this->ReadListFile(path.c_str());
436 else if(arg.find("-P",0) == 0)
438 i++;
439 if(i >= args.size())
441 cmSystemTools::Error("-P must be followed by a file name.");
442 return false;
444 std::string path = args[i];
445 if ( path.size() == 0 )
447 cmSystemTools::Error("No cmake script provided.");
448 return false;
450 this->ReadListFile(path.c_str());
453 return true;
456 void cmake::ReadListFile(const char *path)
458 // if a generator was not yet created, temporarily create one
459 cmGlobalGenerator *gg = this->GetGlobalGenerator();
460 bool created = false;
462 // if a generator was not specified use a generic one
463 if (!gg)
465 gg = new cmGlobalGenerator;
466 gg->SetCMakeInstance(this);
467 created = true;
470 // read in the list file to fill the cache
471 if(path)
473 std::auto_ptr<cmLocalGenerator> lg(gg->CreateLocalGenerator());
474 lg->SetGlobalGenerator(gg);
475 lg->GetMakefile()->SetHomeOutputDirectory
476 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
477 lg->GetMakefile()->SetStartOutputDirectory
478 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
479 lg->GetMakefile()->SetHomeDirectory
480 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
481 lg->GetMakefile()->SetStartDirectory
482 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
483 if (!lg->GetMakefile()->ReadListFile(0, path))
485 cmSystemTools::Error("Error processing file:", path);
489 // free generic one if generated
490 if (created)
492 delete gg;
496 // Parse the args
497 void cmake::SetArgs(const std::vector<std::string>& args)
499 bool directoriesSet = false;
500 for(unsigned int i=1; i < args.size(); ++i)
502 std::string arg = args[i];
503 if(arg.find("-H",0) == 0)
505 directoriesSet = true;
506 std::string path = arg.substr(2);
507 path = cmSystemTools::CollapseFullPath(path.c_str());
508 cmSystemTools::ConvertToUnixSlashes(path);
509 this->SetHomeDirectory(path.c_str());
511 else if(arg.find("-S",0) == 0)
513 // There is no local generate anymore. Ignore -S option.
515 else if(arg.find("-O",0) == 0)
517 // There is no local generate anymore. Ignore -O option.
519 else if(arg.find("-B",0) == 0)
521 directoriesSet = true;
522 std::string path = arg.substr(2);
523 path = cmSystemTools::CollapseFullPath(path.c_str());
524 cmSystemTools::ConvertToUnixSlashes(path);
525 this->SetHomeOutputDirectory(path.c_str());
527 else if((i < args.size()-1) && (arg.find("--check-build-system",0) == 0))
529 this->CheckBuildSystemArgument = args[++i];
530 this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
532 else if((i < args.size()-1) && (arg.find("--check-stamp-file",0) == 0))
534 this->CheckStampFile = args[++i];
536 #if defined(CMAKE_HAVE_VS_GENERATORS)
537 else if((i < args.size()-1) && (arg.find("--vs-solution-file",0) == 0))
539 this->VSSolutionFile = args[++i];
541 #endif
542 else if(arg.find("-V",0) == 0)
544 this->Verbose = true;
546 else if(arg.find("-D",0) == 0)
548 // skip for now
550 else if(arg.find("-U",0) == 0)
552 // skip for now
554 else if(arg.find("-C",0) == 0)
556 // skip for now
558 else if(arg.find("-P",0) == 0)
560 // skip for now
561 i++;
563 else if(arg.find("--graphviz=",0) == 0)
565 std::string path = arg.substr(strlen("--graphviz="));
566 path = cmSystemTools::CollapseFullPath(path.c_str());
567 cmSystemTools::ConvertToUnixSlashes(path);
568 this->GraphVizFile = path;
569 if ( this->GraphVizFile.empty() )
571 cmSystemTools::Error("No file specified for --graphviz");
574 else if(arg.find("--debug-trycompile",0) == 0)
576 std::cout << "debug trycompile on\n";
577 this->DebugTryCompileOn();
579 else if(arg.find("--debug-output",0) == 0)
581 std::cout << "Running with debug output on.\n";
582 this->DebugOutputOn();
584 else if(arg.find("-G",0) == 0)
586 std::string value = arg.substr(2);
587 if(value.size() == 0)
589 ++i;
590 if(i >= args.size())
592 cmSystemTools::Error("No generator specified for -G");
593 return;
595 value = args[i];
597 cmGlobalGenerator* gen =
598 this->CreateGlobalGenerator(value.c_str());
599 if(!gen)
601 cmSystemTools::Error("Could not create named generator ",
602 value.c_str());
604 else
606 this->SetGlobalGenerator(gen);
609 // no option assume it is the path to the source
610 else
612 directoriesSet = true;
613 this->SetDirectoriesFromFile(arg.c_str());
616 if(!directoriesSet)
618 this->SetHomeOutputDirectory
619 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
620 this->SetStartOutputDirectory
621 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
622 this->SetHomeDirectory
623 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
624 this->SetStartDirectory
625 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
628 this->SetStartDirectory(this->GetHomeDirectory());
629 this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
632 //----------------------------------------------------------------------------
633 void cmake::SetDirectoriesFromFile(const char* arg)
635 // Check if the argument refers to a CMakeCache.txt or
636 // CMakeLists.txt file.
637 std::string listPath;
638 std::string cachePath;
639 bool argIsFile = false;
640 if(cmSystemTools::FileIsDirectory(arg))
642 std::string path = cmSystemTools::CollapseFullPath(arg);
643 cmSystemTools::ConvertToUnixSlashes(path);
644 std::string cacheFile = path;
645 cacheFile += "/CMakeCache.txt";
646 std::string listFile = path;
647 listFile += "/CMakeLists.txt";
648 if(cmSystemTools::FileExists(cacheFile.c_str()))
650 cachePath = path;
652 if(cmSystemTools::FileExists(listFile.c_str()))
654 listPath = path;
657 else if(cmSystemTools::FileExists(arg))
659 argIsFile = true;
660 std::string fullPath = cmSystemTools::CollapseFullPath(arg);
661 std::string name = cmSystemTools::GetFilenameName(fullPath.c_str());
662 name = cmSystemTools::LowerCase(name);
663 if(name == "cmakecache.txt")
665 cachePath = cmSystemTools::GetFilenamePath(fullPath.c_str());
667 else if(name == "cmakelists.txt")
669 listPath = cmSystemTools::GetFilenamePath(fullPath.c_str());
672 else
674 // Specified file or directory does not exist. Try to set things
675 // up to produce a meaningful error message.
676 std::string fullPath = cmSystemTools::CollapseFullPath(arg);
677 std::string name = cmSystemTools::GetFilenameName(fullPath.c_str());
678 name = cmSystemTools::LowerCase(name);
679 if(name == "cmakecache.txt" || name == "cmakelists.txt")
681 argIsFile = true;
682 listPath = cmSystemTools::GetFilenamePath(fullPath.c_str());
684 else
686 listPath = fullPath;
690 // If there is a CMakeCache.txt file, use its settings.
691 if(cachePath.length() > 0)
693 cmCacheManager* cachem = this->GetCacheManager();
694 cmCacheManager::CacheIterator it = cachem->NewIterator();
695 if(cachem->LoadCache(cachePath.c_str()) &&
696 it.Find("CMAKE_HOME_DIRECTORY"))
698 this->SetHomeOutputDirectory(cachePath.c_str());
699 this->SetStartOutputDirectory(cachePath.c_str());
700 this->SetHomeDirectory(it.GetValue());
701 this->SetStartDirectory(it.GetValue());
702 return;
706 // If there is a CMakeLists.txt file, use it as the source tree.
707 if(listPath.length() > 0)
709 this->SetHomeDirectory(listPath.c_str());
710 this->SetStartDirectory(listPath.c_str());
712 if(argIsFile)
714 // Source CMakeLists.txt file given. It was probably dropped
715 // onto the executable in a GUI. Default to an in-source build.
716 this->SetHomeOutputDirectory(listPath.c_str());
717 this->SetStartOutputDirectory(listPath.c_str());
719 else
721 // Source directory given on command line. Use current working
722 // directory as build tree.
723 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
724 this->SetHomeOutputDirectory(cwd.c_str());
725 this->SetStartOutputDirectory(cwd.c_str());
727 return;
730 // We didn't find a CMakeLists.txt or CMakeCache.txt file from the
731 // argument. Assume it is the path to the source tree, and use the
732 // current working directory as the build tree.
733 std::string full = cmSystemTools::CollapseFullPath(arg);
734 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
735 this->SetHomeDirectory(full.c_str());
736 this->SetStartDirectory(full.c_str());
737 this->SetHomeOutputDirectory(cwd.c_str());
738 this->SetStartOutputDirectory(cwd.c_str());
741 // at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the
742 // cache
743 int cmake::AddCMakePaths()
745 // Find the cmake executable
746 std::string cMakeSelf = cmSystemTools::GetExecutableDirectory();
747 cMakeSelf += "/cmake";
748 cMakeSelf += cmSystemTools::GetExecutableExtension();
749 if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
751 cmSystemTools::Error("CMake executable cannot be found at ",
752 cMakeSelf.c_str());
753 return 0;
755 // Save the value in the cache
756 this->CacheManager->AddCacheEntry
757 ("CMAKE_COMMAND",cMakeSelf.c_str(), "Path to CMake executable.",
758 cmCacheManager::INTERNAL);
760 // Find and save the command to edit the cache
761 std::string editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
762 "/ccmake" + cmSystemTools::GetFilenameExtension(cMakeSelf);
763 if( !cmSystemTools::FileExists(editCacheCommand.c_str()))
765 editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
766 "/CMakeSetup" + cmSystemTools::GetFilenameExtension(cMakeSelf);
768 if(cmSystemTools::FileExists(editCacheCommand.c_str()))
770 this->CacheManager->AddCacheEntry
771 ("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
772 "Path to cache edit program executable.", cmCacheManager::INTERNAL);
774 std::string ctestCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
775 "/ctest" + cmSystemTools::GetFilenameExtension(cMakeSelf);
776 if(cmSystemTools::FileExists(ctestCommand.c_str()))
778 this->CacheManager->AddCacheEntry
779 ("CMAKE_CTEST_COMMAND", ctestCommand.c_str(),
780 "Path to ctest program executable.", cmCacheManager::INTERNAL);
782 std::string cpackCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
783 "/cpack" + cmSystemTools::GetFilenameExtension(cMakeSelf);
784 if(cmSystemTools::FileExists(ctestCommand.c_str()))
786 this->CacheManager->AddCacheEntry
787 ("CMAKE_CPACK_COMMAND", cpackCommand.c_str(),
788 "Path to cpack program executable.", cmCacheManager::INTERNAL);
791 // do CMAKE_ROOT, look for the environment variable first
792 std::string cMakeRoot;
793 std::string modules;
794 if (getenv("CMAKE_ROOT"))
796 cMakeRoot = getenv("CMAKE_ROOT");
797 modules = cMakeRoot + "/Modules/CMake.cmake";
799 if(!cmSystemTools::FileExists(modules.c_str()))
801 // next try exe/..
802 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
803 std::string::size_type slashPos = cMakeRoot.rfind("/");
804 if(slashPos != std::string::npos)
806 cMakeRoot = cMakeRoot.substr(0, slashPos);
808 // is there no Modules direcory there?
809 modules = cMakeRoot + "/Modules/CMake.cmake";
812 if (!cmSystemTools::FileExists(modules.c_str()))
814 // try exe/../share/cmake
815 cMakeRoot += CMAKE_DATA_DIR;
816 modules = cMakeRoot + "/Modules/CMake.cmake";
818 #ifdef CMAKE_ROOT_DIR
819 if (!cmSystemTools::FileExists(modules.c_str()))
821 // try compiled in root directory
822 cMakeRoot = CMAKE_ROOT_DIR;
823 modules = cMakeRoot + "/Modules/CMake.cmake";
825 #endif
826 #ifdef CMAKE_PREFIX
827 if (!cmSystemTools::FileExists(modules.c_str()))
829 // try compiled in install prefix
830 cMakeRoot = CMAKE_PREFIX CMAKE_DATA_DIR;
831 modules = cMakeRoot + "/Modules/CMake.cmake";
833 #endif
834 if (!cmSystemTools::FileExists(modules.c_str()))
836 // try
837 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
838 cMakeRoot += CMAKE_DATA_DIR;
839 modules = cMakeRoot + "/Modules/CMake.cmake";
841 if(!cmSystemTools::FileExists(modules.c_str()))
843 // next try exe
844 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
845 // is there no Modules direcory there?
846 modules = cMakeRoot + "/Modules/CMake.cmake";
848 if (!cmSystemTools::FileExists(modules.c_str()))
850 // couldn't find modules
851 cmSystemTools::Error("Could not find CMAKE_ROOT !!!\n"
852 "CMake has most likely not been installed correctly.\n"
853 "Modules directory not found in\n",
854 cMakeRoot.c_str());
855 return 0;
857 this->CacheManager->AddCacheEntry
858 ("CMAKE_ROOT", cMakeRoot.c_str(),
859 "Path to CMake installation.", cmCacheManager::INTERNAL);
861 #ifdef _WIN32
862 std::string comspec = "cmw9xcom.exe";
863 cmSystemTools::SetWindows9xComspecSubstitute(comspec.c_str());
864 #endif
865 return 1;
870 void CMakeCommandUsage(const char* program)
872 cmOStringStream errorStream;
874 #ifdef CMAKE_BUILD_WITH_CMAKE
875 errorStream
876 << "cmake version " << cmVersion::GetCMakeVersion() << "\n";
877 #else
878 errorStream
879 << "cmake bootstrap\n";
880 #endif
882 errorStream
883 << "Usage: " << program << " -E [command] [arguments ...]\n"
884 << "Available commands: \n"
885 << " chdir dir cmd [args]... - run command in a given directory\n"
886 << " copy file destination - copy file to destination (either file "
887 "or directory)\n"
888 << " copy_if_different in-file out-file - copy file if input has "
889 "changed\n"
890 << " copy_directory source destination - copy directory 'source' "
891 "content to directory 'destination'\n"
892 << " compare_files file1 file2 - check if file1 is same as file2\n"
893 << " echo [string]... - displays arguments as text\n"
894 << " echo_append [string]... - displays arguments as text but no new "
895 "line\n"
896 << " environment - display the current enviroment\n"
897 << " make_directory dir - create a directory\n"
898 << " md5sum file1 [...] - compute md5sum of files\n"
899 << " remove_directory dir - remove a directory and its contents\n"
900 << " remove [-f] file1 file2 ... - remove the file(s), use -f to force "
901 "it\n"
902 << " tar [cxt][vfz] file.tar file/dir1 file/dir2 ... - create a tar "
903 "archive\n"
904 << " time command [args] ... - run command and return elapsed time\n"
905 << " touch file - touch a file.\n"
906 << " touch_nocreate file - touch a file but do not create it.\n"
907 #if defined(_WIN32) && !defined(__CYGWIN__)
908 << " write_regv key value - write registry value\n"
909 << " delete_regv key - delete registry value\n"
910 << " comspec - on windows 9x use this for RunCommand\n"
911 #else
912 << " create_symlink old new - create a symbolic link new -> old\n"
913 #endif
916 cmSystemTools::Error(errorStream.str().c_str());
919 int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
921 if (args.size() > 1)
923 // Copy file
924 if (args[1] == "copy" && args.size() == 4)
926 if(!cmSystemTools::cmCopyFile(args[2].c_str(), args[3].c_str()))
928 std::cerr << "Error copying file \"" << args[2].c_str()
929 << "\" to \"" << args[3].c_str() << "\".\n";
930 return 1;
932 return 0;
935 // Copy file if different.
936 if (args[1] == "copy_if_different" && args.size() == 4)
938 if(!cmSystemTools::CopyFileIfDifferent(args[2].c_str(),
939 args[3].c_str()))
941 std::cerr << "Error copying file (if different) from \""
942 << args[2].c_str() << "\" to \"" << args[3].c_str()
943 << "\".\n";
944 return 1;
946 return 0;
949 // Copy directory content
950 if (args[1] == "copy_directory" && args.size() == 4)
952 if(!cmSystemTools::CopyADirectory(args[2].c_str(), args[3].c_str()))
954 std::cerr << "Error copying directory from \""
955 << args[2].c_str() << "\" to \"" << args[3].c_str()
956 << "\".\n";
957 return 1;
959 return 0;
962 // Compare files
963 if (args[1] == "compare_files" && args.size() == 4)
965 if(cmSystemTools::FilesDiffer(args[2].c_str(), args[3].c_str()))
967 std::cerr << "Files \""
968 << args[2].c_str() << "\" to \"" << args[3].c_str()
969 << "\" are different.\n";
970 return 1;
972 return 0;
975 // Echo string
976 else if (args[1] == "echo" )
978 unsigned int cc;
979 const char* space = "";
980 for ( cc = 2; cc < args.size(); cc ++ )
982 std::cout << space << args[cc];
983 space = " ";
985 std::cout << std::endl;
986 return 0;
989 // Echo string no new line
990 else if (args[1] == "echo_append" )
992 unsigned int cc;
993 const char* space = "";
994 for ( cc = 2; cc < args.size(); cc ++ )
996 std::cout << space << args[cc];
997 space = " ";
999 return 0;
1002 #if defined(CMAKE_BUILD_WITH_CMAKE)
1003 // Command to create a symbolic link. Fails on platforms not
1004 // supporting them.
1005 else if (args[1] == "environment" )
1007 std::vector<std::string> env = cmSystemTools::GetEnvironmentVariables();
1008 std::vector<std::string>::iterator it;
1009 for ( it = env.begin(); it != env.end(); ++ it )
1011 std::cout << it->c_str() << std::endl;
1013 return 0;
1015 #endif
1017 else if (args[1] == "make_directory" && args.size() == 3)
1019 if(!cmSystemTools::MakeDirectory(args[2].c_str()))
1021 std::cerr << "Error making directory \"" << args[2].c_str()
1022 << "\".\n";
1023 return 1;
1025 return 0;
1028 else if (args[1] == "remove_directory" && args.size() == 3)
1030 if(cmSystemTools::FileIsDirectory(args[2].c_str()) &&
1031 !cmSystemTools::RemoveADirectory(args[2].c_str()))
1033 std::cerr << "Error removing directory \"" << args[2].c_str()
1034 << "\".\n";
1035 return 1;
1037 return 0;
1040 // Remove file
1041 else if (args[1] == "remove" && args.size() > 2)
1043 bool force = false;
1044 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1046 if(args[cc] == "\\-f" || args[cc] == "-f")
1048 force = true;
1050 else
1052 // Complain if the file could not be removed, still exists,
1053 // and the -f option was not given.
1054 if(!cmSystemTools::RemoveFile(args[cc].c_str()) && !force &&
1055 cmSystemTools::FileExists(args[cc].c_str()))
1057 return 1;
1061 return 0;
1063 // Touch file
1064 else if (args[1] == "touch" && args.size() > 2)
1066 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1068 // Complain if the file could not be removed, still exists,
1069 // and the -f option was not given.
1070 if(!cmSystemTools::Touch(args[cc].c_str(), true))
1072 return 1;
1075 return 0;
1077 // Touch file
1078 else if (args[1] == "touch_nocreate" && args.size() > 2)
1080 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1082 // Complain if the file could not be removed, still exists,
1083 // and the -f option was not given.
1084 if(!cmSystemTools::Touch(args[cc].c_str(), false))
1086 return 1;
1089 return 0;
1092 // Clock command
1093 else if (args[1] == "time" && args.size() > 2)
1095 std::string command = args[2];
1096 for (std::string::size_type cc = 3; cc < args.size(); cc ++)
1098 command += " ";
1099 command += args[cc];
1102 clock_t clock_start, clock_finish;
1103 time_t time_start, time_finish;
1105 time(&time_start);
1106 clock_start = clock();
1108 cmSystemTools::RunSingleCommand(command.c_str());
1110 clock_finish = clock();
1111 time(&time_finish);
1113 double clocks_per_sec = static_cast<double>(CLOCKS_PER_SEC);
1114 std::cout << "Elapsed time: "
1115 << static_cast<long>(time_finish - time_start) << " s. (time)"
1116 << ", "
1117 << static_cast<double>(clock_finish - clock_start) / clocks_per_sec
1118 << " s. (clock)"
1119 << "\n";
1120 return 0;
1123 // Command to calculate the md5sum of a file
1124 else if (args[1] == "md5sum" && args.size() >= 3)
1126 char md5out[32];
1127 int retval = 0;
1128 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1130 const char *filename = args[cc].c_str();
1131 // Cannot compute md5sum of a directory
1132 if(cmSystemTools::FileIsDirectory(filename))
1134 std::cerr << "Error: " << filename << " is a directory" << std::endl;
1135 retval++;
1137 else if(!cmSystemTools::ComputeFileMD5(filename, md5out))
1139 // To mimic md5sum behavior in a shell:
1140 std::cerr << filename << ": No such file or directory" << std::endl;
1141 retval++;
1143 else
1145 std::cout << std::string(md5out,32) << " " << filename << std::endl;
1148 return retval;
1151 // Command to change directory and run a program.
1152 else if (args[1] == "chdir" && args.size() >= 4)
1154 std::string directory = args[2];
1155 if(!cmSystemTools::FileExists(directory.c_str()))
1157 cmSystemTools::Error("Directory does not exist for chdir command: ",
1158 args[2].c_str());
1159 return 0;
1162 std::string command = "\"";
1163 command += args[3];
1164 command += "\"";
1165 for (std::string::size_type cc = 4; cc < args.size(); cc ++)
1167 command += " \"";
1168 command += args[cc];
1169 command += "\"";
1171 int retval = 0;
1172 int timeout = 0;
1173 if ( cmSystemTools::RunSingleCommand(command.c_str(), 0, &retval,
1174 directory.c_str(), true, timeout) )
1176 return retval;
1179 return 1;
1182 // Command to start progress for a build
1183 else if (args[1] == "cmake_progress_start" && args.size() == 4)
1185 // bascially remove the directory
1186 std::string dirName = args[2];
1187 dirName += "/Progress";
1188 cmSystemTools::RemoveADirectory(dirName.c_str());
1190 // is the last argument a filename that exists?
1191 FILE *countFile = fopen(args[3].c_str(),"r");
1192 int count;
1193 if (countFile)
1195 fscanf(countFile,"%i",&count);
1196 fclose(countFile);
1198 else
1200 count = atoi(args[3].c_str());
1202 if (count)
1204 cmSystemTools::MakeDirectory(dirName.c_str());
1205 // write the count into the directory
1206 std::string fName = dirName;
1207 fName += "/count.txt";
1208 FILE *progFile = fopen(fName.c_str(),"w");
1209 if (progFile)
1211 fprintf(progFile,"%i\n",count);
1212 fclose(progFile);
1215 return 0;
1218 // Command to report progress for a build
1219 else if (args[1] == "cmake_progress_report" && args.size() >= 3)
1221 std::string dirName = args[2];
1222 dirName += "/Progress";
1223 std::string fName;
1224 FILE *progFile;
1226 // read the count
1227 fName = dirName;
1228 fName += "/count.txt";
1229 progFile = fopen(fName.c_str(),"r");
1230 int count = 0;
1231 if (!progFile)
1233 return 0;
1235 else
1237 fscanf(progFile,"%i",&count);
1238 fclose(progFile);
1240 unsigned int i;
1241 for (i = 3; i < args.size(); ++i)
1243 fName = dirName;
1244 fName += "/";
1245 fName += args[i];
1246 progFile = fopen(fName.c_str(),"w");
1247 if (progFile)
1249 fprintf(progFile,"empty");
1250 fclose(progFile);
1253 int fileNum = static_cast<int>
1254 (cmsys::Directory::GetNumberOfFilesInDirectory(dirName.c_str()));
1255 if (count > 0)
1257 // print the progress
1258 fprintf(stdout,"[%3i%%] ",((fileNum-3)*100)/count);
1260 return 0;
1263 // Command to create a symbolic link. Fails on platforms not
1264 // supporting them.
1265 else if (args[1] == "create_symlink" && args.size() == 4)
1267 const char* destinationFileName = args[3].c_str();
1268 if ( cmSystemTools::FileExists(destinationFileName) )
1270 if ( cmSystemTools::FileIsSymlink(destinationFileName) )
1272 if ( !cmSystemTools::RemoveFile(destinationFileName) ||
1273 cmSystemTools::FileExists(destinationFileName) )
1275 return 0;
1278 else
1280 return 0;
1283 return cmSystemTools::CreateSymlink(args[2].c_str(),
1284 args[3].c_str())? 0:1;
1287 // Internal CMake shared library support.
1288 else if (args[1] == "cmake_symlink_library" && args.size() == 5)
1290 int result = 0;
1291 std::string realName = args[2];
1292 std::string soName = args[3];
1293 std::string name = args[4];
1294 if(soName != realName)
1296 std::string fname = cmSystemTools::GetFilenameName(realName);
1297 if(cmSystemTools::FileExists(soName.c_str()))
1299 cmSystemTools::RemoveFile(soName.c_str());
1301 if(!cmSystemTools::CreateSymlink(fname.c_str(), soName.c_str()))
1303 result = 1;
1306 if(name != soName)
1308 std::string fname = cmSystemTools::GetFilenameName(soName);
1309 if(cmSystemTools::FileExists(soName.c_str()))
1311 cmSystemTools::RemoveFile(name.c_str());
1313 if(!cmSystemTools::CreateSymlink(fname.c_str(), name.c_str()))
1315 result = 1;
1318 return result;
1320 // Internal CMake versioned executable support.
1321 else if (args[1] == "cmake_symlink_executable" && args.size() == 4)
1323 int result = 0;
1324 std::string realName = args[2];
1325 std::string name = args[3];
1326 if(name != realName)
1328 std::string fname = cmSystemTools::GetFilenameName(realName);
1329 if(cmSystemTools::FileExists(realName.c_str()))
1331 cmSystemTools::RemoveFile(name.c_str());
1333 if(!cmSystemTools::CreateSymlink(fname.c_str(), name.c_str()))
1335 result = 1;
1338 return result;
1341 #if defined(CMAKE_HAVE_VS_GENERATORS)
1342 // Internal CMake support for calling Visual Studio macros.
1343 else if (args[1] == "cmake_call_visual_studio_macro" && args.size() >= 4)
1345 // args[2] = full path to .sln file or "ALL"
1346 // args[3] = name of Visual Studio macro to call
1347 // args[4..args.size()-1] = [optional] args for Visual Studio macro
1349 std::string macroArgs;
1351 if (args.size() > 4)
1353 macroArgs = args[4];
1355 for (size_t i = 5; i < args.size(); ++i)
1357 macroArgs += " ";
1358 macroArgs += args[i];
1362 return cmCallVisualStudioMacro::CallMacro(args[2], args[3], macroArgs);
1364 #endif
1366 // Internal CMake dependency scanning support.
1367 else if (args[1] == "cmake_depends" && args.size() >= 6)
1369 // Use the make system's VERBOSE environment variable to enable
1370 // verbose output.
1371 bool verbose = cmSystemTools::GetEnv("VERBOSE") != 0;
1373 // Create a cmake object instance to process dependencies.
1374 cmake cm;
1375 std::string gen;
1376 std::string homeDir;
1377 std::string startDir;
1378 std::string homeOutDir;
1379 std::string startOutDir;
1380 std::string depInfo;
1381 bool color = true;
1382 if(args.size() >= 8)
1384 // Full signature:
1386 // -E cmake_depends <generator>
1387 // <home-src-dir> <start-src-dir>
1388 // <home-out-dir> <start-out-dir>
1389 // <dep-info> [--color=$(COLOR)]
1391 // All paths are provided.
1392 gen = args[2];
1393 homeDir = args[3];
1394 startDir = args[4];
1395 homeOutDir = args[5];
1396 startOutDir = args[6];
1397 depInfo = args[7];
1398 if(args.size() >= 9 &&
1399 args[8].length() > 8 &&
1400 args[8].substr(0, 8) == "--color=")
1402 // Enable or disable color based on the switch value.
1403 color = cmSystemTools::IsOn(args[8].substr(8).c_str());
1406 else
1408 // Support older signature for existing makefiles:
1410 // -E cmake_depends <generator>
1411 // <home-out-dir> <start-out-dir>
1412 // <dep-info>
1414 // Just pretend the source directories are the same as the
1415 // binary directories so at least scanning will work.
1416 gen = args[2];
1417 homeDir = args[3];
1418 startDir = args[4];
1419 homeOutDir = args[3];
1420 startOutDir = args[3];
1421 depInfo = args[5];
1424 // Create a local generator configured for the directory in
1425 // which dependencies will be scanned.
1426 homeDir = cmSystemTools::CollapseFullPath(homeDir.c_str());
1427 startDir = cmSystemTools::CollapseFullPath(startDir.c_str());
1428 homeOutDir = cmSystemTools::CollapseFullPath(homeOutDir.c_str());
1429 startOutDir = cmSystemTools::CollapseFullPath(startOutDir.c_str());
1430 cm.SetHomeDirectory(homeDir.c_str());
1431 cm.SetStartDirectory(startDir.c_str());
1432 cm.SetHomeOutputDirectory(homeOutDir.c_str());
1433 cm.SetStartOutputDirectory(startOutDir.c_str());
1434 if(cmGlobalGenerator* ggd = cm.CreateGlobalGenerator(gen.c_str()))
1436 cm.SetGlobalGenerator(ggd);
1437 std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
1438 lgd->SetGlobalGenerator(ggd);
1439 lgd->GetMakefile()->SetStartDirectory(startDir.c_str());
1440 lgd->GetMakefile()->SetStartOutputDirectory(startOutDir.c_str());
1441 lgd->GetMakefile()->MakeStartDirectoriesCurrent();
1443 // Actually scan dependencies.
1444 return lgd->UpdateDependencies(depInfo.c_str(),
1445 verbose, color)? 0 : 2;
1447 return 1;
1450 // Internal CMake link script support.
1451 else if (args[1] == "cmake_link_script" && args.size() >= 3)
1453 return cmake::ExecuteLinkScript(args);
1456 // Internal CMake unimplemented feature notification.
1457 else if (args[1] == "cmake_unimplemented_variable")
1459 std::cerr << "Feature not implemented for this platform.";
1460 if(args.size() == 3)
1462 std::cerr << " Variable " << args[2] << " is not set.";
1464 std::cerr << std::endl;
1465 return 1;
1467 else if (args[1] == "vs_link_exe")
1469 return cmake::VisualStudioLink(args, 1);
1471 else if (args[1] == "vs_link_dll")
1473 return cmake::VisualStudioLink(args, 2);
1475 #ifdef CMAKE_BUILD_WITH_CMAKE
1476 // Internal CMake color makefile support.
1477 else if (args[1] == "cmake_echo_color")
1479 return cmake::ExecuteEchoColor(args);
1481 #endif
1483 // Tar files
1484 else if (args[1] == "tar" && args.size() > 3)
1486 std::string flags = args[2];
1487 std::string outFile = args[3];
1488 std::vector<cmStdString> files;
1489 for (std::string::size_type cc = 4; cc < args.size(); cc ++)
1491 files.push_back(args[cc]);
1493 bool gzip = false;
1494 bool verbose = false;
1495 if ( flags.find_first_of('z') != flags.npos )
1497 gzip = true;
1499 if ( flags.find_first_of('v') != flags.npos )
1501 verbose = true;
1504 if ( flags.find_first_of('t') != flags.npos )
1506 if ( !cmSystemTools::ListTar(outFile.c_str(), files, gzip, verbose) )
1508 cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
1509 return 1;
1512 else if ( flags.find_first_of('c') != flags.npos )
1514 if ( !cmSystemTools::CreateTar(
1515 outFile.c_str(), files, gzip, verbose) )
1517 cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
1518 return 1;
1521 else if ( flags.find_first_of('x') != flags.npos )
1523 if ( !cmSystemTools::ExtractTar(
1524 outFile.c_str(), files, gzip, verbose) )
1526 cmSystemTools::Error("Problem extracting tar: ", outFile.c_str());
1527 return 1;
1530 return 0;
1533 #if defined(CMAKE_BUILD_WITH_CMAKE)
1534 // Internal CMake Fortran module support.
1535 else if (args[1] == "cmake_copy_f90_mod" && args.size() >= 4)
1537 return cmDependsFortran::CopyModule(args)? 0 : 1;
1539 #endif
1541 #if defined(_WIN32) && !defined(__CYGWIN__)
1542 // Write registry value
1543 else if (args[1] == "write_regv" && args.size() > 3)
1545 return cmSystemTools::WriteRegistryValue(args[2].c_str(),
1546 args[3].c_str()) ? 0 : 1;
1549 // Delete registry value
1550 else if (args[1] == "delete_regv" && args.size() > 2)
1552 return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
1554 // Remove file
1555 else if (args[1] == "comspec" && args.size() > 2)
1557 unsigned int cc;
1558 std::string command = args[2];
1559 for ( cc = 3; cc < args.size(); cc ++ )
1561 command += " " + args[cc];
1563 return cmWin32ProcessExecution::Windows9xHack(command.c_str());
1565 #endif
1568 ::CMakeCommandUsage(args[0].c_str());
1569 return 1;
1572 void cmake::AddExtraGenerator(const char* name,
1573 CreateExtraGeneratorFunctionType newFunction)
1575 cmExternalMakefileProjectGenerator* extraGenerator = newFunction();
1576 const std::vector<std::string>& supportedGlobalGenerators =
1577 extraGenerator->GetSupportedGlobalGenerators();
1579 for(std::vector<std::string>::const_iterator
1580 it = supportedGlobalGenerators.begin();
1581 it != supportedGlobalGenerators.end();
1582 ++it )
1584 std::string fullName = cmExternalMakefileProjectGenerator::
1585 CreateFullGeneratorName(it->c_str(), name);
1586 this->ExtraGenerators[fullName.c_str()] = newFunction;
1588 delete extraGenerator;
1591 void cmake::AddDefaultExtraGenerators()
1593 #if defined(CMAKE_BUILD_WITH_CMAKE)
1594 #if defined(_WIN32) && !defined(__CYGWIN__)
1595 // e.g. kdevelop4 ?
1596 #endif
1598 #if !defined(__CYGWIN__)
1599 this->AddExtraGenerator(cmExtraCodeBlocksGenerator::GetActualName(),
1600 &cmExtraCodeBlocksGenerator::New);
1601 #endif
1603 #ifdef CMAKE_USE_ECLIPSE
1604 this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(),
1605 &cmExtraEclipseCDT4Generator::New);
1606 #endif
1608 #ifdef CMAKE_USE_KDEVELOP
1609 this->AddExtraGenerator(cmGlobalKdevelopGenerator::GetActualName(),
1610 &cmGlobalKdevelopGenerator::New);
1611 // for kdevelop also add the generator with just the name of the
1612 // extra generator, since it was this way since cmake 2.2
1613 this->ExtraGenerators[cmGlobalKdevelopGenerator::GetActualName()]
1614 = &cmGlobalKdevelopGenerator::New;
1615 #endif
1617 #endif
1621 //----------------------------------------------------------------------------
1622 void cmake::GetRegisteredGenerators(std::vector<std::string>& names)
1624 for(RegisteredGeneratorsMap::const_iterator i = this->Generators.begin();
1625 i != this->Generators.end(); ++i)
1627 names.push_back(i->first);
1629 for(RegisteredExtraGeneratorsMap::const_iterator
1630 i = this->ExtraGenerators.begin();
1631 i != this->ExtraGenerators.end(); ++i)
1633 names.push_back(i->first);
1637 cmGlobalGenerator* cmake::CreateGlobalGenerator(const char* name)
1639 cmGlobalGenerator* generator = 0;
1640 cmExternalMakefileProjectGenerator* extraGenerator = 0;
1641 RegisteredGeneratorsMap::const_iterator genIt = this->Generators.find(name);
1642 if(genIt == this->Generators.end())
1644 RegisteredExtraGeneratorsMap::const_iterator extraGenIt =
1645 this->ExtraGenerators.find(name);
1646 if (extraGenIt == this->ExtraGenerators.end())
1648 return 0;
1650 extraGenerator = (extraGenIt->second)();
1651 genIt=this->Generators.find(extraGenerator->GetGlobalGeneratorName(name));
1652 if(genIt == this->Generators.end())
1654 delete extraGenerator;
1655 return 0;
1659 generator = (genIt->second)();
1660 generator->SetCMakeInstance(this);
1661 generator->SetExternalMakefileProjectGenerator(extraGenerator);
1662 return generator;
1665 void cmake::SetHomeDirectory(const char* dir)
1667 this->cmHomeDirectory = dir;
1668 cmSystemTools::ConvertToUnixSlashes(this->cmHomeDirectory);
1671 void cmake::SetHomeOutputDirectory(const char* lib)
1673 this->HomeOutputDirectory = lib;
1674 cmSystemTools::ConvertToUnixSlashes(this->HomeOutputDirectory);
1677 void cmake::SetGlobalGenerator(cmGlobalGenerator *gg)
1679 if(!gg)
1681 cmSystemTools::Error("Error SetGlobalGenerator called with null");
1682 return;
1684 // delete the old generator
1685 if (this->GlobalGenerator)
1687 delete this->GlobalGenerator;
1688 // restore the original environment variables CXX and CC
1689 // Restor CC
1690 std::string env = "CC=";
1691 if(this->CCEnvironment.size())
1693 env += this->CCEnvironment;
1695 cmSystemTools::PutEnv(env.c_str());
1696 env = "CXX=";
1697 if(this->CXXEnvironment.size())
1699 env += this->CXXEnvironment;
1701 cmSystemTools::PutEnv(env.c_str());
1704 // set the new
1705 this->GlobalGenerator = gg;
1707 // set the global flag for unix style paths on cmSystemTools as soon as
1708 // the generator is set. This allows gmake to be used on windows.
1709 cmSystemTools::SetForceUnixPaths
1710 (this->GlobalGenerator->GetForceUnixPaths());
1712 // Save the environment variables CXX and CC
1713 const char* cxx = getenv("CXX");
1714 const char* cc = getenv("CC");
1715 if(cxx)
1717 this->CXXEnvironment = cxx;
1719 else
1721 this->CXXEnvironment = "";
1723 if(cc)
1725 this->CCEnvironment = cc;
1727 else
1729 this->CCEnvironment = "";
1731 // set the cmake instance just to be sure
1732 gg->SetCMakeInstance(this);
1735 int cmake::DoPreConfigureChecks()
1737 // Make sure the Start directory contains a CMakeLists.txt file.
1738 std::string srcList = this->GetHomeDirectory();
1739 srcList += "/CMakeLists.txt";
1740 if(!cmSystemTools::FileExists(srcList.c_str()))
1742 cmOStringStream err;
1743 if(cmSystemTools::FileIsDirectory(this->GetHomeDirectory()))
1745 err << "The source directory \"" << this->GetHomeDirectory()
1746 << "\" does not appear to contain CMakeLists.txt.\n";
1748 else if(cmSystemTools::FileExists(this->GetHomeDirectory()))
1750 err << "The source directory \"" << this->GetHomeDirectory()
1751 << "\" is a file, not a directory.\n";
1753 else
1755 err << "The source directory \"" << this->GetHomeDirectory()
1756 << "\" does not exist.\n";
1758 err << "Specify --help for usage, or press the help button on the CMake "
1759 "GUI.";
1760 cmSystemTools::Error(err.str().c_str());
1761 return -2;
1764 // do a sanity check on some values
1765 if(this->CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY"))
1767 std::string cacheStart =
1768 this->CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY");
1769 cacheStart += "/CMakeLists.txt";
1770 std::string currentStart = this->GetHomeDirectory();
1771 currentStart += "/CMakeLists.txt";
1772 if(!cmSystemTools::SameFile(cacheStart.c_str(), currentStart.c_str()))
1774 std::string message = "The source \"";
1775 message += currentStart;
1776 message += "\" does not match the source \"";
1777 message += cacheStart;
1778 message += "\" used to generate cache. ";
1779 message += "Re-run cmake with a different source directory.";
1780 cmSystemTools::Error(message.c_str());
1781 return -2;
1784 else
1786 return 0;
1788 return 1;
1790 struct SaveCacheEntry
1792 std::string key;
1793 std::string value;
1794 std::string help;
1795 cmCacheManager::CacheEntryType type;
1798 int cmake::HandleDeleteCacheVariables(const char* var)
1800 std::vector<std::string> argsSplit;
1801 cmSystemTools::ExpandListArgument(std::string(var), argsSplit);
1802 // erase the property to avoid infinite recursion
1803 this->SetProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", "");
1805 cmCacheManager::CacheIterator ci = this->CacheManager->NewIterator();
1806 std::vector<SaveCacheEntry> saved;
1807 cmOStringStream warning;
1808 warning
1809 << "You have changed variables that require your cache to be deleted.\n"
1810 << "Configure will be re-run and you may have to reset some variables.\n"
1811 << "The following variables have changed:\n";
1812 for(std::vector<std::string>::iterator i = argsSplit.begin();
1813 i != argsSplit.end(); ++i)
1815 SaveCacheEntry save;
1816 save.key = *i;
1817 warning << *i << "= ";
1818 i++;
1819 save.value = *i;
1820 warning << *i << "\n";
1821 if(ci.Find(save.key.c_str()))
1823 save.type = ci.GetType();
1824 save.help = ci.GetProperty("HELPSTRING");
1826 saved.push_back(save);
1829 // remove the cache
1830 this->CacheManager->DeleteCache(this->GetStartOutputDirectory());
1831 // load the empty cache
1832 this->LoadCache();
1833 // restore the changed compilers
1834 for(std::vector<SaveCacheEntry>::iterator i = saved.begin();
1835 i != saved.end(); ++i)
1837 this->AddCacheEntry(i->key.c_str(), i->value.c_str(),
1838 i->help.c_str(), i->type);
1840 cmSystemTools::Message(warning.str().c_str());
1841 // avoid reconfigure if there were errors
1842 if(!cmSystemTools::GetErrorOccuredFlag())
1844 // re-run configure
1845 return this->Configure();
1847 return 0;
1850 int cmake::Configure()
1852 int ret = this->ActualConfigure();
1853 const char* delCacheVars =
1854 this->GetProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_");
1855 if(delCacheVars && delCacheVars[0] != 0)
1857 return this->HandleDeleteCacheVariables(delCacheVars);
1859 return ret;
1863 int cmake::ActualConfigure()
1865 // Construct right now our path conversion table before it's too late:
1866 this->UpdateConversionPathTable();
1867 this->CleanupCommandsAndMacros();
1869 int res = 0;
1870 if ( !this->ScriptMode )
1872 res = this->DoPreConfigureChecks();
1874 if ( res < 0 )
1876 return -2;
1878 if ( !res )
1880 this->CacheManager->AddCacheEntry
1881 ("CMAKE_HOME_DIRECTORY",
1882 this->GetHomeDirectory(),
1883 "Start directory with the top level CMakeLists.txt file for this "
1884 "project",
1885 cmCacheManager::INTERNAL);
1888 // set the default BACKWARDS compatibility to the current version
1889 if(!this->CacheManager->GetCacheValue("CMAKE_BACKWARDS_COMPATIBILITY"))
1891 char ver[256];
1892 sprintf(ver,"%i.%i",cmVersion::GetMajorVersion(),
1893 cmVersion::GetMinorVersion());
1894 this->CacheManager->AddCacheEntry
1895 ("CMAKE_BACKWARDS_COMPATIBILITY",ver,
1896 "For backwards compatibility, what version of CMake commands and "
1897 "syntax should this version of CMake allow.",
1898 cmCacheManager::STRING);
1901 // no generator specified on the command line
1902 if(!this->GlobalGenerator)
1904 const char* genName =
1905 this->CacheManager->GetCacheValue("CMAKE_GENERATOR");
1906 const char* extraGenName =
1907 this->CacheManager->GetCacheValue("CMAKE_EXTRA_GENERATOR");
1908 if(genName)
1910 std::string fullName = cmExternalMakefileProjectGenerator::
1911 CreateFullGeneratorName(genName, extraGenName);
1912 this->GlobalGenerator = this->CreateGlobalGenerator(fullName.c_str());
1914 if(this->GlobalGenerator)
1916 // set the global flag for unix style paths on cmSystemTools as
1917 // soon as the generator is set. This allows gmake to be used
1918 // on windows.
1919 cmSystemTools::SetForceUnixPaths
1920 (this->GlobalGenerator->GetForceUnixPaths());
1922 else
1924 #if defined(__BORLANDC__) && defined(_WIN32)
1925 this->SetGlobalGenerator(new cmGlobalBorlandMakefileGenerator);
1926 #elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
1927 std::string installedCompiler;
1928 std::string mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
1929 "\\VisualStudio\\8.0\\Setup;Dbghelp_path]";
1930 cmSystemTools::ExpandRegistryValues(mp);
1931 if (!(mp == "/registry"))
1933 installedCompiler = "Visual Studio 8 2005";
1935 else
1937 mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
1938 "\\VisualStudio\\7.1;InstallDir]";
1939 cmSystemTools::ExpandRegistryValues(mp);
1940 if (!(mp == "/registry"))
1942 installedCompiler = "Visual Studio 7 .NET 2003";
1944 else
1946 mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
1947 "\\VisualStudio\\7.0;InstallDir]";
1948 cmSystemTools::ExpandRegistryValues(mp);
1949 if (!(mp == "/registry"))
1951 installedCompiler = "Visual Studio 7";
1953 else
1955 installedCompiler = "Visual Studio 6";
1959 cmGlobalGenerator* gen
1960 = this->CreateGlobalGenerator(installedCompiler.c_str());
1961 if(!gen)
1963 gen = new cmGlobalNMakeMakefileGenerator;
1965 this->SetGlobalGenerator(gen);
1966 #else
1967 this->SetGlobalGenerator(new cmGlobalUnixMakefileGenerator3);
1968 #endif
1970 if(!this->GlobalGenerator)
1972 cmSystemTools::Error("Could not create generator");
1973 return -1;
1977 const char* genName = this->CacheManager->GetCacheValue("CMAKE_GENERATOR");
1978 if(genName)
1980 if(strcmp(this->GlobalGenerator->GetName(), genName) != 0)
1982 std::string message = "Error: generator : ";
1983 message += this->GlobalGenerator->GetName();
1984 message += "\nDoes not match the generator used previously: ";
1985 message += genName;
1986 message +=
1987 "\nEither remove the CMakeCache.txt file or choose a different"
1988 " binary directory.";
1989 cmSystemTools::Error(message.c_str());
1990 return -2;
1993 if(!this->CacheManager->GetCacheValue("CMAKE_GENERATOR"))
1995 this->CacheManager->AddCacheEntry("CMAKE_GENERATOR",
1996 this->GlobalGenerator->GetName(),
1997 "Name of generator.",
1998 cmCacheManager::INTERNAL);
1999 this->CacheManager->AddCacheEntry("CMAKE_EXTRA_GENERATOR",
2000 this->GlobalGenerator->GetExtraGeneratorName(),
2001 "Name of external makefile project generator.",
2002 cmCacheManager::INTERNAL);
2005 // reset any system configuration information, except for when we are
2006 // InTryCompile. With TryCompile the system info is taken from the parent's
2007 // info to save time
2008 if (!this->InTryCompile)
2010 this->GlobalGenerator->ClearEnabledLanguages();
2013 this->CleanupWrittenFiles();
2015 // Truncate log files
2016 if (!this->InTryCompile)
2018 this->TruncateOutputLog("CMakeOutput.log");
2019 this->TruncateOutputLog("CMakeError.log");
2022 // actually do the configure
2023 this->GlobalGenerator->Configure();
2024 // Before saving the cache
2025 // if the project did not define one of the entries below, add them now
2026 // so users can edit the values in the cache:
2027 // LIBRARY_OUTPUT_PATH
2028 // EXECUTABLE_OUTPUT_PATH
2029 if(!this->CacheManager->GetCacheValue("LIBRARY_OUTPUT_PATH"))
2031 this->CacheManager->AddCacheEntry
2032 ("LIBRARY_OUTPUT_PATH", "",
2033 "Single output directory for building all libraries.",
2034 cmCacheManager::PATH);
2036 if(!this->CacheManager->GetCacheValue("EXECUTABLE_OUTPUT_PATH"))
2038 this->CacheManager->AddCacheEntry
2039 ("EXECUTABLE_OUTPUT_PATH", "",
2040 "Single output directory for building all executables.",
2041 cmCacheManager::PATH);
2043 if(!this->CacheManager->GetCacheValue("CMAKE_USE_RELATIVE_PATHS"))
2045 this->CacheManager->AddCacheEntry
2046 ("CMAKE_USE_RELATIVE_PATHS", false,
2047 "If true, cmake will use relative paths in makefiles and projects.");
2048 cmCacheManager::CacheIterator it =
2049 this->CacheManager->GetCacheIterator("CMAKE_USE_RELATIVE_PATHS");
2050 if ( !it.PropertyExists("ADVANCED") )
2052 it.SetProperty("ADVANCED", "1");
2056 if(cmSystemTools::GetFatalErrorOccured() &&
2057 (!this->CacheManager->GetCacheValue("CMAKE_MAKE_PROGRAM") ||
2058 cmSystemTools::IsOff(this->CacheManager->
2059 GetCacheValue("CMAKE_MAKE_PROGRAM"))))
2061 // We must have a bad generator selection. Wipe the cache entry so the
2062 // user can select another.
2063 this->CacheManager->RemoveCacheEntry("CMAKE_GENERATOR");
2064 this->CacheManager->RemoveCacheEntry("CMAKE_EXTRA_GENERATOR");
2066 // only save the cache if there were no fatal errors
2067 if ( !this->ScriptMode )
2069 this->CacheManager->SaveCache(this->GetHomeOutputDirectory());
2071 if ( !this->GraphVizFile.empty() )
2073 std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
2074 this->GenerateGraphViz(this->GraphVizFile.c_str());
2076 if(cmSystemTools::GetErrorOccuredFlag())
2078 return -1;
2080 return 0;
2083 bool cmake::CacheVersionMatches()
2085 const char* majv =
2086 this->CacheManager->GetCacheValue("CMAKE_CACHE_MAJOR_VERSION");
2087 const char* minv =
2088 this->CacheManager->GetCacheValue("CMAKE_CACHE_MINOR_VERSION");
2089 const char* relv =
2090 this->CacheManager->GetCacheValue("CMAKE_CACHE_RELEASE_VERSION");
2091 bool cacheSameCMake = false;
2092 if(majv &&
2093 atoi(majv) == static_cast<int>(cmVersion::GetMajorVersion())
2094 && minv &&
2095 atoi(minv) == static_cast<int>(cmVersion::GetMinorVersion())
2096 && relv && (strcmp(relv, cmVersion::GetReleaseVersion().c_str()) == 0))
2098 cacheSameCMake = true;
2100 return cacheSameCMake;
2103 void cmake::PreLoadCMakeFiles()
2105 std::string pre_load = this->GetHomeDirectory();
2106 if ( pre_load.size() > 0 )
2108 pre_load += "/PreLoad.cmake";
2109 if ( cmSystemTools::FileExists(pre_load.c_str()) )
2111 this->ReadListFile(pre_load.c_str());
2114 pre_load = this->GetHomeOutputDirectory();
2115 if ( pre_load.size() > 0 )
2117 pre_load += "/PreLoad.cmake";
2118 if ( cmSystemTools::FileExists(pre_load.c_str()) )
2120 this->ReadListFile(pre_load.c_str());
2125 // handle a command line invocation
2126 int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
2128 // Process the arguments
2129 this->SetArgs(args);
2130 if(cmSystemTools::GetErrorOccuredFlag())
2132 return -1;
2135 // If we are given a stamp file check if it is really out of date.
2136 if(!this->CheckStampFile.empty() &&
2137 cmakeCheckStampFile(this->CheckStampFile.c_str()))
2139 return 0;
2142 // set the cmake command
2143 this->CMakeCommand = args[0];
2145 if ( !this->ScriptMode )
2147 // load the cache
2148 if(this->LoadCache() < 0)
2150 cmSystemTools::Error("Error executing cmake::LoadCache(). Aborting.\n");
2151 return -1;
2154 else
2156 this->AddCMakePaths();
2159 // Add any cache args
2160 if ( !this->SetCacheArgs(args) )
2162 cmSystemTools::Error("Problem processing arguments. Aborting.\n");
2163 return -1;
2166 // In script mode we terminate after running the script.
2167 if(this->ScriptMode)
2169 if(cmSystemTools::GetErrorOccuredFlag())
2171 return -1;
2173 else
2175 return 0;
2179 this->PreLoadCMakeFiles();
2181 std::string systemFile = this->GetHomeOutputDirectory();
2182 systemFile += "/CMakeSystem.cmake";
2184 if ( noconfigure )
2186 return 0;
2189 // now run the global generate
2190 // Check the state of the build system to see if we need to regenerate.
2191 if(!this->CheckBuildSystem())
2193 return 0;
2196 // If we are doing global generate, we better set start and start
2197 // output directory to the root of the project.
2198 std::string oldstartdir = this->GetStartDirectory();
2199 std::string oldstartoutputdir = this->GetStartOutputDirectory();
2200 this->SetStartDirectory(this->GetHomeDirectory());
2201 this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
2202 int ret = this->Configure();
2203 if (ret || this->ScriptMode)
2205 #if defined(CMAKE_HAVE_VS_GENERATORS)
2206 if(!this->VSSolutionFile.empty() && this->GlobalGenerator)
2208 // CMake is running to regenerate a Visual Studio build tree
2209 // during a build from the VS IDE. The build files cannot be
2210 // regenerated, so we should stop the build.
2211 cmSystemTools::Message(
2212 "CMake Configure step failed. "
2213 "Build files cannot be regenerated correctly. "
2214 "Attempting to stop IDE build.");
2215 cmGlobalVisualStudioGenerator* gg =
2216 static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
2217 gg->CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
2218 this->VSSolutionFile.c_str());
2220 #endif
2221 return ret;
2223 ret = this->Generate();
2224 std::string message = "Build files have been written to: ";
2225 message += this->GetHomeOutputDirectory();
2226 this->UpdateProgress(message.c_str(), -1);
2227 if(ret)
2229 return ret;
2231 this->SetStartDirectory(oldstartdir.c_str());
2232 this->SetStartOutputDirectory(oldstartoutputdir.c_str());
2234 return ret;
2237 int cmake::Generate()
2239 if(!this->GlobalGenerator)
2241 return -1;
2243 this->GlobalGenerator->Generate();
2244 if(cmSystemTools::GetErrorOccuredFlag())
2246 return -1;
2248 if (this->GetProperty("REPORT_UNDEFINED_PROPERTIES"))
2250 this->ReportUndefinedPropertyAccesses
2251 (this->GetProperty("REPORT_UNDEFINED_PROPERTIES"));
2253 return 0;
2256 void cmake::AddCacheEntry(const char* key, const char* value,
2257 const char* helpString,
2258 int type)
2260 this->CacheManager->AddCacheEntry(key, value,
2261 helpString,
2262 cmCacheManager::CacheEntryType(type));
2265 const char* cmake::GetCacheDefinition(const char* name) const
2267 return this->CacheManager->GetCacheValue(name);
2270 int cmake::DumpDocumentationToFile(std::ostream& f)
2272 #ifdef CMAKE_BUILD_WITH_CMAKE
2273 // Loop over all registered commands and print out documentation
2274 const char *name;
2275 const char *terse;
2276 const char *full;
2277 char tmp[1024];
2278 sprintf(tmp,"Version %d.%d (%s)", cmVersion::GetMajorVersion(),
2279 cmVersion::GetMinorVersion(),
2280 cmVersion::GetReleaseVersion().c_str());
2281 f << "<html>\n";
2282 f << "<h1>Documentation for commands of CMake " << tmp << "</h1>\n";
2283 f << "<ul>\n";
2284 for(RegisteredCommandsMap::iterator j = this->Commands.begin();
2285 j != this->Commands.end(); ++j)
2287 name = (*j).second->GetName();
2288 terse = (*j).second->GetTerseDocumentation();
2289 full = (*j).second->GetFullDocumentation();
2290 f << "<li><b>" << name << "</b> - " << terse << std::endl
2291 << "<br><i>Usage:</i> " << full << "</li>" << std::endl << std::endl;
2293 f << "</ul></html>\n";
2294 #else
2295 (void)f;
2296 #endif
2297 return 1;
2300 void cmake::AddDefaultCommands()
2302 std::list<cmCommand*> commands;
2303 GetBootstrapCommands(commands);
2304 GetPredefinedCommands(commands);
2305 for(std::list<cmCommand*>::iterator i = commands.begin();
2306 i != commands.end(); ++i)
2308 this->AddCommand(*i);
2312 void cmake::AddDefaultGenerators()
2314 #if defined(_WIN32) && !defined(__CYGWIN__)
2315 # if !defined(CMAKE_BOOT_MINGW)
2316 this->Generators[cmGlobalVisualStudio6Generator::GetActualName()] =
2317 &cmGlobalVisualStudio6Generator::New;
2318 this->Generators[cmGlobalVisualStudio7Generator::GetActualName()] =
2319 &cmGlobalVisualStudio7Generator::New;
2320 this->Generators[cmGlobalVisualStudio71Generator::GetActualName()] =
2321 &cmGlobalVisualStudio71Generator::New;
2322 this->Generators[cmGlobalVisualStudio8Generator::GetActualName()] =
2323 &cmGlobalVisualStudio8Generator::New;
2324 this->Generators[cmGlobalVisualStudio9Generator::GetActualName()] =
2325 &cmGlobalVisualStudio9Generator::New;
2326 this->Generators[cmGlobalVisualStudio9Win64Generator::GetActualName()] =
2327 &cmGlobalVisualStudio9Win64Generator::New;
2328 this->Generators[cmGlobalVisualStudio8Win64Generator::GetActualName()] =
2329 &cmGlobalVisualStudio8Win64Generator::New;
2330 this->Generators[cmGlobalBorlandMakefileGenerator::GetActualName()] =
2331 &cmGlobalBorlandMakefileGenerator::New;
2332 this->Generators[cmGlobalNMakeMakefileGenerator::GetActualName()] =
2333 &cmGlobalNMakeMakefileGenerator::New;
2334 this->Generators[cmGlobalWatcomWMakeGenerator::GetActualName()] =
2335 &cmGlobalWatcomWMakeGenerator::New;
2336 # endif
2337 this->Generators[cmGlobalMSYSMakefileGenerator::GetActualName()] =
2338 &cmGlobalMSYSMakefileGenerator::New;
2339 this->Generators[cmGlobalMinGWMakefileGenerator::GetActualName()] =
2340 &cmGlobalMinGWMakefileGenerator::New;
2341 #endif
2342 this->Generators[cmGlobalUnixMakefileGenerator3::GetActualName()] =
2343 &cmGlobalUnixMakefileGenerator3::New;
2344 #ifdef CMAKE_USE_XCODE
2345 this->Generators[cmGlobalXCodeGenerator::GetActualName()] =
2346 &cmGlobalXCodeGenerator::New;
2347 #endif
2350 int cmake::LoadCache()
2352 // could we not read the cache
2353 if (!this->CacheManager->LoadCache(this->GetHomeOutputDirectory()))
2355 // if it does exist, but isn;t readable then warn the user
2356 std::string cacheFile = this->GetHomeOutputDirectory();
2357 cacheFile += "/CMakeCache.txt";
2358 if(cmSystemTools::FileExists(cacheFile.c_str()))
2360 cmSystemTools::Error(
2361 "There is a CMakeCache.txt file for the current binary tree but "
2362 "cmake does not have permission to read it. Please check the "
2363 "permissions of the directory you are trying to run CMake on.");
2364 return -1;
2368 if (this->CMakeCommand.size() < 2)
2370 cmSystemTools::Error(
2371 "cmake command was not specified prior to loading the cache in "
2372 "cmake.cxx");
2373 return -1;
2376 // setup CMAKE_ROOT and CMAKE_COMMAND
2377 if(!this->AddCMakePaths())
2379 return -3;
2382 // set the default BACKWARDS compatibility to the current version
2383 if(!this->CacheManager->GetCacheValue("CMAKE_BACKWARDS_COMPATIBILITY"))
2385 char ver[256];
2386 sprintf(ver,"%i.%i",cmVersion::GetMajorVersion(),
2387 cmVersion::GetMinorVersion());
2388 this->CacheManager->AddCacheEntry
2389 ("CMAKE_BACKWARDS_COMPATIBILITY",ver,
2390 "For backwards compatibility, what version of CMake commands and "
2391 "syntax should this version of CMake allow.",
2392 cmCacheManager::STRING);
2395 return 0;
2398 void cmake::SetProgressCallback(ProgressCallbackType f, void *cd)
2400 this->ProgressCallback = f;
2401 this->ProgressCallbackClientData = cd;
2404 void cmake::UpdateProgress(const char *msg, float prog)
2406 if(this->ProgressCallback && !this->InTryCompile)
2408 (*this->ProgressCallback)(msg, prog, this->ProgressCallbackClientData);
2409 return;
2413 void cmake::GetCommandDocumentation(std::vector<cmDocumentationEntry>& v,
2414 bool withCurrentCommands,
2415 bool withCompatCommands) const
2417 for(RegisteredCommandsMap::const_iterator j = this->Commands.begin();
2418 j != this->Commands.end(); ++j)
2420 if ((( withCompatCommands == false) && ( (*j).second->IsDiscouraged()))
2421 || ((withCurrentCommands == false) && (!(*j).second->IsDiscouraged())))
2423 continue;
2426 cmDocumentationEntry e((*j).second->GetName(),
2427 (*j).second->GetTerseDocumentation(),
2428 (*j).second->GetFullDocumentation());
2429 v.push_back(e);
2433 void cmake::GetPropertiesDocumentation(std::map<std::string,
2434 cmDocumentationSection *>& v)
2436 // loop over the properties and put them into the doc structure
2437 std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::iterator i;
2438 i = this->PropertyDefinitions.begin();
2439 for (;i != this->PropertyDefinitions.end(); ++i)
2441 i->second.GetPropertiesDocumentation(v);
2445 void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v)
2447 for(RegisteredGeneratorsMap::const_iterator i = this->Generators.begin();
2448 i != this->Generators.end(); ++i)
2450 cmDocumentationEntry e;
2451 cmGlobalGenerator* generator = (i->second)();
2452 generator->GetDocumentation(e);
2453 delete generator;
2454 v.push_back(e);
2456 for(RegisteredExtraGeneratorsMap::const_iterator
2457 i = this->ExtraGenerators.begin(); i != this->ExtraGenerators.end(); ++i)
2459 cmDocumentationEntry e;
2460 cmExternalMakefileProjectGenerator* generator = (i->second)();
2461 generator->GetDocumentation(e, i->first.c_str());
2462 e.Name = i->first;
2463 delete generator;
2464 v.push_back(e);
2468 void cmake::AddWrittenFile(const char* file)
2470 this->WrittenFiles.insert(file);
2473 bool cmake::HasWrittenFile(const char* file)
2475 return this->WrittenFiles.find(file) != this->WrittenFiles.end();
2478 void cmake::CleanupWrittenFiles()
2480 this->WrittenFiles.clear();
2483 void cmake::UpdateConversionPathTable()
2485 // Update the path conversion table with any specified file:
2486 const char* tablepath =
2487 this->CacheManager->GetCacheValue("CMAKE_PATH_TRANSLATION_FILE");
2489 if(tablepath)
2491 std::ifstream table( tablepath );
2492 if(!table)
2494 cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to ", tablepath,
2495 ". CMake can not open file.");
2496 cmSystemTools::ReportLastSystemError("CMake can not open file.");
2498 else
2500 std::string a, b;
2501 while(!table.eof())
2503 // two entries per line
2504 table >> a; table >> b;
2505 cmSystemTools::AddTranslationPath( a.c_str(), b.c_str());
2511 //----------------------------------------------------------------------------
2512 int cmake::CheckBuildSystem()
2514 // We do not need to rerun CMake. Check dependency integrity. Use
2515 // the make system's VERBOSE environment variable to enable verbose
2516 // output.
2517 bool verbose = cmSystemTools::GetEnv("VERBOSE") != 0;
2519 // This method will check the integrity of the build system if the
2520 // option was given on the command line. It reads the given file to
2521 // determine whether CMake should rerun.
2523 // If no file is provided for the check, we have to rerun.
2524 if(this->CheckBuildSystemArgument.size() == 0)
2526 if(verbose)
2528 cmOStringStream msg;
2529 msg << "Re-run cmake no build system arguments\n";
2530 cmSystemTools::Stdout(msg.str().c_str());
2532 return 1;
2535 // If the file provided does not exist, we have to rerun.
2536 if(!cmSystemTools::FileExists(this->CheckBuildSystemArgument.c_str()))
2538 if(verbose)
2540 cmOStringStream msg;
2541 msg << "Re-run cmake missing file: "
2542 << this->CheckBuildSystemArgument.c_str() << "\n";
2543 cmSystemTools::Stdout(msg.str().c_str());
2545 return 1;
2548 // Read the rerun check file and use it to decide whether to do the
2549 // global generate.
2550 cmake cm;
2551 cmGlobalGenerator gg;
2552 gg.SetCMakeInstance(&cm);
2553 std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
2554 lg->SetGlobalGenerator(&gg);
2555 cmMakefile* mf = lg->GetMakefile();
2556 if(!mf->ReadListFile(0, this->CheckBuildSystemArgument.c_str()) ||
2557 cmSystemTools::GetErrorOccuredFlag())
2559 if(verbose)
2561 cmOStringStream msg;
2562 msg << "Re-run cmake error reading : "
2563 << this->CheckBuildSystemArgument.c_str() << "\n";
2564 cmSystemTools::Stdout(msg.str().c_str());
2566 // There was an error reading the file. Just rerun.
2567 return 1;
2570 if(this->ClearBuildSystem)
2572 // Get the generator used for this build system.
2573 const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
2574 if(!genName || genName[0] == '\0')
2576 genName = "Unix Makefiles";
2579 // Create the generator and use it to clear the dependencies.
2580 std::auto_ptr<cmGlobalGenerator>
2581 ggd(this->CreateGlobalGenerator(genName));
2582 if(ggd.get())
2584 std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
2585 lgd->SetGlobalGenerator(ggd.get());
2586 lgd->ClearDependencies(mf, verbose);
2590 // Get the set of dependencies and outputs.
2591 std::vector<std::string> depends;
2592 std::vector<std::string> outputs;
2593 const char* dependsStr = mf->GetDefinition("CMAKE_MAKEFILE_DEPENDS");
2594 const char* outputsStr = mf->GetDefinition("CMAKE_MAKEFILE_OUTPUTS");
2595 if(dependsStr && outputsStr)
2597 cmSystemTools::ExpandListArgument(dependsStr, depends);
2598 cmSystemTools::ExpandListArgument(outputsStr, outputs);
2600 if(depends.empty() || outputs.empty())
2602 // Not enough information was provided to do the test. Just rerun.
2603 if(verbose)
2605 cmOStringStream msg;
2606 msg << "Re-run cmake no CMAKE_MAKEFILE_DEPENDS "
2607 "or CMAKE_MAKEFILE_OUTPUTS :\n";
2608 cmSystemTools::Stdout(msg.str().c_str());
2610 return 1;
2613 // Find find the newest dependency.
2614 std::vector<std::string>::iterator dep = depends.begin();
2615 std::string dep_newest = *dep++;
2616 for(;dep != depends.end(); ++dep)
2618 int result = 0;
2619 if(this->FileComparison->FileTimeCompare(dep_newest.c_str(),
2620 dep->c_str(), &result))
2622 if(result < 0)
2624 dep_newest = *dep;
2627 else
2629 if(verbose)
2631 cmOStringStream msg;
2632 msg << "Re-run cmake: build system dependency is missing\n";
2633 cmSystemTools::Stdout(msg.str().c_str());
2635 return 1;
2639 // Find find the oldest output.
2640 std::vector<std::string>::iterator out = outputs.begin();
2641 std::string out_oldest = *out++;
2642 for(;out != outputs.end(); ++out)
2644 int result = 0;
2645 if(this->FileComparison->FileTimeCompare(out_oldest.c_str(),
2646 out->c_str(), &result))
2648 if(result > 0)
2650 out_oldest = *out;
2653 else
2655 if(verbose)
2657 cmOStringStream msg;
2658 msg << "Re-run cmake: build system output is missing\n";
2659 cmSystemTools::Stdout(msg.str().c_str());
2661 return 1;
2665 // If any output is older than any dependency then rerun.
2667 int result = 0;
2668 if(!this->FileComparison->FileTimeCompare(out_oldest.c_str(),
2669 dep_newest.c_str(),
2670 &result) ||
2671 result < 0)
2673 if(verbose)
2675 cmOStringStream msg;
2676 msg << "Re-run cmake file: " << out_oldest.c_str()
2677 << " older than: " << dep_newest.c_str() << "\n";
2678 cmSystemTools::Stdout(msg.str().c_str());
2680 return 1;
2684 // No need to rerun.
2685 return 0;
2688 //----------------------------------------------------------------------------
2689 void cmake::TruncateOutputLog(const char* fname)
2691 std::string fullPath = this->GetHomeOutputDirectory();
2692 fullPath += "/";
2693 fullPath += fname;
2694 struct stat st;
2695 if ( ::stat(fullPath.c_str(), &st) )
2697 return;
2699 if ( !this->CacheManager->GetCacheValue("CMAKE_CACHEFILE_DIR") )
2701 cmSystemTools::RemoveFile(fullPath.c_str());
2702 return;
2704 off_t fsize = st.st_size;
2705 const off_t maxFileSize = 50 * 1024;
2706 if ( fsize < maxFileSize )
2708 //TODO: truncate file
2709 return;
2713 inline std::string removeQuotes(const std::string& s)
2715 if(s[0] == '\"' && s[s.size()-1] == '\"')
2717 return s.substr(1, s.size()-2);
2719 return s;
2722 std::string cmake::FindCMakeProgram(const char* name) const
2724 std::string path;
2725 if ((name) && (*name))
2727 const cmMakefile* mf
2728 = this->GetGlobalGenerator()->GetLocalGenerators()[0]->GetMakefile();
2729 #ifdef CMAKE_BUILD_WITH_CMAKE
2730 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2731 path = removeQuotes(path);
2732 path = cmSystemTools::GetFilenamePath(path.c_str());
2733 path += "/";
2734 path += name;
2735 path += cmSystemTools::GetExecutableExtension();
2736 if(!cmSystemTools::FileExists(path.c_str()))
2738 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2739 path = cmSystemTools::GetFilenamePath(path.c_str());
2740 path += "/Debug/";
2741 path += name;
2742 path += cmSystemTools::GetExecutableExtension();
2744 if(!cmSystemTools::FileExists(path.c_str()))
2746 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2747 path = cmSystemTools::GetFilenamePath(path.c_str());
2748 path += "/Release/";
2749 path += name;
2750 path += cmSystemTools::GetExecutableExtension();
2752 #else
2753 // Only for bootstrap
2754 path += mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
2755 path += "/";
2756 path += name;
2757 path += cmSystemTools::GetExecutableExtension();
2758 #endif
2760 return path;
2763 const char* cmake::GetCTestCommand()
2765 if ( this->CTestCommand.empty() )
2767 this->CTestCommand = this->FindCMakeProgram("ctest");
2769 if ( this->CTestCommand.empty() )
2771 cmSystemTools::Error("Cannot find the CTest executable");
2772 this->CTestCommand = "CTEST-COMMAND-NOT-FOUND";
2774 return this->CTestCommand.c_str();
2777 const char* cmake::GetCPackCommand()
2779 if ( this->CPackCommand.empty() )
2781 this->CPackCommand = this->FindCMakeProgram("cpack");
2783 if ( this->CPackCommand.empty() )
2785 cmSystemTools::Error("Cannot find the CPack executable");
2786 this->CPackCommand = "CPACK-COMMAND-NOT-FOUND";
2788 return this->CPackCommand.c_str();
2791 void cmake::GenerateGraphViz(const char* fileName) const
2793 cmGeneratedFileStream str(fileName);
2794 if ( !str )
2796 return;
2798 cmake cm;
2799 cmGlobalGenerator ggi;
2800 ggi.SetCMakeInstance(&cm);
2801 std::auto_ptr<cmLocalGenerator> lg(ggi.CreateLocalGenerator());
2802 lg->SetGlobalGenerator(&ggi);
2803 cmMakefile *mf = lg->GetMakefile();
2805 std::string infile = this->GetHomeOutputDirectory();
2806 infile += "/CMakeGraphVizOptions.cmake";
2807 if ( !cmSystemTools::FileExists(infile.c_str()) )
2809 infile = this->GetHomeDirectory();
2810 infile += "/CMakeGraphVizOptions.cmake";
2811 if ( !cmSystemTools::FileExists(infile.c_str()) )
2813 infile = "";
2817 if ( !infile.empty() )
2819 if ( !mf->ReadListFile(0, infile.c_str()) )
2821 cmSystemTools::Error("Problem opening GraphViz options file: ",
2822 infile.c_str());
2823 return;
2825 std::cout << "Read GraphViz options file: " << infile.c_str()
2826 << std::endl;
2829 #define __set_if_not_set(var, value, cmakeDefinition) \
2830 const char* var = mf->GetDefinition(cmakeDefinition); \
2831 if ( !var ) \
2833 var = value; \
2835 __set_if_not_set(graphType, "digraph", "GRAPHVIZ_GRAPH_TYPE");
2836 __set_if_not_set(graphName, "GG", "GRAPHVIZ_GRAPH_NAME");
2837 __set_if_not_set(graphHeader, "node [\n fontsize = \"12\"\n];",
2838 "GRAPHVIZ_GRAPH_HEADER");
2839 __set_if_not_set(graphNodePrefix, "node", "GRAPHVIZ_NODE_PREFIX");
2840 const char* ignoreTargets = mf->GetDefinition("GRAPHVIZ_IGNORE_TARGETS");
2841 std::set<cmStdString> ignoreTargetsSet;
2842 if ( ignoreTargets )
2844 std::vector<std::string> ignoreTargetsVector;
2845 cmSystemTools::ExpandListArgument(ignoreTargets,ignoreTargetsVector);
2846 std::vector<std::string>::iterator itvIt;
2847 for ( itvIt = ignoreTargetsVector.begin();
2848 itvIt != ignoreTargetsVector.end();
2849 ++ itvIt )
2851 ignoreTargetsSet.insert(itvIt->c_str());
2855 str << graphType << " " << graphName << " {" << std::endl;
2856 str << graphHeader << std::endl;
2858 const cmGlobalGenerator* gg = this->GetGlobalGenerator();
2859 const std::vector<cmLocalGenerator*>& localGenerators =
2860 gg->GetLocalGenerators();
2861 std::vector<cmLocalGenerator*>::const_iterator lit;
2862 // for target deps
2863 // 1 - cmake target
2864 // 2 - external target
2865 // 0 - no deps
2866 std::map<cmStdString, int> targetDeps;
2867 std::map<cmStdString, const cmTarget*> targetPtrs;
2868 std::map<cmStdString, cmStdString> targetNamesNodes;
2869 int cnt = 0;
2870 // First pass get the list of all cmake targets
2871 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2873 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
2874 cmTargets::const_iterator tit;
2875 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
2877 const char* realTargetName = tit->first.c_str();
2878 if ( ignoreTargetsSet.find(realTargetName) != ignoreTargetsSet.end() )
2880 // Skip ignored targets
2881 continue;
2883 //std::cout << "Found target: " << tit->first.c_str() << std::endl;
2884 cmOStringStream ostr;
2885 ostr << graphNodePrefix << cnt++;
2886 targetNamesNodes[realTargetName] = ostr.str();
2887 targetPtrs[realTargetName] = &tit->second;
2890 // Ok, now find all the stuff we link to that is not in cmake
2891 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2893 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
2894 cmTargets::const_iterator tit;
2895 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
2897 const cmTarget::LinkLibraryVectorType* ll
2898 = &(tit->second.GetOriginalLinkLibraries());
2899 cmTarget::LinkLibraryVectorType::const_iterator llit;
2900 const char* realTargetName = tit->first.c_str();
2901 if ( ignoreTargetsSet.find(realTargetName) != ignoreTargetsSet.end() )
2903 // Skip ignored targets
2904 continue;
2906 if ( ll->size() > 0 )
2908 targetDeps[realTargetName] = 1;
2910 for ( llit = ll->begin(); llit != ll->end(); ++ llit )
2912 const char* libName = llit->first.c_str();
2913 std::map<cmStdString, cmStdString>::const_iterator tarIt
2914 = targetNamesNodes.find(libName);
2915 if ( ignoreTargetsSet.find(libName) != ignoreTargetsSet.end() )
2917 // Skip ignored targets
2918 continue;
2920 if ( tarIt == targetNamesNodes.end() )
2922 cmOStringStream ostr;
2923 ostr << graphNodePrefix << cnt++;
2924 targetDeps[libName] = 2;
2925 targetNamesNodes[libName] = ostr.str();
2926 //str << " \"" << ostr.c_str() << "\" [ label=\"" << libName
2927 //<< "\" shape=\"ellipse\"];" << std::endl;
2929 else
2931 std::map<cmStdString, int>::const_iterator depIt
2932 = targetDeps.find(libName);
2933 if ( depIt == targetDeps.end() )
2935 targetDeps[libName] = 1;
2942 // Write out nodes
2943 std::map<cmStdString, int>::const_iterator depIt;
2944 for ( depIt = targetDeps.begin(); depIt != targetDeps.end(); ++ depIt )
2946 const char* newTargetName = depIt->first.c_str();
2947 std::map<cmStdString, cmStdString>::const_iterator tarIt
2948 = targetNamesNodes.find(newTargetName);
2949 if ( tarIt == targetNamesNodes.end() )
2951 // We should not be here.
2952 std::cout << __LINE__ << " Cannot find library: " << newTargetName
2953 << " even though it was added in the previous pass" << std::endl;
2954 abort();
2957 str << " \"" << tarIt->second.c_str() << "\" [ label=\""
2958 << newTargetName << "\" shape=\"";
2959 if ( depIt->second == 1 )
2961 std::map<cmStdString, const cmTarget*>::const_iterator tarTypeIt =
2962 targetPtrs.find(newTargetName);
2963 if ( tarTypeIt == targetPtrs.end() )
2965 // We should not be here.
2966 std::cout << __LINE__ << " Cannot find library: " << newTargetName
2967 << " even though it was added in the previous pass" << std::endl;
2968 abort();
2970 const cmTarget* tg = tarTypeIt->second;
2971 switch ( tg->GetType() )
2973 case cmTarget::EXECUTABLE:
2974 str << "house";
2975 break;
2976 case cmTarget::STATIC_LIBRARY:
2977 str << "diamond";
2978 break;
2979 case cmTarget::SHARED_LIBRARY:
2980 str << "polygon";
2981 break;
2982 case cmTarget::MODULE_LIBRARY:
2983 str << "octagon";
2984 break;
2985 default:
2986 str << "box";
2989 else
2991 str << "ellipse";
2993 str << "\"];" << std::endl;
2996 // Now generate the connectivity
2997 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2999 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
3000 cmTargets::const_iterator tit;
3001 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
3003 std::map<cmStdString, int>::iterator dependIt
3004 = targetDeps.find(tit->first.c_str());
3005 if ( dependIt == targetDeps.end() )
3007 continue;
3009 std::map<cmStdString, cmStdString>::iterator cmakeTarIt
3010 = targetNamesNodes.find(tit->first.c_str());
3011 const cmTarget::LinkLibraryVectorType* ll
3012 = &(tit->second.GetOriginalLinkLibraries());
3013 cmTarget::LinkLibraryVectorType::const_iterator llit;
3014 for ( llit = ll->begin(); llit != ll->end(); ++ llit )
3016 const char* libName = llit->first.c_str();
3017 std::map<cmStdString, cmStdString>::const_iterator tarIt
3018 = targetNamesNodes.find(libName);
3019 if ( tarIt == targetNamesNodes.end() )
3021 // We should not be here.
3022 std::cout << __LINE__ << " Cannot find library: " << libName
3023 << " even though it was added in the previous pass" << std::endl;
3024 abort();
3026 str << " \"" << cmakeTarIt->second.c_str() << "\" -> \""
3027 << tarIt->second.c_str() << "\"" << std::endl;
3032 // TODO: Use dotted or something for external libraries
3033 //str << " \"node0\":f4 -> \"node12\"[color=\"#0000ff\" style=dotted]"
3034 //<< std::endl;
3036 str << "}" << std::endl;
3039 //----------------------------------------------------------------------------
3040 #ifdef CMAKE_BUILD_WITH_CMAKE
3041 int cmake::ExecuteEchoColor(std::vector<std::string>& args)
3043 // The arguments are
3044 // argv[0] == <cmake-executable>
3045 // argv[1] == cmake_echo_color
3047 bool enabled = true;
3048 int color = cmsysTerminal_Color_Normal;
3049 bool newline = true;
3050 for(unsigned int i=2; i < args.size(); ++i)
3052 if(args[i].find("--switch=") == 0)
3054 // Enable or disable color based on the switch value.
3055 std::string value = args[i].substr(9);
3056 if(!value.empty())
3058 if(cmSystemTools::IsOn(value.c_str()))
3060 enabled = true;
3062 else
3064 enabled = false;
3068 else if(args[i] == "--normal")
3070 color = cmsysTerminal_Color_Normal;
3072 else if(args[i] == "--black")
3074 color = cmsysTerminal_Color_ForegroundBlack;
3076 else if(args[i] == "--red")
3078 color = cmsysTerminal_Color_ForegroundRed;
3080 else if(args[i] == "--green")
3082 color = cmsysTerminal_Color_ForegroundGreen;
3084 else if(args[i] == "--yellow")
3086 color = cmsysTerminal_Color_ForegroundYellow;
3088 else if(args[i] == "--blue")
3090 color = cmsysTerminal_Color_ForegroundBlue;
3092 else if(args[i] == "--magenta")
3094 color = cmsysTerminal_Color_ForegroundMagenta;
3096 else if(args[i] == "--cyan")
3098 color = cmsysTerminal_Color_ForegroundCyan;
3100 else if(args[i] == "--white")
3102 color = cmsysTerminal_Color_ForegroundWhite;
3104 else if(args[i] == "--bold")
3106 color |= cmsysTerminal_Color_ForegroundBold;
3108 else if(args[i] == "--no-newline")
3110 newline = false;
3112 else if(args[i] == "--newline")
3114 newline = true;
3116 else
3118 // Color is enabled. Print with the current color.
3119 cmSystemTools::MakefileColorEcho(color, args[i].c_str(),
3120 newline, enabled);
3124 return 0;
3126 #else
3127 int cmake::ExecuteEchoColor(std::vector<std::string>&)
3129 return 1;
3131 #endif
3133 //----------------------------------------------------------------------------
3134 int cmake::ExecuteLinkScript(std::vector<std::string>& args)
3136 // The arguments are
3137 // argv[0] == <cmake-executable>
3138 // argv[1] == cmake_link_script
3139 // argv[2] == <link-script-name>
3140 // argv[3] == --verbose=?
3141 bool verbose = false;
3142 if(args.size() >= 4)
3144 if(args[3].find("--verbose=") == 0)
3146 if(!cmSystemTools::IsOff(args[3].substr(10).c_str()))
3148 verbose = true;
3153 // Allocate a process instance.
3154 cmsysProcess* cp = cmsysProcess_New();
3155 if(!cp)
3157 std::cerr << "Error allocating process instance in link script."
3158 << std::endl;
3159 return 1;
3162 // Children should share stdout and stderr with this process.
3163 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
3164 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
3166 // Run the command lines verbatim.
3167 cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
3169 // Read command lines from the script.
3170 std::ifstream fin(args[2].c_str());
3171 if(!fin)
3173 std::cerr << "Error opening link script \""
3174 << args[2] << "\"" << std::endl;
3175 return 1;
3178 // Run one command at a time.
3179 std::string command;
3180 int result = 0;
3181 while(result == 0 && cmSystemTools::GetLineFromStream(fin, command))
3183 // Setup this command line.
3184 const char* cmd[2] = {command.c_str(), 0};
3185 cmsysProcess_SetCommand(cp, cmd);
3187 // Report the command if verbose output is enabled.
3188 if(verbose)
3190 std::cout << command << std::endl;
3193 // Run the command and wait for it to exit.
3194 cmsysProcess_Execute(cp);
3195 cmsysProcess_WaitForExit(cp, 0);
3197 // Report failure if any.
3198 switch(cmsysProcess_GetState(cp))
3200 case cmsysProcess_State_Exited:
3202 int value = cmsysProcess_GetExitValue(cp);
3203 if(value != 0)
3205 result = value;
3208 break;
3209 case cmsysProcess_State_Exception:
3210 std::cerr << "Error running link command: "
3211 << cmsysProcess_GetExceptionString(cp) << std::endl;
3212 result = 1;
3213 break;
3214 case cmsysProcess_State_Error:
3215 std::cerr << "Error running link command: "
3216 << cmsysProcess_GetErrorString(cp) << std::endl;
3217 result = 2;
3218 break;
3219 default:
3220 break;
3224 // Free the process instance.
3225 cmsysProcess_Delete(cp);
3227 // Return the final resulting return value.
3228 return result;
3231 void cmake::DefineProperties(cmake *cm)
3233 cm->DefineProperty
3234 ("REPORT_UNDEFINED_PROPERTIES", cmProperty::GLOBAL,
3235 "If set, report any undefined properties to this file.",
3236 "If this property is set to a filename then when CMake runs "
3237 "it will report any properties or variables that were accessed "
3238 "but not defined into the filename specified in this property."
3241 cm->DefineProperty
3242 ("TARGET_SUPPORTS_SHARED_LIBS", cmProperty::GLOBAL,
3243 "Does the target platform support shared libraries.",
3244 "TARGET_SUPPORTS_SHARED_LIBS is a boolean specifying whether the target "
3245 "platform supports shared libraries. Basically all current general "
3246 "general purpose OS do so, the exception are usually embedded systems "
3247 "with no or special OSs.");
3248 cm->DefineProperty
3249 ("FIND_LIBRARY_USE_LIB64_PATHS", cmProperty::GLOBAL,
3250 "Whether FIND_LIBRARY should automatically search lib64 directories.",
3251 "FIND_LIBRARY_USE_LIB64_PATHS is a boolean specifying whether the "
3252 "FIND_LIBRARY command should automatically search the lib64 variant of "
3253 "directories called lib in the search path when building 64-bit "
3254 "binaries.");
3255 cm->DefineProperty
3256 ("ENABLED_FEATURES", cmProperty::GLOBAL,
3257 "List of features which are enabled during the CMake run.",
3258 "List of features which are enabled during the CMake run. Be default "
3259 "it contains the names of all packages which were found. This is "
3260 "determined using the <NAME>_FOUND variables. Packages which are "
3261 "searched QUIET are not listed. A project can add its own features to "
3262 "this list.This property is used by the macros in FeatureSummary.cmake.");
3263 cm->DefineProperty
3264 ("DISABLED_FEATURES", cmProperty::GLOBAL,
3265 "List of features which are disabled during the CMake run.",
3266 "List of features which are disabled during the CMake run. Be default "
3267 "it contains the names of all packages which were not found. This is "
3268 "determined using the <NAME>_FOUND variables. Packages which are "
3269 "searched QUIET are not listed. A project can add its own features to "
3270 "this list.This property is used by the macros in FeatureSummary.cmake.");
3271 cm->DefineProperty
3272 ("PACKAGES_FOUND", cmProperty::GLOBAL,
3273 "List of packages which were found during the CMake run.",
3274 "List of packages which were found during the CMake run. Whether a "
3275 "package has been found is determined using the <NAME>_FOUND variables.");
3276 cm->DefineProperty
3277 ("PACKAGES_NOT_FOUND", cmProperty::GLOBAL,
3278 "List of packages which were not found during the CMake run.",
3279 "List of packages which were not found during the CMake run. Whether a "
3280 "package has been found is determined using the <NAME>_FOUND variables.");
3282 cm->DefineProperty
3283 ("PACKAGES_NOT_FOUND", cmProperty::GLOBAL,
3284 "List of packages which were not found during the CMake run.",
3285 "List of packages which were not found during the CMake run. Whether a "
3286 "package has been found is determined using the <NAME>_FOUND variables.");
3287 cm->DefineProperty(
3288 "__CMAKE_DELETE_CACHE_CHANGE_VARS_", cmProperty::GLOBAL,
3289 "Internal property",
3290 "Used to detect compiler changes, Do not set.");
3292 // ================================================================
3293 // define variables as well
3294 // ================================================================
3295 cmDocumentVariables::DefineVariables(cm);
3299 void cmake::DefineProperty(const char *name, cmProperty::ScopeType scope,
3300 const char *ShortDescription,
3301 const char *FullDescription,
3302 bool chained, const char *docSection)
3304 this->PropertyDefinitions[scope].DefineProperty(name,scope,ShortDescription,
3305 FullDescription,
3306 docSection,
3307 chained);
3310 cmPropertyDefinition *cmake
3311 ::GetPropertyDefinition(const char *name,
3312 cmProperty::ScopeType scope)
3314 if (this->IsPropertyDefined(name,scope))
3316 return &(this->PropertyDefinitions[scope][name]);
3318 return 0;
3321 void cmake::RecordPropertyAccess(const char *name,
3322 cmProperty::ScopeType scope)
3324 this->AccessedProperties.insert
3325 (std::pair<cmStdString,cmProperty::ScopeType>(name,scope));
3328 void cmake::ReportUndefinedPropertyAccesses(const char *filename)
3330 FILE *progFile = fopen(filename,"w");
3331 if (!progFile || !this->GlobalGenerator)
3333 return;
3336 // what are the enabled languages?
3337 std::vector<std::string> enLangs;
3338 this->GlobalGenerator->GetEnabledLanguages(enLangs);
3340 // Common configuration names.
3341 // TODO: Compute current configuration(s).
3342 std::vector<std::string> enConfigs;
3343 enConfigs.push_back("");
3344 enConfigs.push_back("DEBUG");
3345 enConfigs.push_back("RELEASE");
3346 enConfigs.push_back("MINSIZEREL");
3347 enConfigs.push_back("RELWITHDEBINFO");
3349 // take all the defined properties and add definitions for all the enabled
3350 // languages
3351 std::set<std::pair<cmStdString,cmProperty::ScopeType> > aliasedProperties;
3352 std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::iterator i;
3353 i = this->PropertyDefinitions.begin();
3354 for (;i != this->PropertyDefinitions.end(); ++i)
3356 cmPropertyDefinitionMap::iterator j;
3357 for (j = i->second.begin(); j != i->second.end(); ++j)
3359 // TODO: What if both <LANG> and <CONFIG> appear?
3360 if (j->first.find("<CONFIG>") != std::string::npos)
3362 std::vector<std::string>::const_iterator k;
3363 for (k = enConfigs.begin(); k != enConfigs.end(); ++k)
3365 std::string tmp = j->first;
3366 cmSystemTools::ReplaceString(tmp, "<CONFIG>", k->c_str());
3367 // add alias
3368 aliasedProperties.insert
3369 (std::pair<cmStdString,cmProperty::ScopeType>(tmp,i->first));
3372 if (j->first.find("<LANG>") != std::string::npos)
3374 std::vector<std::string>::const_iterator k;
3375 for (k = enLangs.begin(); k != enLangs.end(); ++k)
3377 std::string tmp = j->first;
3378 cmSystemTools::ReplaceString(tmp, "<LANG>", k->c_str());
3379 // add alias
3380 aliasedProperties.insert
3381 (std::pair<cmStdString,cmProperty::ScopeType>(tmp,i->first));
3387 std::set<std::pair<cmStdString,cmProperty::ScopeType> >::const_iterator ap;
3388 ap = this->AccessedProperties.begin();
3389 for (;ap != this->AccessedProperties.end(); ++ap)
3391 if (!this->IsPropertyDefined(ap->first.c_str(),ap->second) &&
3392 aliasedProperties.find(std::pair<cmStdString,cmProperty::ScopeType>
3393 (ap->first,ap->second)) ==
3394 aliasedProperties.end())
3396 const char *scopeStr = "";
3397 switch (ap->second)
3399 case cmProperty::TARGET:
3400 scopeStr = "TARGET";
3401 break;
3402 case cmProperty::SOURCE_FILE:
3403 scopeStr = "SOURCE_FILE";
3404 break;
3405 case cmProperty::DIRECTORY:
3406 scopeStr = "DIRECTORY";
3407 break;
3408 case cmProperty::TEST:
3409 scopeStr = "TEST";
3410 break;
3411 case cmProperty::VARIABLE:
3412 scopeStr = "VARIABLE";
3413 break;
3414 case cmProperty::CACHED_VARIABLE:
3415 scopeStr = "CACHED_VARIABLE";
3416 break;
3417 default:
3418 scopeStr = "unknown";
3419 break;
3421 fprintf(progFile,"%s with scope %s\n",ap->first.c_str(),scopeStr);
3424 fclose(progFile);
3427 bool cmake::IsPropertyDefined(const char *name, cmProperty::ScopeType scope)
3429 return this->PropertyDefinitions[scope].IsPropertyDefined(name);
3432 bool cmake::IsPropertyChained(const char *name, cmProperty::ScopeType scope)
3434 return this->PropertyDefinitions[scope].IsPropertyChained(name);
3437 void cmake::SetProperty(const char* prop, const char* value)
3439 if (!prop)
3441 return;
3443 if (!value)
3445 value = "NOTFOUND";
3448 this->Properties.SetProperty(prop, value, cmProperty::GLOBAL);
3451 void cmake::AppendProperty(const char* prop, const char* value)
3453 if (!prop)
3455 return;
3457 this->Properties.AppendProperty(prop, value, cmProperty::GLOBAL);
3460 const char *cmake::GetProperty(const char* prop)
3462 return this->GetProperty(prop, cmProperty::GLOBAL);
3465 const char *cmake::GetProperty(const char* prop, cmProperty::ScopeType scope)
3467 bool chain = false;
3469 // watch for special properties
3470 std::string propname = prop;
3471 std::string output = "";
3472 if ( propname == "CACHE_VARIABLES" )
3474 cmCacheManager::CacheIterator cit =
3475 this->GetCacheManager()->GetCacheIterator();
3476 for ( cit.Begin(); !cit.IsAtEnd(); cit.Next() )
3478 if ( output.size() )
3480 output += ";";
3482 output += cit.GetName();
3484 this->SetProperty("CACHE_VARIABLES", output.c_str());
3486 else if ( propname == "COMMANDS" )
3488 cmake::RegisteredCommandsMap::iterator cmds
3489 = this->GetCommands()->begin();
3490 for (unsigned int cc=0 ; cmds != this->GetCommands()->end(); ++ cmds )
3492 if ( cc > 0 )
3494 output += ";";
3496 output += cmds->first.c_str();
3497 cc++;
3499 this->SetProperty("COMMANDS",output.c_str());
3502 return this->Properties.GetPropertyValue(prop, scope, chain);
3505 bool cmake::GetPropertyAsBool(const char* prop)
3507 return cmSystemTools::IsOn(this->GetProperty(prop));
3510 int cmake::GetSystemInformation(std::vector<std::string>& args)
3512 // so create the directory
3513 std::string resultFile;
3514 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
3515 std::string destPath = cwd + "/__cmake_systeminformation";
3516 cmSystemTools::RemoveADirectory(destPath.c_str());
3517 if (!cmSystemTools::MakeDirectory(destPath.c_str()))
3519 std::cerr << "Error: --system-information must be run from a "
3520 "writable directory!\n";
3521 return 1;
3524 // process the arguments
3525 bool writeToStdout = true;
3526 for(unsigned int i=1; i < args.size(); ++i)
3528 std::string arg = args[i];
3529 if(arg.find("-V",0) == 0)
3531 this->Verbose = true;
3533 else if(arg.find("-G",0) == 0)
3535 std::string value = arg.substr(2);
3536 if(value.size() == 0)
3538 ++i;
3539 if(i >= args.size())
3541 cmSystemTools::Error("No generator specified for -G");
3542 return -1;
3544 value = args[i];
3546 cmGlobalGenerator* gen =
3547 this->CreateGlobalGenerator(value.c_str());
3548 if(!gen)
3550 cmSystemTools::Error("Could not create named generator ",
3551 value.c_str());
3553 else
3555 this->SetGlobalGenerator(gen);
3558 // no option assume it is the output file
3559 else
3561 if (!cmSystemTools::FileIsFullPath(arg.c_str()))
3563 resultFile = cwd;
3564 resultFile += "/";
3566 resultFile += arg;
3567 writeToStdout = false;
3572 // we have to find the module directory, so we can copy the files
3573 this->AddCMakePaths();
3574 std::string modulesPath =
3575 this->CacheManager->GetCacheValue("CMAKE_ROOT");
3576 modulesPath += "/Modules";
3577 std::string inFile = modulesPath;
3578 inFile += "/SystemInformation.cmake";
3579 std::string outFile = destPath;
3580 outFile += "/CMakeLists.txt";
3582 // Copy file
3583 if(!cmSystemTools::cmCopyFile(inFile.c_str(), outFile.c_str()))
3585 std::cerr << "Error copying file \"" << inFile.c_str()
3586 << "\" to \"" << outFile.c_str() << "\".\n";
3587 return 1;
3590 // do we write to a file or to stdout?
3591 if (resultFile.size() == 0)
3593 resultFile = cwd;
3594 resultFile += "/__cmake_systeminformation/results.txt";
3597 // now run cmake on the CMakeLists file
3598 cmSystemTools::ChangeDirectory(destPath.c_str());
3599 std::vector<std::string> args2;
3600 args2.push_back(args[0]);
3601 args2.push_back(destPath);
3602 std::string resultArg = "-DRESULT_FILE=";
3603 resultArg += resultFile;
3604 args2.push_back(resultArg);
3605 int res = this->Run(args2, false);
3607 if (res != 0)
3609 std::cerr << "Error: --system-information failed on internal CMake!\n";
3610 return res;
3613 // change back to the original directory
3614 cmSystemTools::ChangeDirectory(cwd.c_str());
3616 // echo results to stdout if needed
3617 if (writeToStdout)
3619 FILE* fin = fopen(resultFile.c_str(), "r");
3620 if(fin)
3622 const int bufferSize = 4096;
3623 char buffer[bufferSize];
3624 size_t n;
3625 while((n = fread(buffer, 1, bufferSize, fin)) > 0)
3627 for(char* c = buffer; c < buffer+n; ++c)
3629 putc(*c, stdout);
3631 fflush(stdout);
3633 fclose(fin);
3637 // clean up the directory
3638 cmSystemTools::RemoveADirectory(destPath.c_str());
3639 return 0;
3642 //----------------------------------------------------------------------------
3643 static bool cmakeCheckStampFile(const char* stampName)
3645 // If the stamp file still exists then it must really be out of
3646 // date.
3647 if(cmSystemTools::FileExists(stampName))
3649 return false;
3652 // The stamp file does not exist. Use the stamp dependencies to
3653 // determine whether it is really out of date. This works in
3654 // conjunction with cmLocalVisualStudio7Generator to avoid
3655 // repeatedly re-running CMake when the user rebuilds the entire
3656 // solution.
3657 std::string stampDepends = stampName;
3658 stampDepends += ".depend";
3659 #if defined(_WIN32) || defined(__CYGWIN__)
3660 std::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
3661 #else
3662 std::ifstream fin(stampDepends.c_str(), std::ios::in);
3663 #endif
3664 if(!fin)
3666 // The stamp dependencies file cannot be read. Just assume the
3667 // build system is really out of date.
3668 return false;
3671 // Compare the stamp dependencies against the dependency file itself.
3672 cmFileTimeComparison ftc;
3673 std::string dep;
3674 while(cmSystemTools::GetLineFromStream(fin, dep))
3676 int result;
3677 if(dep.length() >= 1 && dep[0] != '#' &&
3678 (!ftc.FileTimeCompare(stampDepends.c_str(), dep.c_str(), &result)
3679 || result < 0))
3681 // The stamp depends file is older than this dependency. The
3682 // build system is really out of date.
3683 return false;
3687 // The build system is up to date. The stamp file has been removed
3688 // by the VS IDE due to a "rebuild" request. Just restore it.
3689 std::ofstream stamp(stampName);
3690 stamp << "# CMake generation timestamp file this directory.\n";
3691 if(stamp)
3693 // Notify the user why CMake is not re-running. It is safe to
3694 // just print to stdout here because this code is only reachable
3695 // through an undocumented flag used by the VS generator.
3696 std::cout << "CMake does not need to re-run because the "
3697 << "generation timestamp is up-to-date.\n";
3698 return true;
3700 else
3702 cmSystemTools::Error("Cannot restore timestamp ", stampName);
3703 return false;
3707 // For visual studio 2005 and newer manifest files need to be embeded into
3708 // exe and dll's. This code does that in such a way that incremental linking
3709 // still works.
3710 int cmake::VisualStudioLink(std::vector<std::string>& args, int type)
3712 if(args.size() < 2)
3714 return -1;
3716 bool verbose = false;
3717 if(cmSystemTools::GetEnv("VERBOSE"))
3719 verbose = true;
3721 std::vector<std::string> expandedArgs;
3722 for(std::vector<std::string>::iterator i = args.begin();
3723 i != args.end(); ++i)
3725 // check for nmake temporary files
3726 if((*i)[0] == '@')
3728 std::ifstream fin(i->substr(1).c_str());
3729 std::string line;
3730 while(cmSystemTools::GetLineFromStream(fin,
3731 line))
3733 cmSystemTools::ParseWindowsCommandLine(line.c_str(), expandedArgs);
3736 else
3738 expandedArgs.push_back(*i);
3741 // figure out if this is an incremental link or not and run the correct
3742 // link function.
3743 for(std::vector<std::string>::iterator i = expandedArgs.begin();
3744 i != expandedArgs.end(); ++i)
3746 if(cmSystemTools::Strucmp(i->c_str(), "/INCREMENTAL:YES") == 0)
3748 if(verbose)
3750 std::cout << "Visual Studio Incremental Link\n";
3752 return cmake::VisualStudioLinkIncremental(expandedArgs, type, verbose);
3755 if(verbose)
3757 std::cout << "Visual Studio Non-Incremental Link\n";
3759 return cmake::VisualStudioLinkNonIncremental(expandedArgs, type, verbose);
3762 int cmake::ParseVisualStudioLinkCommand(std::vector<std::string>& args,
3763 std::vector<cmStdString>& command,
3764 std::string& targetName)
3766 std::vector<std::string>::iterator i = args.begin();
3767 i++; // skip -E
3768 i++; // skip vs_link_dll or vs_link_exe
3769 command.push_back(*i);
3770 i++; // move past link command
3771 for(; i != args.end(); ++i)
3773 command.push_back(*i);
3774 if(i->find("/Fe") == 0)
3776 targetName = i->substr(3);
3778 if(i->find("/out:") == 0)
3780 targetName = i->substr(5);
3783 if(targetName.size() == 0 || command.size() == 0)
3785 return -1;
3787 return 0;
3790 bool cmake::RunCommand(const char* comment,
3791 std::vector<cmStdString>& command,
3792 bool verbose,
3793 int* retCodeOut)
3795 if(verbose)
3797 std::cout << comment << ":\n";
3798 for(std::vector<cmStdString>::iterator i = command.begin();
3799 i != command.end(); ++i)
3801 std::cout << i->c_str() << " ";
3803 std::cout << "\n";
3805 std::string output;
3806 int retCode =0;
3807 // use rc command to create .res file
3808 cmSystemTools::RunSingleCommand(command,
3809 &output,
3810 &retCode);
3811 if(verbose)
3813 std::cout << output << "\n";
3815 // if retCodeOut is requested then always return true
3816 // and set the retCodeOut to retCode
3817 if(retCodeOut)
3819 *retCodeOut = retCode;
3820 return true;
3822 if(retCode != 0)
3824 std::cout << comment << " failed. with " << retCode << "\n";
3826 return retCode == 0;
3829 int cmake::VisualStudioLinkIncremental(std::vector<std::string>& args,
3830 int type, bool verbose)
3832 // This follows the steps listed here:
3833 // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx
3835 // 1. Compiler compiles the application and generates the *.obj files.
3836 // 2. An empty manifest file is generated if this is a clean build and if
3837 // not the previous one is reused.
3838 // 3. The resource compiler (rc.exe) compiles the *.manifest file to a
3839 // *.res file.
3840 // 4. Linker generates the binary (EXE or DLL) with the /incremental
3841 // switch and embeds the dummy manifest file. The linker also generates
3842 // the real manifest file based on the binaries that your binary depends
3843 // on.
3844 // 5. The manifest tool (mt.exe) is then used to generate the final
3845 // manifest.
3847 // If the final manifest is changed, then 6 and 7 are run, if not
3848 // they are skipped, and it is done.
3850 // 6. The resource compiler is invoked one more time.
3851 // 7. Finally, the Linker does another incremental link, but since the
3852 // only thing that has changed is the *.res file that contains the
3853 // manifest it is a short link.
3854 std::vector<cmStdString> linkCommand;
3855 std::string targetName;
3856 if(cmake::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1)
3858 return -1;
3860 std::string manifestArg = "/MANIFESTFILE:";
3861 std::vector<cmStdString> rcCommand;
3862 rcCommand.push_back(cmSystemTools::FindProgram("rc.exe"));
3863 std::vector<cmStdString> mtCommand;
3864 mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
3865 std::string tempManifest;
3866 tempManifest = targetName;
3867 tempManifest += ".intermediate.manifest";
3868 std::string resourceInputFile = targetName;
3869 resourceInputFile += ".resource.txt";
3870 if(verbose)
3872 std::cout << "Create " << resourceInputFile.c_str() << "\n";
3874 // Create input file for rc command
3875 std::ofstream fout(resourceInputFile.c_str());
3876 if(!fout)
3878 return -1;
3880 std::string manifestFile = targetName;
3881 manifestFile += ".embed.manifest";
3882 std::string fullPath= cmSystemTools::CollapseFullPath(manifestFile.c_str());
3883 fout << type << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID "
3884 "*/ 24 /* RT_MANIFEST */ " << "\"" << fullPath.c_str() << "\"";
3885 fout.close();
3886 manifestArg += tempManifest;
3887 // add the manifest arg to the linkCommand
3888 linkCommand.push_back(manifestArg);
3889 // if manifestFile is not yet created, create an
3890 // empty one
3891 if(!cmSystemTools::FileExists(manifestFile.c_str()))
3893 if(verbose)
3895 std::cout << "Create empty: " << manifestFile.c_str() << "\n";
3897 std::ofstream foutTmp(manifestFile.c_str());
3899 std::string resourceFile = manifestFile;
3900 resourceFile += ".res";
3901 // add the resource file to the end of the link command
3902 linkCommand.push_back(resourceFile);
3903 std::string outputOpt = "/fo";
3904 outputOpt += resourceFile;
3905 rcCommand.push_back(outputOpt);
3906 rcCommand.push_back(resourceInputFile);
3907 // Run rc command to create resource
3908 if(!cmake::RunCommand("RC Pass 1", rcCommand, verbose))
3910 return -1;
3912 // Now run the link command to link and create manifest
3913 if(!cmake::RunCommand("LINK Pass 1", linkCommand, verbose))
3915 return -1;
3917 // create mt command
3918 std::string outArg("/out:");
3919 outArg+= manifestFile;
3920 mtCommand.push_back("/nologo");
3921 mtCommand.push_back(outArg);
3922 mtCommand.push_back("/notify_update");
3923 mtCommand.push_back("/manifest");
3924 mtCommand.push_back(tempManifest);
3925 // now run mt.exe to create the final manifest file
3926 int mtRet =0;
3927 cmake::RunCommand("MT", mtCommand, verbose, &mtRet);
3928 // if mt returns 0, then the manifest was not changed and
3929 // we do not need to do another link step
3930 if(mtRet == 0)
3932 return 0;
3934 // check for magic mt return value if mt returns the magic number
3935 // 1090650113 then it means that it updated the manifest file and we need
3936 // to do the final link. If mt has any value other than 0 or 1090650113
3937 // then there was some problem with the command itself and there was an
3938 // error so return the error code back out of cmake so make can report it.
3939 if(mtRet != 1090650113)
3941 return mtRet;
3943 // update the resource file with the new manifest from the mt command.
3944 if(!cmake::RunCommand("RC Pass 2", rcCommand, verbose))
3946 return -1;
3948 // Run the final incremental link that will put the new manifest resource
3949 // into the file incrementally.
3950 if(!cmake::RunCommand("FINAL LINK", linkCommand, verbose))
3952 return -1;
3954 return 0;
3957 int cmake::VisualStudioLinkNonIncremental(std::vector<std::string>& args,
3958 int type,
3959 bool verbose)
3961 std::vector<cmStdString> linkCommand;
3962 std::string targetName;
3963 if(cmake::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1)
3965 return -1;
3967 // Run the link command as given
3968 if(!cmake::RunCommand("LINK", linkCommand, verbose))
3970 return -1;
3972 std::vector<cmStdString> mtCommand;
3973 mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
3974 mtCommand.push_back("/nologo");
3975 mtCommand.push_back("/manifest");
3976 std::string manifestFile = targetName;
3977 manifestFile += ".manifest";
3978 mtCommand.push_back(manifestFile);
3979 std::string outresource = "/outputresource:";
3980 outresource += targetName;
3981 outresource += ";#";
3982 if(type == 1)
3984 outresource += "1";
3986 else if(type == 2)
3988 outresource += "2";
3990 mtCommand.push_back(outresource);
3991 // Now use the mt tool to embed the manifest into the exe or dll
3992 if(!cmake::RunCommand("MT", mtCommand, verbose))
3994 return -1;
3996 return 0;