ENH: keep cleaning up Tcl/Tk modules
[cmake.git] / Source / cmake.cxx
blobe0e6821b675b77f5c0bf4caa056aed41f15b11ec
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmake.cxx,v $
5 Language: C++
6 Date: $Date: 2008-01-20 18:36:13 $
7 Version: $Revision: 1.354 $
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::RemoveADirectory(args[2].c_str()))
1032 std::cerr << "Error removing directory \"" << args[2].c_str()
1033 << "\".\n";
1034 return 1;
1036 return 0;
1039 // Remove file
1040 else if (args[1] == "remove" && args.size() > 2)
1042 bool force = false;
1043 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1045 if(args[cc] == "\\-f" || args[cc] == "-f")
1047 force = true;
1049 else
1051 // Complain if the file could not be removed, still exists,
1052 // and the -f option was not given.
1053 if(!cmSystemTools::RemoveFile(args[cc].c_str()) && !force &&
1054 cmSystemTools::FileExists(args[cc].c_str()))
1056 return 1;
1060 return 0;
1062 // Touch file
1063 else if (args[1] == "touch" && args.size() > 2)
1065 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1067 // Complain if the file could not be removed, still exists,
1068 // and the -f option was not given.
1069 if(!cmSystemTools::Touch(args[cc].c_str(), true))
1071 return 1;
1074 return 0;
1076 // Touch file
1077 else if (args[1] == "touch_nocreate" && args.size() > 2)
1079 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1081 // Complain if the file could not be removed, still exists,
1082 // and the -f option was not given.
1083 if(!cmSystemTools::Touch(args[cc].c_str(), false))
1085 return 1;
1088 return 0;
1091 // Clock command
1092 else if (args[1] == "time" && args.size() > 2)
1094 std::string command = args[2];
1095 for (std::string::size_type cc = 3; cc < args.size(); cc ++)
1097 command += " ";
1098 command += args[cc];
1101 clock_t clock_start, clock_finish;
1102 time_t time_start, time_finish;
1104 time(&time_start);
1105 clock_start = clock();
1107 cmSystemTools::RunSingleCommand(command.c_str());
1109 clock_finish = clock();
1110 time(&time_finish);
1112 double clocks_per_sec = static_cast<double>(CLOCKS_PER_SEC);
1113 std::cout << "Elapsed time: "
1114 << static_cast<long>(time_finish - time_start) << " s. (time)"
1115 << ", "
1116 << static_cast<double>(clock_finish - clock_start) / clocks_per_sec
1117 << " s. (clock)"
1118 << "\n";
1119 return 0;
1122 // Command to calculate the md5sum of a file
1123 else if (args[1] == "md5sum" && args.size() >= 3)
1125 char md5out[32];
1126 int retval = 0;
1127 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
1129 const char *filename = args[cc].c_str();
1130 // Cannot compute md5sum of a directory
1131 if(cmSystemTools::FileIsDirectory(filename))
1133 std::cerr << "Error: " << filename << " is a directory" << std::endl;
1134 retval++;
1136 else if(!cmSystemTools::ComputeFileMD5(filename, md5out))
1138 // To mimic md5sum behavior in a shell:
1139 std::cerr << filename << ": No such file or directory" << std::endl;
1140 retval++;
1142 else
1144 std::cout << std::string(md5out,32) << " " << filename << std::endl;
1147 return retval;
1150 // Command to change directory and run a program.
1151 else if (args[1] == "chdir" && args.size() >= 4)
1153 std::string directory = args[2];
1154 if(!cmSystemTools::FileExists(directory.c_str()))
1156 cmSystemTools::Error("Directory does not exist for chdir command: ",
1157 args[2].c_str());
1158 return 0;
1161 std::string command = "\"";
1162 command += args[3];
1163 command += "\"";
1164 for (std::string::size_type cc = 4; cc < args.size(); cc ++)
1166 command += " \"";
1167 command += args[cc];
1168 command += "\"";
1170 int retval = 0;
1171 int timeout = 0;
1172 if ( cmSystemTools::RunSingleCommand(command.c_str(), 0, &retval,
1173 directory.c_str(), true, timeout) )
1175 return retval;
1178 return 1;
1181 // Command to start progress for a build
1182 else if (args[1] == "cmake_progress_start" && args.size() == 4)
1184 // bascially remove the directory
1185 std::string dirName = args[2];
1186 dirName += "/Progress";
1187 cmSystemTools::RemoveADirectory(dirName.c_str());
1189 // is the last argument a filename that exists?
1190 FILE *countFile = fopen(args[3].c_str(),"r");
1191 int count;
1192 if (countFile)
1194 fscanf(countFile,"%i",&count);
1195 fclose(countFile);
1197 else
1199 count = atoi(args[3].c_str());
1201 if (count)
1203 cmSystemTools::MakeDirectory(dirName.c_str());
1204 // write the count into the directory
1205 std::string fName = dirName;
1206 fName += "/count.txt";
1207 FILE *progFile = fopen(fName.c_str(),"w");
1208 if (progFile)
1210 fprintf(progFile,"%i\n",count);
1211 fclose(progFile);
1214 return 0;
1217 // Command to report progress for a build
1218 else if (args[1] == "cmake_progress_report" && args.size() >= 3)
1220 std::string dirName = args[2];
1221 dirName += "/Progress";
1222 std::string fName;
1223 FILE *progFile;
1225 // read the count
1226 fName = dirName;
1227 fName += "/count.txt";
1228 progFile = fopen(fName.c_str(),"r");
1229 int count = 0;
1230 if (!progFile)
1232 return 0;
1234 else
1236 fscanf(progFile,"%i",&count);
1237 fclose(progFile);
1239 unsigned int i;
1240 for (i = 3; i < args.size(); ++i)
1242 fName = dirName;
1243 fName += "/";
1244 fName += args[i];
1245 progFile = fopen(fName.c_str(),"w");
1246 if (progFile)
1248 fprintf(progFile,"empty");
1249 fclose(progFile);
1252 int fileNum = static_cast<int>
1253 (cmsys::Directory::GetNumberOfFilesInDirectory(dirName.c_str()));
1254 if (count > 0)
1256 // print the progress
1257 fprintf(stdout,"[%3i%%] ",((fileNum-3)*100)/count);
1259 return 0;
1262 // Command to create a symbolic link. Fails on platforms not
1263 // supporting them.
1264 else if (args[1] == "create_symlink" && args.size() == 4)
1266 const char* destinationFileName = args[3].c_str();
1267 if ( cmSystemTools::FileExists(destinationFileName) )
1269 if ( cmSystemTools::FileIsSymlink(destinationFileName) )
1271 if ( !cmSystemTools::RemoveFile(destinationFileName) ||
1272 cmSystemTools::FileExists(destinationFileName) )
1274 return 0;
1277 else
1279 return 0;
1282 return cmSystemTools::CreateSymlink(args[2].c_str(),
1283 args[3].c_str())? 0:1;
1286 // Internal CMake shared library support.
1287 else if (args[1] == "cmake_symlink_library" && args.size() == 5)
1289 int result = 0;
1290 std::string realName = args[2];
1291 std::string soName = args[3];
1292 std::string name = args[4];
1293 if(soName != realName)
1295 std::string fname = cmSystemTools::GetFilenameName(realName);
1296 if(cmSystemTools::FileExists(soName.c_str()))
1298 cmSystemTools::RemoveFile(soName.c_str());
1300 if(!cmSystemTools::CreateSymlink(fname.c_str(), soName.c_str()))
1302 result = 1;
1305 if(name != soName)
1307 std::string fname = cmSystemTools::GetFilenameName(soName);
1308 if(cmSystemTools::FileExists(soName.c_str()))
1310 cmSystemTools::RemoveFile(name.c_str());
1312 if(!cmSystemTools::CreateSymlink(fname.c_str(), name.c_str()))
1314 result = 1;
1317 return result;
1319 // Internal CMake versioned executable support.
1320 else if (args[1] == "cmake_symlink_executable" && args.size() == 4)
1322 int result = 0;
1323 std::string realName = args[2];
1324 std::string name = args[3];
1325 if(name != realName)
1327 std::string fname = cmSystemTools::GetFilenameName(realName);
1328 if(cmSystemTools::FileExists(realName.c_str()))
1330 cmSystemTools::RemoveFile(name.c_str());
1332 if(!cmSystemTools::CreateSymlink(fname.c_str(), name.c_str()))
1334 result = 1;
1337 return result;
1340 #if defined(CMAKE_HAVE_VS_GENERATORS)
1341 // Internal CMake support for calling Visual Studio macros.
1342 else if (args[1] == "cmake_call_visual_studio_macro" && args.size() >= 4)
1344 // args[2] = full path to .sln file or "ALL"
1345 // args[3] = name of Visual Studio macro to call
1346 // args[4..args.size()-1] = [optional] args for Visual Studio macro
1348 std::string macroArgs;
1350 if (args.size() > 4)
1352 macroArgs = args[4];
1354 for (size_t i = 5; i < args.size(); ++i)
1356 macroArgs += " ";
1357 macroArgs += args[i];
1361 return cmCallVisualStudioMacro::CallMacro(args[2], args[3], macroArgs);
1363 #endif
1365 // Internal CMake dependency scanning support.
1366 else if (args[1] == "cmake_depends" && args.size() >= 6)
1368 // Use the make system's VERBOSE environment variable to enable
1369 // verbose output.
1370 bool verbose = cmSystemTools::GetEnv("VERBOSE") != 0;
1372 // Create a cmake object instance to process dependencies.
1373 cmake cm;
1374 std::string gen;
1375 std::string homeDir;
1376 std::string startDir;
1377 std::string homeOutDir;
1378 std::string startOutDir;
1379 std::string depInfo;
1380 bool color = true;
1381 if(args.size() >= 8)
1383 // Full signature:
1385 // -E cmake_depends <generator>
1386 // <home-src-dir> <start-src-dir>
1387 // <home-out-dir> <start-out-dir>
1388 // <dep-info> [--color=$(COLOR)]
1390 // All paths are provided.
1391 gen = args[2];
1392 homeDir = args[3];
1393 startDir = args[4];
1394 homeOutDir = args[5];
1395 startOutDir = args[6];
1396 depInfo = args[7];
1397 if(args.size() >= 9 &&
1398 args[8].length() > 8 &&
1399 args[8].substr(0, 8) == "--color=")
1401 // Enable or disable color based on the switch value.
1402 color = cmSystemTools::IsOn(args[8].substr(8).c_str());
1405 else
1407 // Support older signature for existing makefiles:
1409 // -E cmake_depends <generator>
1410 // <home-out-dir> <start-out-dir>
1411 // <dep-info>
1413 // Just pretend the source directories are the same as the
1414 // binary directories so at least scanning will work.
1415 gen = args[2];
1416 homeDir = args[3];
1417 startDir = args[4];
1418 homeOutDir = args[3];
1419 startOutDir = args[3];
1420 depInfo = args[5];
1423 // Create a local generator configured for the directory in
1424 // which dependencies will be scanned.
1425 homeDir = cmSystemTools::CollapseFullPath(homeDir.c_str());
1426 startDir = cmSystemTools::CollapseFullPath(startDir.c_str());
1427 homeOutDir = cmSystemTools::CollapseFullPath(homeOutDir.c_str());
1428 startOutDir = cmSystemTools::CollapseFullPath(startOutDir.c_str());
1429 cm.SetHomeDirectory(homeDir.c_str());
1430 cm.SetStartDirectory(startDir.c_str());
1431 cm.SetHomeOutputDirectory(homeOutDir.c_str());
1432 cm.SetStartOutputDirectory(startOutDir.c_str());
1433 if(cmGlobalGenerator* ggd = cm.CreateGlobalGenerator(gen.c_str()))
1435 cm.SetGlobalGenerator(ggd);
1436 std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
1437 lgd->SetGlobalGenerator(ggd);
1438 lgd->GetMakefile()->SetStartDirectory(startDir.c_str());
1439 lgd->GetMakefile()->SetStartOutputDirectory(startOutDir.c_str());
1440 lgd->GetMakefile()->MakeStartDirectoriesCurrent();
1442 // Actually scan dependencies.
1443 return lgd->UpdateDependencies(depInfo.c_str(),
1444 verbose, color)? 0 : 2;
1446 return 1;
1449 // Internal CMake link script support.
1450 else if (args[1] == "cmake_link_script" && args.size() >= 3)
1452 return cmake::ExecuteLinkScript(args);
1455 // Internal CMake unimplemented feature notification.
1456 else if (args[1] == "cmake_unimplemented_variable")
1458 std::cerr << "Feature not implemented for this platform.";
1459 if(args.size() == 3)
1461 std::cerr << " Variable " << args[2] << " is not set.";
1463 std::cerr << std::endl;
1464 return 1;
1466 else if (args[1] == "vs_link_exe")
1468 return cmake::VisualStudioLink(args, 1);
1470 else if (args[1] == "vs_link_dll")
1472 return cmake::VisualStudioLink(args, 2);
1474 #ifdef CMAKE_BUILD_WITH_CMAKE
1475 // Internal CMake color makefile support.
1476 else if (args[1] == "cmake_echo_color")
1478 return cmake::ExecuteEchoColor(args);
1480 #endif
1482 // Tar files
1483 else if (args[1] == "tar" && args.size() > 3)
1485 std::string flags = args[2];
1486 std::string outFile = args[3];
1487 std::vector<cmStdString> files;
1488 for (std::string::size_type cc = 4; cc < args.size(); cc ++)
1490 files.push_back(args[cc]);
1492 bool gzip = false;
1493 bool verbose = false;
1494 if ( flags.find_first_of('z') != flags.npos )
1496 gzip = true;
1498 if ( flags.find_first_of('v') != flags.npos )
1500 verbose = true;
1503 if ( flags.find_first_of('t') != flags.npos )
1505 if ( !cmSystemTools::ListTar(outFile.c_str(), files, gzip, verbose) )
1507 cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
1508 return 1;
1511 else if ( flags.find_first_of('c') != flags.npos )
1513 if ( !cmSystemTools::CreateTar(
1514 outFile.c_str(), files, gzip, verbose) )
1516 cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
1517 return 1;
1520 else if ( flags.find_first_of('x') != flags.npos )
1522 if ( !cmSystemTools::ExtractTar(
1523 outFile.c_str(), files, gzip, verbose) )
1525 cmSystemTools::Error("Problem extracting tar: ", outFile.c_str());
1526 return 1;
1529 return 0;
1532 #if defined(CMAKE_BUILD_WITH_CMAKE)
1533 // Internal CMake Fortran module support.
1534 else if (args[1] == "cmake_copy_f90_mod" && args.size() >= 4)
1536 return cmDependsFortran::CopyModule(args)? 0 : 1;
1538 #endif
1540 #if defined(_WIN32) && !defined(__CYGWIN__)
1541 // Write registry value
1542 else if (args[1] == "write_regv" && args.size() > 3)
1544 return cmSystemTools::WriteRegistryValue(args[2].c_str(),
1545 args[3].c_str()) ? 0 : 1;
1548 // Delete registry value
1549 else if (args[1] == "delete_regv" && args.size() > 2)
1551 return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
1553 // Remove file
1554 else if (args[1] == "comspec" && args.size() > 2)
1556 unsigned int cc;
1557 std::string command = args[2];
1558 for ( cc = 3; cc < args.size(); cc ++ )
1560 command += " " + args[cc];
1562 return cmWin32ProcessExecution::Windows9xHack(command.c_str());
1564 #endif
1567 ::CMakeCommandUsage(args[0].c_str());
1568 return 1;
1571 void cmake::AddExtraGenerator(const char* name,
1572 CreateExtraGeneratorFunctionType newFunction)
1574 cmExternalMakefileProjectGenerator* extraGenerator = newFunction();
1575 const std::vector<std::string>& supportedGlobalGenerators =
1576 extraGenerator->GetSupportedGlobalGenerators();
1578 for(std::vector<std::string>::const_iterator
1579 it = supportedGlobalGenerators.begin();
1580 it != supportedGlobalGenerators.end();
1581 ++it )
1583 std::string fullName = cmExternalMakefileProjectGenerator::
1584 CreateFullGeneratorName(it->c_str(), name);
1585 this->ExtraGenerators[fullName.c_str()] = newFunction;
1587 delete extraGenerator;
1590 void cmake::AddDefaultExtraGenerators()
1592 #if defined(CMAKE_BUILD_WITH_CMAKE)
1593 #if defined(_WIN32) && !defined(__CYGWIN__)
1594 // e.g. kdevelop4 ?
1595 #endif
1597 #if !defined(__CYGWIN__)
1598 this->AddExtraGenerator(cmExtraCodeBlocksGenerator::GetActualName(),
1599 &cmExtraCodeBlocksGenerator::New);
1600 #endif
1602 #ifdef CMAKE_USE_ECLIPSE
1603 this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(),
1604 &cmExtraEclipseCDT4Generator::New);
1605 #endif
1607 #ifdef CMAKE_USE_KDEVELOP
1608 this->AddExtraGenerator(cmGlobalKdevelopGenerator::GetActualName(),
1609 &cmGlobalKdevelopGenerator::New);
1610 // for kdevelop also add the generator with just the name of the
1611 // extra generator, since it was this way since cmake 2.2
1612 this->ExtraGenerators[cmGlobalKdevelopGenerator::GetActualName()]
1613 = &cmGlobalKdevelopGenerator::New;
1614 #endif
1616 #endif
1620 //----------------------------------------------------------------------------
1621 void cmake::GetRegisteredGenerators(std::vector<std::string>& names)
1623 for(RegisteredGeneratorsMap::const_iterator i = this->Generators.begin();
1624 i != this->Generators.end(); ++i)
1626 names.push_back(i->first);
1628 for(RegisteredExtraGeneratorsMap::const_iterator
1629 i = this->ExtraGenerators.begin();
1630 i != this->ExtraGenerators.end(); ++i)
1632 names.push_back(i->first);
1636 cmGlobalGenerator* cmake::CreateGlobalGenerator(const char* name)
1638 cmGlobalGenerator* generator = 0;
1639 cmExternalMakefileProjectGenerator* extraGenerator = 0;
1640 RegisteredGeneratorsMap::const_iterator genIt = this->Generators.find(name);
1641 if(genIt == this->Generators.end())
1643 RegisteredExtraGeneratorsMap::const_iterator extraGenIt =
1644 this->ExtraGenerators.find(name);
1645 if (extraGenIt == this->ExtraGenerators.end())
1647 return 0;
1649 extraGenerator = (extraGenIt->second)();
1650 genIt=this->Generators.find(extraGenerator->GetGlobalGeneratorName(name));
1651 if(genIt == this->Generators.end())
1653 delete extraGenerator;
1654 return 0;
1658 generator = (genIt->second)();
1659 generator->SetCMakeInstance(this);
1660 generator->SetExternalMakefileProjectGenerator(extraGenerator);
1661 return generator;
1664 void cmake::SetHomeDirectory(const char* dir)
1666 this->cmHomeDirectory = dir;
1667 cmSystemTools::ConvertToUnixSlashes(this->cmHomeDirectory);
1670 void cmake::SetHomeOutputDirectory(const char* lib)
1672 this->HomeOutputDirectory = lib;
1673 cmSystemTools::ConvertToUnixSlashes(this->HomeOutputDirectory);
1676 void cmake::SetGlobalGenerator(cmGlobalGenerator *gg)
1678 if(!gg)
1680 cmSystemTools::Error("Error SetGlobalGenerator called with null");
1681 return;
1683 // delete the old generator
1684 if (this->GlobalGenerator)
1686 delete this->GlobalGenerator;
1687 // restore the original environment variables CXX and CC
1688 // Restor CC
1689 std::string env = "CC=";
1690 if(this->CCEnvironment.size())
1692 env += this->CCEnvironment;
1694 cmSystemTools::PutEnv(env.c_str());
1695 env = "CXX=";
1696 if(this->CXXEnvironment.size())
1698 env += this->CXXEnvironment;
1700 cmSystemTools::PutEnv(env.c_str());
1703 // set the new
1704 this->GlobalGenerator = gg;
1706 // set the global flag for unix style paths on cmSystemTools as soon as
1707 // the generator is set. This allows gmake to be used on windows.
1708 cmSystemTools::SetForceUnixPaths
1709 (this->GlobalGenerator->GetForceUnixPaths());
1711 // Save the environment variables CXX and CC
1712 const char* cxx = getenv("CXX");
1713 const char* cc = getenv("CC");
1714 if(cxx)
1716 this->CXXEnvironment = cxx;
1718 else
1720 this->CXXEnvironment = "";
1722 if(cc)
1724 this->CCEnvironment = cc;
1726 else
1728 this->CCEnvironment = "";
1730 // set the cmake instance just to be sure
1731 gg->SetCMakeInstance(this);
1734 int cmake::DoPreConfigureChecks()
1736 // Make sure the Start directory contains a CMakeLists.txt file.
1737 std::string srcList = this->GetHomeDirectory();
1738 srcList += "/CMakeLists.txt";
1739 if(!cmSystemTools::FileExists(srcList.c_str()))
1741 cmOStringStream err;
1742 if(cmSystemTools::FileIsDirectory(this->GetHomeDirectory()))
1744 err << "The source directory \"" << this->GetHomeDirectory()
1745 << "\" does not appear to contain CMakeLists.txt.\n";
1747 else if(cmSystemTools::FileExists(this->GetHomeDirectory()))
1749 err << "The source directory \"" << this->GetHomeDirectory()
1750 << "\" is a file, not a directory.\n";
1752 else
1754 err << "The source directory \"" << this->GetHomeDirectory()
1755 << "\" does not exist.\n";
1757 err << "Specify --help for usage, or press the help button on the CMake "
1758 "GUI.";
1759 cmSystemTools::Error(err.str().c_str());
1760 return -2;
1763 // do a sanity check on some values
1764 if(this->CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY"))
1766 std::string cacheStart =
1767 this->CacheManager->GetCacheValue("CMAKE_HOME_DIRECTORY");
1768 cacheStart += "/CMakeLists.txt";
1769 std::string currentStart = this->GetHomeDirectory();
1770 currentStart += "/CMakeLists.txt";
1771 if(!cmSystemTools::SameFile(cacheStart.c_str(), currentStart.c_str()))
1773 std::string message = "The source \"";
1774 message += currentStart;
1775 message += "\" does not match the source \"";
1776 message += cacheStart;
1777 message += "\" used to generate cache. ";
1778 message += "Re-run cmake with a different source directory.";
1779 cmSystemTools::Error(message.c_str());
1780 return -2;
1783 else
1785 return 0;
1787 return 1;
1789 struct SaveCacheEntry
1791 std::string key;
1792 std::string value;
1793 std::string help;
1794 cmCacheManager::CacheEntryType type;
1797 int cmake::HandleDeleteCacheVariables(const char* var)
1799 std::vector<std::string> argsSplit;
1800 cmSystemTools::ExpandListArgument(std::string(var), argsSplit);
1801 // erase the property to avoid infinite recursion
1802 this->SetProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", "");
1804 cmCacheManager::CacheIterator ci = this->CacheManager->NewIterator();
1805 std::vector<SaveCacheEntry> saved;
1806 cmOStringStream warning;
1807 warning
1808 << "You have changed variables that require your cache to be deleted.\n"
1809 << "Configure will be re-run and you may have to reset some variables.\n"
1810 << "The following variables have changed:\n";
1811 for(std::vector<std::string>::iterator i = argsSplit.begin();
1812 i != argsSplit.end(); ++i)
1814 SaveCacheEntry save;
1815 save.key = *i;
1816 warning << *i << "= ";
1817 i++;
1818 save.value = *i;
1819 warning << *i << "\n";
1820 if(ci.Find(save.key.c_str()))
1822 save.type = ci.GetType();
1823 save.help = ci.GetProperty("HELPSTRING");
1825 saved.push_back(save);
1828 // remove the cache
1829 this->CacheManager->DeleteCache(this->GetStartOutputDirectory());
1830 // load the empty cache
1831 this->LoadCache();
1832 // restore the changed compilers
1833 for(std::vector<SaveCacheEntry>::iterator i = saved.begin();
1834 i != saved.end(); ++i)
1836 this->AddCacheEntry(i->key.c_str(), i->value.c_str(),
1837 i->help.c_str(), i->type);
1839 cmSystemTools::Message(warning.str().c_str());
1840 // avoid reconfigure if there were errors
1841 if(!cmSystemTools::GetErrorOccuredFlag())
1843 // re-run configure
1844 return this->Configure();
1846 return 0;
1849 int cmake::Configure()
1851 int ret = this->ActualConfigure();
1852 const char* delCacheVars =
1853 this->GetProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_");
1854 if(delCacheVars && delCacheVars[0] != 0)
1856 return this->HandleDeleteCacheVariables(delCacheVars);
1858 return ret;
1862 int cmake::ActualConfigure()
1864 // Construct right now our path conversion table before it's too late:
1865 this->UpdateConversionPathTable();
1866 this->CleanupCommandsAndMacros();
1868 int res = 0;
1869 if ( !this->ScriptMode )
1871 res = this->DoPreConfigureChecks();
1873 if ( res < 0 )
1875 return -2;
1877 if ( !res )
1879 this->CacheManager->AddCacheEntry
1880 ("CMAKE_HOME_DIRECTORY",
1881 this->GetHomeDirectory(),
1882 "Start directory with the top level CMakeLists.txt file for this "
1883 "project",
1884 cmCacheManager::INTERNAL);
1887 // set the default BACKWARDS compatibility to the current version
1888 if(!this->CacheManager->GetCacheValue("CMAKE_BACKWARDS_COMPATIBILITY"))
1890 char ver[256];
1891 sprintf(ver,"%i.%i",cmVersion::GetMajorVersion(),
1892 cmVersion::GetMinorVersion());
1893 this->CacheManager->AddCacheEntry
1894 ("CMAKE_BACKWARDS_COMPATIBILITY",ver,
1895 "For backwards compatibility, what version of CMake commands and "
1896 "syntax should this version of CMake allow.",
1897 cmCacheManager::STRING);
1900 // no generator specified on the command line
1901 if(!this->GlobalGenerator)
1903 const char* genName =
1904 this->CacheManager->GetCacheValue("CMAKE_GENERATOR");
1905 const char* extraGenName =
1906 this->CacheManager->GetCacheValue("CMAKE_EXTRA_GENERATOR");
1907 if(genName)
1909 std::string fullName = cmExternalMakefileProjectGenerator::
1910 CreateFullGeneratorName(genName, extraGenName);
1911 this->GlobalGenerator = this->CreateGlobalGenerator(fullName.c_str());
1913 if(this->GlobalGenerator)
1915 // set the global flag for unix style paths on cmSystemTools as
1916 // soon as the generator is set. This allows gmake to be used
1917 // on windows.
1918 cmSystemTools::SetForceUnixPaths
1919 (this->GlobalGenerator->GetForceUnixPaths());
1921 else
1923 #if defined(__BORLANDC__) && defined(_WIN32)
1924 this->SetGlobalGenerator(new cmGlobalBorlandMakefileGenerator);
1925 #elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
1926 std::string installedCompiler;
1927 std::string mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
1928 "\\VisualStudio\\8.0\\Setup;Dbghelp_path]";
1929 cmSystemTools::ExpandRegistryValues(mp);
1930 if (!(mp == "/registry"))
1932 installedCompiler = "Visual Studio 8 2005";
1934 else
1936 mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
1937 "\\VisualStudio\\7.1;InstallDir]";
1938 cmSystemTools::ExpandRegistryValues(mp);
1939 if (!(mp == "/registry"))
1941 installedCompiler = "Visual Studio 7 .NET 2003";
1943 else
1945 mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft"
1946 "\\VisualStudio\\7.0;InstallDir]";
1947 cmSystemTools::ExpandRegistryValues(mp);
1948 if (!(mp == "/registry"))
1950 installedCompiler = "Visual Studio 7";
1952 else
1954 installedCompiler = "Visual Studio 6";
1958 cmGlobalGenerator* gen
1959 = this->CreateGlobalGenerator(installedCompiler.c_str());
1960 if(!gen)
1962 gen = new cmGlobalNMakeMakefileGenerator;
1964 this->SetGlobalGenerator(gen);
1965 #else
1966 this->SetGlobalGenerator(new cmGlobalUnixMakefileGenerator3);
1967 #endif
1969 if(!this->GlobalGenerator)
1971 cmSystemTools::Error("Could not create generator");
1972 return -1;
1976 const char* genName = this->CacheManager->GetCacheValue("CMAKE_GENERATOR");
1977 if(genName)
1979 if(strcmp(this->GlobalGenerator->GetName(), genName) != 0)
1981 std::string message = "Error: generator : ";
1982 message += this->GlobalGenerator->GetName();
1983 message += "\nDoes not match the generator used previously: ";
1984 message += genName;
1985 message +=
1986 "\nEither remove the CMakeCache.txt file or choose a different"
1987 " binary directory.";
1988 cmSystemTools::Error(message.c_str());
1989 return -2;
1992 if(!this->CacheManager->GetCacheValue("CMAKE_GENERATOR"))
1994 this->CacheManager->AddCacheEntry("CMAKE_GENERATOR",
1995 this->GlobalGenerator->GetName(),
1996 "Name of generator.",
1997 cmCacheManager::INTERNAL);
1998 this->CacheManager->AddCacheEntry("CMAKE_EXTRA_GENERATOR",
1999 this->GlobalGenerator->GetExtraGeneratorName(),
2000 "Name of external makefile project generator.",
2001 cmCacheManager::INTERNAL);
2004 // reset any system configuration information, except for when we are
2005 // InTryCompile. With TryCompile the system info is taken from the parent's
2006 // info to save time
2007 if (!this->InTryCompile)
2009 this->GlobalGenerator->ClearEnabledLanguages();
2012 this->CleanupWrittenFiles();
2014 // Truncate log files
2015 if (!this->InTryCompile)
2017 this->TruncateOutputLog("CMakeOutput.log");
2018 this->TruncateOutputLog("CMakeError.log");
2021 // actually do the configure
2022 this->GlobalGenerator->Configure();
2023 // Before saving the cache
2024 // if the project did not define one of the entries below, add them now
2025 // so users can edit the values in the cache:
2026 // LIBRARY_OUTPUT_PATH
2027 // EXECUTABLE_OUTPUT_PATH
2028 if(!this->CacheManager->GetCacheValue("LIBRARY_OUTPUT_PATH"))
2030 this->CacheManager->AddCacheEntry
2031 ("LIBRARY_OUTPUT_PATH", "",
2032 "Single output directory for building all libraries.",
2033 cmCacheManager::PATH);
2035 if(!this->CacheManager->GetCacheValue("EXECUTABLE_OUTPUT_PATH"))
2037 this->CacheManager->AddCacheEntry
2038 ("EXECUTABLE_OUTPUT_PATH", "",
2039 "Single output directory for building all executables.",
2040 cmCacheManager::PATH);
2042 if(!this->CacheManager->GetCacheValue("CMAKE_USE_RELATIVE_PATHS"))
2044 this->CacheManager->AddCacheEntry
2045 ("CMAKE_USE_RELATIVE_PATHS", false,
2046 "If true, cmake will use relative paths in makefiles and projects.");
2047 cmCacheManager::CacheIterator it =
2048 this->CacheManager->GetCacheIterator("CMAKE_USE_RELATIVE_PATHS");
2049 if ( !it.PropertyExists("ADVANCED") )
2051 it.SetProperty("ADVANCED", "1");
2055 if(cmSystemTools::GetFatalErrorOccured() &&
2056 (!this->CacheManager->GetCacheValue("CMAKE_MAKE_PROGRAM") ||
2057 cmSystemTools::IsOff(this->CacheManager->
2058 GetCacheValue("CMAKE_MAKE_PROGRAM"))))
2060 // We must have a bad generator selection. Wipe the cache entry so the
2061 // user can select another.
2062 this->CacheManager->RemoveCacheEntry("CMAKE_GENERATOR");
2063 this->CacheManager->RemoveCacheEntry("CMAKE_EXTRA_GENERATOR");
2065 // only save the cache if there were no fatal errors
2066 if ( !this->ScriptMode )
2068 this->CacheManager->SaveCache(this->GetHomeOutputDirectory());
2070 if ( !this->GraphVizFile.empty() )
2072 std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
2073 this->GenerateGraphViz(this->GraphVizFile.c_str());
2075 if(cmSystemTools::GetErrorOccuredFlag())
2077 return -1;
2079 return 0;
2082 bool cmake::CacheVersionMatches()
2084 const char* majv =
2085 this->CacheManager->GetCacheValue("CMAKE_CACHE_MAJOR_VERSION");
2086 const char* minv =
2087 this->CacheManager->GetCacheValue("CMAKE_CACHE_MINOR_VERSION");
2088 const char* relv =
2089 this->CacheManager->GetCacheValue("CMAKE_CACHE_RELEASE_VERSION");
2090 bool cacheSameCMake = false;
2091 if(majv &&
2092 atoi(majv) == static_cast<int>(cmVersion::GetMajorVersion())
2093 && minv &&
2094 atoi(minv) == static_cast<int>(cmVersion::GetMinorVersion())
2095 && relv && (strcmp(relv, cmVersion::GetReleaseVersion().c_str()) == 0))
2097 cacheSameCMake = true;
2099 return cacheSameCMake;
2102 void cmake::PreLoadCMakeFiles()
2104 std::string pre_load = this->GetHomeDirectory();
2105 if ( pre_load.size() > 0 )
2107 pre_load += "/PreLoad.cmake";
2108 if ( cmSystemTools::FileExists(pre_load.c_str()) )
2110 this->ReadListFile(pre_load.c_str());
2113 pre_load = this->GetHomeOutputDirectory();
2114 if ( pre_load.size() > 0 )
2116 pre_load += "/PreLoad.cmake";
2117 if ( cmSystemTools::FileExists(pre_load.c_str()) )
2119 this->ReadListFile(pre_load.c_str());
2124 // handle a command line invocation
2125 int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
2127 // Process the arguments
2128 this->SetArgs(args);
2129 if(cmSystemTools::GetErrorOccuredFlag())
2131 return -1;
2134 // If we are given a stamp file check if it is really out of date.
2135 if(!this->CheckStampFile.empty() &&
2136 cmakeCheckStampFile(this->CheckStampFile.c_str()))
2138 return 0;
2141 // set the cmake command
2142 this->CMakeCommand = args[0];
2144 if ( !this->ScriptMode )
2146 // load the cache
2147 if(this->LoadCache() < 0)
2149 cmSystemTools::Error("Error executing cmake::LoadCache(). Aborting.\n");
2150 return -1;
2153 else
2155 this->AddCMakePaths();
2158 // Add any cache args
2159 if ( !this->SetCacheArgs(args) )
2161 cmSystemTools::Error("Problem processing arguments. Aborting.\n");
2162 return -1;
2165 // In script mode we terminate after running the script.
2166 if(this->ScriptMode)
2168 if(cmSystemTools::GetErrorOccuredFlag())
2170 return -1;
2172 else
2174 return 0;
2178 this->PreLoadCMakeFiles();
2180 std::string systemFile = this->GetHomeOutputDirectory();
2181 systemFile += "/CMakeSystem.cmake";
2183 if ( noconfigure )
2185 return 0;
2188 // now run the global generate
2189 // Check the state of the build system to see if we need to regenerate.
2190 if(!this->CheckBuildSystem())
2192 return 0;
2195 // If we are doing global generate, we better set start and start
2196 // output directory to the root of the project.
2197 std::string oldstartdir = this->GetStartDirectory();
2198 std::string oldstartoutputdir = this->GetStartOutputDirectory();
2199 this->SetStartDirectory(this->GetHomeDirectory());
2200 this->SetStartOutputDirectory(this->GetHomeOutputDirectory());
2201 int ret = this->Configure();
2202 if (ret || this->ScriptMode)
2204 #if defined(CMAKE_HAVE_VS_GENERATORS)
2205 if(!this->VSSolutionFile.empty() && this->GlobalGenerator)
2207 // CMake is running to regenerate a Visual Studio build tree
2208 // during a build from the VS IDE. The build files cannot be
2209 // regenerated, so we should stop the build.
2210 cmSystemTools::Message(
2211 "CMake Configure step failed. "
2212 "Build files cannot be regenerated correctly. "
2213 "Attempting to stop IDE build.");
2214 cmGlobalVisualStudioGenerator* gg =
2215 static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
2216 gg->CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
2217 this->VSSolutionFile.c_str());
2219 #endif
2220 return ret;
2222 ret = this->Generate();
2223 std::string message = "Build files have been written to: ";
2224 message += this->GetHomeOutputDirectory();
2225 this->UpdateProgress(message.c_str(), -1);
2226 if(ret)
2228 return ret;
2230 this->SetStartDirectory(oldstartdir.c_str());
2231 this->SetStartOutputDirectory(oldstartoutputdir.c_str());
2233 return ret;
2236 int cmake::Generate()
2238 if(!this->GlobalGenerator)
2240 return -1;
2242 this->GlobalGenerator->Generate();
2243 if(cmSystemTools::GetErrorOccuredFlag())
2245 return -1;
2247 if (this->GetProperty("REPORT_UNDEFINED_PROPERTIES"))
2249 this->ReportUndefinedPropertyAccesses
2250 (this->GetProperty("REPORT_UNDEFINED_PROPERTIES"));
2252 return 0;
2255 void cmake::AddCacheEntry(const char* key, const char* value,
2256 const char* helpString,
2257 int type)
2259 this->CacheManager->AddCacheEntry(key, value,
2260 helpString,
2261 cmCacheManager::CacheEntryType(type));
2264 const char* cmake::GetCacheDefinition(const char* name) const
2266 return this->CacheManager->GetCacheValue(name);
2269 int cmake::DumpDocumentationToFile(std::ostream& f)
2271 #ifdef CMAKE_BUILD_WITH_CMAKE
2272 // Loop over all registered commands and print out documentation
2273 const char *name;
2274 const char *terse;
2275 const char *full;
2276 char tmp[1024];
2277 sprintf(tmp,"Version %d.%d (%s)", cmVersion::GetMajorVersion(),
2278 cmVersion::GetMinorVersion(),
2279 cmVersion::GetReleaseVersion().c_str());
2280 f << "<html>\n";
2281 f << "<h1>Documentation for commands of CMake " << tmp << "</h1>\n";
2282 f << "<ul>\n";
2283 for(RegisteredCommandsMap::iterator j = this->Commands.begin();
2284 j != this->Commands.end(); ++j)
2286 name = (*j).second->GetName();
2287 terse = (*j).second->GetTerseDocumentation();
2288 full = (*j).second->GetFullDocumentation();
2289 f << "<li><b>" << name << "</b> - " << terse << std::endl
2290 << "<br><i>Usage:</i> " << full << "</li>" << std::endl << std::endl;
2292 f << "</ul></html>\n";
2293 #else
2294 (void)f;
2295 #endif
2296 return 1;
2299 void cmake::AddDefaultCommands()
2301 std::list<cmCommand*> commands;
2302 GetBootstrapCommands(commands);
2303 GetPredefinedCommands(commands);
2304 for(std::list<cmCommand*>::iterator i = commands.begin();
2305 i != commands.end(); ++i)
2307 this->AddCommand(*i);
2311 void cmake::AddDefaultGenerators()
2313 #if defined(_WIN32) && !defined(__CYGWIN__)
2314 # if !defined(CMAKE_BOOT_MINGW)
2315 this->Generators[cmGlobalVisualStudio6Generator::GetActualName()] =
2316 &cmGlobalVisualStudio6Generator::New;
2317 this->Generators[cmGlobalVisualStudio7Generator::GetActualName()] =
2318 &cmGlobalVisualStudio7Generator::New;
2319 this->Generators[cmGlobalVisualStudio71Generator::GetActualName()] =
2320 &cmGlobalVisualStudio71Generator::New;
2321 this->Generators[cmGlobalVisualStudio8Generator::GetActualName()] =
2322 &cmGlobalVisualStudio8Generator::New;
2323 this->Generators[cmGlobalVisualStudio9Generator::GetActualName()] =
2324 &cmGlobalVisualStudio9Generator::New;
2325 this->Generators[cmGlobalVisualStudio9Win64Generator::GetActualName()] =
2326 &cmGlobalVisualStudio9Win64Generator::New;
2327 this->Generators[cmGlobalVisualStudio8Win64Generator::GetActualName()] =
2328 &cmGlobalVisualStudio8Win64Generator::New;
2329 this->Generators[cmGlobalBorlandMakefileGenerator::GetActualName()] =
2330 &cmGlobalBorlandMakefileGenerator::New;
2331 this->Generators[cmGlobalNMakeMakefileGenerator::GetActualName()] =
2332 &cmGlobalNMakeMakefileGenerator::New;
2333 this->Generators[cmGlobalWatcomWMakeGenerator::GetActualName()] =
2334 &cmGlobalWatcomWMakeGenerator::New;
2335 # endif
2336 this->Generators[cmGlobalMSYSMakefileGenerator::GetActualName()] =
2337 &cmGlobalMSYSMakefileGenerator::New;
2338 this->Generators[cmGlobalMinGWMakefileGenerator::GetActualName()] =
2339 &cmGlobalMinGWMakefileGenerator::New;
2340 #endif
2341 this->Generators[cmGlobalUnixMakefileGenerator3::GetActualName()] =
2342 &cmGlobalUnixMakefileGenerator3::New;
2343 #ifdef CMAKE_USE_XCODE
2344 this->Generators[cmGlobalXCodeGenerator::GetActualName()] =
2345 &cmGlobalXCodeGenerator::New;
2346 #endif
2349 int cmake::LoadCache()
2351 // could we not read the cache
2352 if (!this->CacheManager->LoadCache(this->GetHomeOutputDirectory()))
2354 // if it does exist, but isn;t readable then warn the user
2355 std::string cacheFile = this->GetHomeOutputDirectory();
2356 cacheFile += "/CMakeCache.txt";
2357 if(cmSystemTools::FileExists(cacheFile.c_str()))
2359 cmSystemTools::Error(
2360 "There is a CMakeCache.txt file for the current binary tree but "
2361 "cmake does not have permission to read it. Please check the "
2362 "permissions of the directory you are trying to run CMake on.");
2363 return -1;
2367 if (this->CMakeCommand.size() < 2)
2369 cmSystemTools::Error(
2370 "cmake command was not specified prior to loading the cache in "
2371 "cmake.cxx");
2372 return -1;
2375 // setup CMAKE_ROOT and CMAKE_COMMAND
2376 if(!this->AddCMakePaths())
2378 return -3;
2381 // set the default BACKWARDS compatibility to the current version
2382 if(!this->CacheManager->GetCacheValue("CMAKE_BACKWARDS_COMPATIBILITY"))
2384 char ver[256];
2385 sprintf(ver,"%i.%i",cmVersion::GetMajorVersion(),
2386 cmVersion::GetMinorVersion());
2387 this->CacheManager->AddCacheEntry
2388 ("CMAKE_BACKWARDS_COMPATIBILITY",ver,
2389 "For backwards compatibility, what version of CMake commands and "
2390 "syntax should this version of CMake allow.",
2391 cmCacheManager::STRING);
2394 return 0;
2397 void cmake::SetProgressCallback(ProgressCallbackType f, void *cd)
2399 this->ProgressCallback = f;
2400 this->ProgressCallbackClientData = cd;
2403 void cmake::UpdateProgress(const char *msg, float prog)
2405 if(this->ProgressCallback && !this->InTryCompile)
2407 (*this->ProgressCallback)(msg, prog, this->ProgressCallbackClientData);
2408 return;
2412 void cmake::GetCommandDocumentation(std::vector<cmDocumentationEntry>& v,
2413 bool withCurrentCommands,
2414 bool withCompatCommands) const
2416 for(RegisteredCommandsMap::const_iterator j = this->Commands.begin();
2417 j != this->Commands.end(); ++j)
2419 if ((( withCompatCommands == false) && ( (*j).second->IsDiscouraged()))
2420 || ((withCurrentCommands == false) && (!(*j).second->IsDiscouraged())))
2422 continue;
2425 cmDocumentationEntry e((*j).second->GetName(),
2426 (*j).second->GetTerseDocumentation(),
2427 (*j).second->GetFullDocumentation());
2428 v.push_back(e);
2432 void cmake::GetPropertiesDocumentation(std::map<std::string,
2433 cmDocumentationSection *>& v)
2435 // loop over the properties and put them into the doc structure
2436 std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::iterator i;
2437 i = this->PropertyDefinitions.begin();
2438 for (;i != this->PropertyDefinitions.end(); ++i)
2440 i->second.GetPropertiesDocumentation(v);
2444 void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v)
2446 for(RegisteredGeneratorsMap::const_iterator i = this->Generators.begin();
2447 i != this->Generators.end(); ++i)
2449 cmDocumentationEntry e;
2450 cmGlobalGenerator* generator = (i->second)();
2451 generator->GetDocumentation(e);
2452 delete generator;
2453 v.push_back(e);
2455 for(RegisteredExtraGeneratorsMap::const_iterator
2456 i = this->ExtraGenerators.begin(); i != this->ExtraGenerators.end(); ++i)
2458 cmDocumentationEntry e;
2459 cmExternalMakefileProjectGenerator* generator = (i->second)();
2460 generator->GetDocumentation(e, i->first.c_str());
2461 e.Name = i->first;
2462 delete generator;
2463 v.push_back(e);
2467 void cmake::AddWrittenFile(const char* file)
2469 this->WrittenFiles.insert(file);
2472 bool cmake::HasWrittenFile(const char* file)
2474 return this->WrittenFiles.find(file) != this->WrittenFiles.end();
2477 void cmake::CleanupWrittenFiles()
2479 this->WrittenFiles.clear();
2482 void cmake::UpdateConversionPathTable()
2484 // Update the path conversion table with any specified file:
2485 const char* tablepath =
2486 this->CacheManager->GetCacheValue("CMAKE_PATH_TRANSLATION_FILE");
2488 if(tablepath)
2490 std::ifstream table( tablepath );
2491 if(!table)
2493 cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to ", tablepath,
2494 ". CMake can not open file.");
2495 cmSystemTools::ReportLastSystemError("CMake can not open file.");
2497 else
2499 std::string a, b;
2500 while(!table.eof())
2502 // two entries per line
2503 table >> a; table >> b;
2504 cmSystemTools::AddTranslationPath( a.c_str(), b.c_str());
2510 //----------------------------------------------------------------------------
2511 int cmake::CheckBuildSystem()
2513 // We do not need to rerun CMake. Check dependency integrity. Use
2514 // the make system's VERBOSE environment variable to enable verbose
2515 // output.
2516 bool verbose = cmSystemTools::GetEnv("VERBOSE") != 0;
2518 // This method will check the integrity of the build system if the
2519 // option was given on the command line. It reads the given file to
2520 // determine whether CMake should rerun.
2522 // If no file is provided for the check, we have to rerun.
2523 if(this->CheckBuildSystemArgument.size() == 0)
2525 if(verbose)
2527 cmOStringStream msg;
2528 msg << "Re-run cmake no build system arguments\n";
2529 cmSystemTools::Stdout(msg.str().c_str());
2531 return 1;
2534 // If the file provided does not exist, we have to rerun.
2535 if(!cmSystemTools::FileExists(this->CheckBuildSystemArgument.c_str()))
2537 if(verbose)
2539 cmOStringStream msg;
2540 msg << "Re-run cmake missing file: "
2541 << this->CheckBuildSystemArgument.c_str() << "\n";
2542 cmSystemTools::Stdout(msg.str().c_str());
2544 return 1;
2547 // Read the rerun check file and use it to decide whether to do the
2548 // global generate.
2549 cmake cm;
2550 cmGlobalGenerator gg;
2551 gg.SetCMakeInstance(&cm);
2552 std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
2553 lg->SetGlobalGenerator(&gg);
2554 cmMakefile* mf = lg->GetMakefile();
2555 if(!mf->ReadListFile(0, this->CheckBuildSystemArgument.c_str()) ||
2556 cmSystemTools::GetErrorOccuredFlag())
2558 if(verbose)
2560 cmOStringStream msg;
2561 msg << "Re-run cmake error reading : "
2562 << this->CheckBuildSystemArgument.c_str() << "\n";
2563 cmSystemTools::Stdout(msg.str().c_str());
2565 // There was an error reading the file. Just rerun.
2566 return 1;
2569 if(this->ClearBuildSystem)
2571 // Get the generator used for this build system.
2572 const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
2573 if(!genName || genName[0] == '\0')
2575 genName = "Unix Makefiles";
2578 // Create the generator and use it to clear the dependencies.
2579 std::auto_ptr<cmGlobalGenerator>
2580 ggd(this->CreateGlobalGenerator(genName));
2581 if(ggd.get())
2583 std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
2584 lgd->SetGlobalGenerator(ggd.get());
2585 lgd->ClearDependencies(mf, verbose);
2589 // Get the set of dependencies and outputs.
2590 std::vector<std::string> depends;
2591 std::vector<std::string> outputs;
2592 const char* dependsStr = mf->GetDefinition("CMAKE_MAKEFILE_DEPENDS");
2593 const char* outputsStr = mf->GetDefinition("CMAKE_MAKEFILE_OUTPUTS");
2594 if(dependsStr && outputsStr)
2596 cmSystemTools::ExpandListArgument(dependsStr, depends);
2597 cmSystemTools::ExpandListArgument(outputsStr, outputs);
2599 if(depends.empty() || outputs.empty())
2601 // Not enough information was provided to do the test. Just rerun.
2602 if(verbose)
2604 cmOStringStream msg;
2605 msg << "Re-run cmake no CMAKE_MAKEFILE_DEPENDS "
2606 "or CMAKE_MAKEFILE_OUTPUTS :\n";
2607 cmSystemTools::Stdout(msg.str().c_str());
2609 return 1;
2612 // Find find the newest dependency.
2613 std::vector<std::string>::iterator dep = depends.begin();
2614 std::string dep_newest = *dep++;
2615 for(;dep != depends.end(); ++dep)
2617 int result = 0;
2618 if(this->FileComparison->FileTimeCompare(dep_newest.c_str(),
2619 dep->c_str(), &result))
2621 if(result < 0)
2623 dep_newest = *dep;
2626 else
2628 if(verbose)
2630 cmOStringStream msg;
2631 msg << "Re-run cmake: build system dependency is missing\n";
2632 cmSystemTools::Stdout(msg.str().c_str());
2634 return 1;
2638 // Find find the oldest output.
2639 std::vector<std::string>::iterator out = outputs.begin();
2640 std::string out_oldest = *out++;
2641 for(;out != outputs.end(); ++out)
2643 int result = 0;
2644 if(this->FileComparison->FileTimeCompare(out_oldest.c_str(),
2645 out->c_str(), &result))
2647 if(result > 0)
2649 out_oldest = *out;
2652 else
2654 if(verbose)
2656 cmOStringStream msg;
2657 msg << "Re-run cmake: build system output is missing\n";
2658 cmSystemTools::Stdout(msg.str().c_str());
2660 return 1;
2664 // If any output is older than any dependency then rerun.
2666 int result = 0;
2667 if(!this->FileComparison->FileTimeCompare(out_oldest.c_str(),
2668 dep_newest.c_str(),
2669 &result) ||
2670 result < 0)
2672 if(verbose)
2674 cmOStringStream msg;
2675 msg << "Re-run cmake file: " << out_oldest.c_str()
2676 << " older than: " << dep_newest.c_str() << "\n";
2677 cmSystemTools::Stdout(msg.str().c_str());
2679 return 1;
2683 // No need to rerun.
2684 return 0;
2687 //----------------------------------------------------------------------------
2688 void cmake::TruncateOutputLog(const char* fname)
2690 std::string fullPath = this->GetHomeOutputDirectory();
2691 fullPath += "/";
2692 fullPath += fname;
2693 struct stat st;
2694 if ( ::stat(fullPath.c_str(), &st) )
2696 return;
2698 if ( !this->CacheManager->GetCacheValue("CMAKE_CACHEFILE_DIR") )
2700 cmSystemTools::RemoveFile(fullPath.c_str());
2701 return;
2703 off_t fsize = st.st_size;
2704 const off_t maxFileSize = 50 * 1024;
2705 if ( fsize < maxFileSize )
2707 //TODO: truncate file
2708 return;
2712 inline std::string removeQuotes(const std::string& s)
2714 if(s[0] == '\"' && s[s.size()-1] == '\"')
2716 return s.substr(1, s.size()-2);
2718 return s;
2721 std::string cmake::FindCMakeProgram(const char* name) const
2723 std::string path;
2724 if ((name) && (*name))
2726 const cmMakefile* mf
2727 = this->GetGlobalGenerator()->GetLocalGenerators()[0]->GetMakefile();
2728 #ifdef CMAKE_BUILD_WITH_CMAKE
2729 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2730 path = removeQuotes(path);
2731 path = cmSystemTools::GetFilenamePath(path.c_str());
2732 path += "/";
2733 path += name;
2734 path += cmSystemTools::GetExecutableExtension();
2735 if(!cmSystemTools::FileExists(path.c_str()))
2737 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2738 path = cmSystemTools::GetFilenamePath(path.c_str());
2739 path += "/Debug/";
2740 path += name;
2741 path += cmSystemTools::GetExecutableExtension();
2743 if(!cmSystemTools::FileExists(path.c_str()))
2745 path = mf->GetRequiredDefinition("CMAKE_COMMAND");
2746 path = cmSystemTools::GetFilenamePath(path.c_str());
2747 path += "/Release/";
2748 path += name;
2749 path += cmSystemTools::GetExecutableExtension();
2751 #else
2752 // Only for bootstrap
2753 path += mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
2754 path += "/";
2755 path += name;
2756 path += cmSystemTools::GetExecutableExtension();
2757 #endif
2759 return path;
2762 const char* cmake::GetCTestCommand()
2764 if ( this->CTestCommand.empty() )
2766 this->CTestCommand = this->FindCMakeProgram("ctest");
2768 if ( this->CTestCommand.empty() )
2770 cmSystemTools::Error("Cannot find the CTest executable");
2771 this->CTestCommand = "CTEST-COMMAND-NOT-FOUND";
2773 return this->CTestCommand.c_str();
2776 const char* cmake::GetCPackCommand()
2778 if ( this->CPackCommand.empty() )
2780 this->CPackCommand = this->FindCMakeProgram("cpack");
2782 if ( this->CPackCommand.empty() )
2784 cmSystemTools::Error("Cannot find the CPack executable");
2785 this->CPackCommand = "CPACK-COMMAND-NOT-FOUND";
2787 return this->CPackCommand.c_str();
2790 void cmake::GenerateGraphViz(const char* fileName) const
2792 cmGeneratedFileStream str(fileName);
2793 if ( !str )
2795 return;
2797 cmake cm;
2798 cmGlobalGenerator ggi;
2799 ggi.SetCMakeInstance(&cm);
2800 std::auto_ptr<cmLocalGenerator> lg(ggi.CreateLocalGenerator());
2801 lg->SetGlobalGenerator(&ggi);
2802 cmMakefile *mf = lg->GetMakefile();
2804 std::string infile = this->GetHomeOutputDirectory();
2805 infile += "/CMakeGraphVizOptions.cmake";
2806 if ( !cmSystemTools::FileExists(infile.c_str()) )
2808 infile = this->GetHomeDirectory();
2809 infile += "/CMakeGraphVizOptions.cmake";
2810 if ( !cmSystemTools::FileExists(infile.c_str()) )
2812 infile = "";
2816 if ( !infile.empty() )
2818 if ( !mf->ReadListFile(0, infile.c_str()) )
2820 cmSystemTools::Error("Problem opening GraphViz options file: ",
2821 infile.c_str());
2822 return;
2824 std::cout << "Read GraphViz options file: " << infile.c_str()
2825 << std::endl;
2828 #define __set_if_not_set(var, value, cmakeDefinition) \
2829 const char* var = mf->GetDefinition(cmakeDefinition); \
2830 if ( !var ) \
2832 var = value; \
2834 __set_if_not_set(graphType, "digraph", "GRAPHVIZ_GRAPH_TYPE");
2835 __set_if_not_set(graphName, "GG", "GRAPHVIZ_GRAPH_NAME");
2836 __set_if_not_set(graphHeader, "node [\n fontsize = \"12\"\n];",
2837 "GRAPHVIZ_GRAPH_HEADER");
2838 __set_if_not_set(graphNodePrefix, "node", "GRAPHVIZ_NODE_PREFIX");
2839 const char* ignoreTargets = mf->GetDefinition("GRAPHVIZ_IGNORE_TARGETS");
2840 std::set<cmStdString> ignoreTargetsSet;
2841 if ( ignoreTargets )
2843 std::vector<std::string> ignoreTargetsVector;
2844 cmSystemTools::ExpandListArgument(ignoreTargets,ignoreTargetsVector);
2845 std::vector<std::string>::iterator itvIt;
2846 for ( itvIt = ignoreTargetsVector.begin();
2847 itvIt != ignoreTargetsVector.end();
2848 ++ itvIt )
2850 ignoreTargetsSet.insert(itvIt->c_str());
2854 str << graphType << " " << graphName << " {" << std::endl;
2855 str << graphHeader << std::endl;
2857 const cmGlobalGenerator* gg = this->GetGlobalGenerator();
2858 const std::vector<cmLocalGenerator*>& localGenerators =
2859 gg->GetLocalGenerators();
2860 std::vector<cmLocalGenerator*>::const_iterator lit;
2861 // for target deps
2862 // 1 - cmake target
2863 // 2 - external target
2864 // 0 - no deps
2865 std::map<cmStdString, int> targetDeps;
2866 std::map<cmStdString, const cmTarget*> targetPtrs;
2867 std::map<cmStdString, cmStdString> targetNamesNodes;
2868 int cnt = 0;
2869 // First pass get the list of all cmake targets
2870 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2872 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
2873 cmTargets::const_iterator tit;
2874 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
2876 const char* realTargetName = tit->first.c_str();
2877 if ( ignoreTargetsSet.find(realTargetName) != ignoreTargetsSet.end() )
2879 // Skip ignored targets
2880 continue;
2882 //std::cout << "Found target: " << tit->first.c_str() << std::endl;
2883 cmOStringStream ostr;
2884 ostr << graphNodePrefix << cnt++;
2885 targetNamesNodes[realTargetName] = ostr.str();
2886 targetPtrs[realTargetName] = &tit->second;
2889 // Ok, now find all the stuff we link to that is not in cmake
2890 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2892 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
2893 cmTargets::const_iterator tit;
2894 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
2896 const cmTarget::LinkLibraryVectorType* ll
2897 = &(tit->second.GetOriginalLinkLibraries());
2898 cmTarget::LinkLibraryVectorType::const_iterator llit;
2899 const char* realTargetName = tit->first.c_str();
2900 if ( ignoreTargetsSet.find(realTargetName) != ignoreTargetsSet.end() )
2902 // Skip ignored targets
2903 continue;
2905 if ( ll->size() > 0 )
2907 targetDeps[realTargetName] = 1;
2909 for ( llit = ll->begin(); llit != ll->end(); ++ llit )
2911 const char* libName = llit->first.c_str();
2912 std::map<cmStdString, cmStdString>::const_iterator tarIt
2913 = targetNamesNodes.find(libName);
2914 if ( ignoreTargetsSet.find(libName) != ignoreTargetsSet.end() )
2916 // Skip ignored targets
2917 continue;
2919 if ( tarIt == targetNamesNodes.end() )
2921 cmOStringStream ostr;
2922 ostr << graphNodePrefix << cnt++;
2923 targetDeps[libName] = 2;
2924 targetNamesNodes[libName] = ostr.str();
2925 //str << " \"" << ostr.c_str() << "\" [ label=\"" << libName
2926 //<< "\" shape=\"ellipse\"];" << std::endl;
2928 else
2930 std::map<cmStdString, int>::const_iterator depIt
2931 = targetDeps.find(libName);
2932 if ( depIt == targetDeps.end() )
2934 targetDeps[libName] = 1;
2941 // Write out nodes
2942 std::map<cmStdString, int>::const_iterator depIt;
2943 for ( depIt = targetDeps.begin(); depIt != targetDeps.end(); ++ depIt )
2945 const char* newTargetName = depIt->first.c_str();
2946 std::map<cmStdString, cmStdString>::const_iterator tarIt
2947 = targetNamesNodes.find(newTargetName);
2948 if ( tarIt == targetNamesNodes.end() )
2950 // We should not be here.
2951 std::cout << __LINE__ << " Cannot find library: " << newTargetName
2952 << " even though it was added in the previous pass" << std::endl;
2953 abort();
2956 str << " \"" << tarIt->second.c_str() << "\" [ label=\""
2957 << newTargetName << "\" shape=\"";
2958 if ( depIt->second == 1 )
2960 std::map<cmStdString, const cmTarget*>::const_iterator tarTypeIt =
2961 targetPtrs.find(newTargetName);
2962 if ( tarTypeIt == targetPtrs.end() )
2964 // We should not be here.
2965 std::cout << __LINE__ << " Cannot find library: " << newTargetName
2966 << " even though it was added in the previous pass" << std::endl;
2967 abort();
2969 const cmTarget* tg = tarTypeIt->second;
2970 switch ( tg->GetType() )
2972 case cmTarget::EXECUTABLE:
2973 str << "house";
2974 break;
2975 case cmTarget::STATIC_LIBRARY:
2976 str << "diamond";
2977 break;
2978 case cmTarget::SHARED_LIBRARY:
2979 str << "polygon";
2980 break;
2981 case cmTarget::MODULE_LIBRARY:
2982 str << "octagon";
2983 break;
2984 default:
2985 str << "box";
2988 else
2990 str << "ellipse";
2992 str << "\"];" << std::endl;
2995 // Now generate the connectivity
2996 for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
2998 const cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
2999 cmTargets::const_iterator tit;
3000 for ( tit = targets->begin(); tit != targets->end(); ++ tit )
3002 std::map<cmStdString, int>::iterator dependIt
3003 = targetDeps.find(tit->first.c_str());
3004 if ( dependIt == targetDeps.end() )
3006 continue;
3008 std::map<cmStdString, cmStdString>::iterator cmakeTarIt
3009 = targetNamesNodes.find(tit->first.c_str());
3010 const cmTarget::LinkLibraryVectorType* ll
3011 = &(tit->second.GetOriginalLinkLibraries());
3012 cmTarget::LinkLibraryVectorType::const_iterator llit;
3013 for ( llit = ll->begin(); llit != ll->end(); ++ llit )
3015 const char* libName = llit->first.c_str();
3016 std::map<cmStdString, cmStdString>::const_iterator tarIt
3017 = targetNamesNodes.find(libName);
3018 if ( tarIt == targetNamesNodes.end() )
3020 // We should not be here.
3021 std::cout << __LINE__ << " Cannot find library: " << libName
3022 << " even though it was added in the previous pass" << std::endl;
3023 abort();
3025 str << " \"" << cmakeTarIt->second.c_str() << "\" -> \""
3026 << tarIt->second.c_str() << "\"" << std::endl;
3031 // TODO: Use dotted or something for external libraries
3032 //str << " \"node0\":f4 -> \"node12\"[color=\"#0000ff\" style=dotted]"
3033 //<< std::endl;
3035 str << "}" << std::endl;
3038 //----------------------------------------------------------------------------
3039 #ifdef CMAKE_BUILD_WITH_CMAKE
3040 int cmake::ExecuteEchoColor(std::vector<std::string>& args)
3042 // The arguments are
3043 // argv[0] == <cmake-executable>
3044 // argv[1] == cmake_echo_color
3046 bool enabled = true;
3047 int color = cmsysTerminal_Color_Normal;
3048 bool newline = true;
3049 for(unsigned int i=2; i < args.size(); ++i)
3051 if(args[i].find("--switch=") == 0)
3053 // Enable or disable color based on the switch value.
3054 std::string value = args[i].substr(9);
3055 if(!value.empty())
3057 if(cmSystemTools::IsOn(value.c_str()))
3059 enabled = true;
3061 else
3063 enabled = false;
3067 else if(args[i] == "--normal")
3069 color = cmsysTerminal_Color_Normal;
3071 else if(args[i] == "--black")
3073 color = cmsysTerminal_Color_ForegroundBlack;
3075 else if(args[i] == "--red")
3077 color = cmsysTerminal_Color_ForegroundRed;
3079 else if(args[i] == "--green")
3081 color = cmsysTerminal_Color_ForegroundGreen;
3083 else if(args[i] == "--yellow")
3085 color = cmsysTerminal_Color_ForegroundYellow;
3087 else if(args[i] == "--blue")
3089 color = cmsysTerminal_Color_ForegroundBlue;
3091 else if(args[i] == "--magenta")
3093 color = cmsysTerminal_Color_ForegroundMagenta;
3095 else if(args[i] == "--cyan")
3097 color = cmsysTerminal_Color_ForegroundCyan;
3099 else if(args[i] == "--white")
3101 color = cmsysTerminal_Color_ForegroundWhite;
3103 else if(args[i] == "--bold")
3105 color |= cmsysTerminal_Color_ForegroundBold;
3107 else if(args[i] == "--no-newline")
3109 newline = false;
3111 else if(args[i] == "--newline")
3113 newline = true;
3115 else
3117 // Color is enabled. Print with the current color.
3118 cmSystemTools::MakefileColorEcho(color, args[i].c_str(),
3119 newline, enabled);
3123 return 0;
3125 #else
3126 int cmake::ExecuteEchoColor(std::vector<std::string>&)
3128 return 1;
3130 #endif
3132 //----------------------------------------------------------------------------
3133 int cmake::ExecuteLinkScript(std::vector<std::string>& args)
3135 // The arguments are
3136 // argv[0] == <cmake-executable>
3137 // argv[1] == cmake_link_script
3138 // argv[2] == <link-script-name>
3139 // argv[3] == --verbose=?
3140 bool verbose = false;
3141 if(args.size() >= 4)
3143 if(args[3].find("--verbose=") == 0)
3145 if(!cmSystemTools::IsOff(args[3].substr(10).c_str()))
3147 verbose = true;
3152 // Allocate a process instance.
3153 cmsysProcess* cp = cmsysProcess_New();
3154 if(!cp)
3156 std::cerr << "Error allocating process instance in link script."
3157 << std::endl;
3158 return 1;
3161 // Children should share stdout and stderr with this process.
3162 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
3163 cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
3165 // Run the command lines verbatim.
3166 cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
3168 // Read command lines from the script.
3169 std::ifstream fin(args[2].c_str());
3170 if(!fin)
3172 std::cerr << "Error opening link script \""
3173 << args[2] << "\"" << std::endl;
3174 return 1;
3177 // Run one command at a time.
3178 std::string command;
3179 int result = 0;
3180 while(result == 0 && cmSystemTools::GetLineFromStream(fin, command))
3182 // Setup this command line.
3183 const char* cmd[2] = {command.c_str(), 0};
3184 cmsysProcess_SetCommand(cp, cmd);
3186 // Report the command if verbose output is enabled.
3187 if(verbose)
3189 std::cout << command << std::endl;
3192 // Run the command and wait for it to exit.
3193 cmsysProcess_Execute(cp);
3194 cmsysProcess_WaitForExit(cp, 0);
3196 // Report failure if any.
3197 switch(cmsysProcess_GetState(cp))
3199 case cmsysProcess_State_Exited:
3201 int value = cmsysProcess_GetExitValue(cp);
3202 if(value != 0)
3204 result = value;
3207 break;
3208 case cmsysProcess_State_Exception:
3209 std::cerr << "Error running link command: "
3210 << cmsysProcess_GetExceptionString(cp) << std::endl;
3211 result = 1;
3212 break;
3213 case cmsysProcess_State_Error:
3214 std::cerr << "Error running link command: "
3215 << cmsysProcess_GetErrorString(cp) << std::endl;
3216 result = 2;
3217 break;
3218 default:
3219 break;
3223 // Free the process instance.
3224 cmsysProcess_Delete(cp);
3226 // Return the final resulting return value.
3227 return result;
3230 void cmake::DefineProperties(cmake *cm)
3232 cm->DefineProperty
3233 ("REPORT_UNDEFINED_PROPERTIES", cmProperty::GLOBAL,
3234 "If set, report any undefined properties to this file.",
3235 "If this property is set to a filename then when CMake runs "
3236 "it will report any properties or variables that were accessed "
3237 "but not defined into the filename specified in this property."
3240 cm->DefineProperty
3241 ("TARGET_SUPPORTS_SHARED_LIBS", cmProperty::GLOBAL,
3242 "Does the target platform support shared libraries.",
3243 "TARGET_SUPPORTS_SHARED_LIBS is a boolean specifying whether the target "
3244 "platform supports shared libraries. Basically all current general "
3245 "general purpose OS do so, the exception are usually embedded systems "
3246 "with no or special OSs.");
3247 cm->DefineProperty
3248 ("FIND_LIBRARY_USE_LIB64_PATHS", cmProperty::GLOBAL,
3249 "Whether FIND_LIBRARY should automatically search lib64 directories.",
3250 "FIND_LIBRARY_USE_LIB64_PATHS is a boolean specifying whether the "
3251 "FIND_LIBRARY command should automatically search the lib64 variant of "
3252 "directories called lib in the search path when building 64-bit "
3253 "binaries.");
3254 cm->DefineProperty
3255 ("ENABLED_FEATURES", cmProperty::GLOBAL,
3256 "List of features which are enabled during the CMake run.",
3257 "List of features which are enabled during the CMake run. Be default "
3258 "it contains the names of all packages which were found. This is "
3259 "determined using the <NAME>_FOUND variables. Packages which are "
3260 "searched QUIET are not listed. A project can add its own features to "
3261 "this list.This property is used by the macros in FeatureSummary.cmake.");
3262 cm->DefineProperty
3263 ("DISABLED_FEATURES", cmProperty::GLOBAL,
3264 "List of features which are disabled during the CMake run.",
3265 "List of features which are disabled during the CMake run. Be default "
3266 "it contains the names of all packages which were not found. This is "
3267 "determined using the <NAME>_FOUND variables. Packages which are "
3268 "searched QUIET are not listed. A project can add its own features to "
3269 "this list.This property is used by the macros in FeatureSummary.cmake.");
3270 cm->DefineProperty
3271 ("PACKAGES_FOUND", cmProperty::GLOBAL,
3272 "List of packages which were found during the CMake run.",
3273 "List of packages which were found during the CMake run. Whether a "
3274 "package has been found is determined using the <NAME>_FOUND variables.");
3275 cm->DefineProperty
3276 ("PACKAGES_NOT_FOUND", cmProperty::GLOBAL,
3277 "List of packages which were not found during the CMake run.",
3278 "List of packages which were not found during the CMake run. Whether a "
3279 "package has been found is determined using the <NAME>_FOUND variables.");
3281 cm->DefineProperty
3282 ("PACKAGES_NOT_FOUND", cmProperty::GLOBAL,
3283 "List of packages which were not found during the CMake run.",
3284 "List of packages which were not found during the CMake run. Whether a "
3285 "package has been found is determined using the <NAME>_FOUND variables.");
3286 cm->DefineProperty(
3287 "__CMAKE_DELETE_CACHE_CHANGE_VARS_", cmProperty::GLOBAL,
3288 "Internal property",
3289 "Used to detect compiler changes, Do not set.");
3291 // ================================================================
3292 // define variables as well
3293 // ================================================================
3294 cmDocumentVariables::DefineVariables(cm);
3298 void cmake::DefineProperty(const char *name, cmProperty::ScopeType scope,
3299 const char *ShortDescription,
3300 const char *FullDescription,
3301 bool chained, const char *docSection)
3303 this->PropertyDefinitions[scope].DefineProperty(name,scope,ShortDescription,
3304 FullDescription,
3305 docSection,
3306 chained);
3309 cmPropertyDefinition *cmake
3310 ::GetPropertyDefinition(const char *name,
3311 cmProperty::ScopeType scope)
3313 if (this->IsPropertyDefined(name,scope))
3315 return &(this->PropertyDefinitions[scope][name]);
3317 return 0;
3320 void cmake::RecordPropertyAccess(const char *name,
3321 cmProperty::ScopeType scope)
3323 this->AccessedProperties.insert
3324 (std::pair<cmStdString,cmProperty::ScopeType>(name,scope));
3327 void cmake::ReportUndefinedPropertyAccesses(const char *filename)
3329 FILE *progFile = fopen(filename,"w");
3330 if (!progFile || !this->GlobalGenerator)
3332 return;
3335 // what are the enabled languages?
3336 std::vector<std::string> enLangs;
3337 this->GlobalGenerator->GetEnabledLanguages(enLangs);
3339 // Common configuration names.
3340 // TODO: Compute current configuration(s).
3341 std::vector<std::string> enConfigs;
3342 enConfigs.push_back("");
3343 enConfigs.push_back("DEBUG");
3344 enConfigs.push_back("RELEASE");
3345 enConfigs.push_back("MINSIZEREL");
3346 enConfigs.push_back("RELWITHDEBINFO");
3348 // take all the defined properties and add definitions for all the enabled
3349 // languages
3350 std::set<std::pair<cmStdString,cmProperty::ScopeType> > aliasedProperties;
3351 std::map<cmProperty::ScopeType, cmPropertyDefinitionMap>::iterator i;
3352 i = this->PropertyDefinitions.begin();
3353 for (;i != this->PropertyDefinitions.end(); ++i)
3355 cmPropertyDefinitionMap::iterator j;
3356 for (j = i->second.begin(); j != i->second.end(); ++j)
3358 // TODO: What if both <LANG> and <CONFIG> appear?
3359 if (j->first.find("<CONFIG>") != std::string::npos)
3361 std::vector<std::string>::const_iterator k;
3362 for (k = enConfigs.begin(); k != enConfigs.end(); ++k)
3364 std::string tmp = j->first;
3365 cmSystemTools::ReplaceString(tmp, "<CONFIG>", k->c_str());
3366 // add alias
3367 aliasedProperties.insert
3368 (std::pair<cmStdString,cmProperty::ScopeType>(tmp,i->first));
3371 if (j->first.find("<LANG>") != std::string::npos)
3373 std::vector<std::string>::const_iterator k;
3374 for (k = enLangs.begin(); k != enLangs.end(); ++k)
3376 std::string tmp = j->first;
3377 cmSystemTools::ReplaceString(tmp, "<LANG>", k->c_str());
3378 // add alias
3379 aliasedProperties.insert
3380 (std::pair<cmStdString,cmProperty::ScopeType>(tmp,i->first));
3386 std::set<std::pair<cmStdString,cmProperty::ScopeType> >::const_iterator ap;
3387 ap = this->AccessedProperties.begin();
3388 for (;ap != this->AccessedProperties.end(); ++ap)
3390 if (!this->IsPropertyDefined(ap->first.c_str(),ap->second) &&
3391 aliasedProperties.find(std::pair<cmStdString,cmProperty::ScopeType>
3392 (ap->first,ap->second)) ==
3393 aliasedProperties.end())
3395 const char *scopeStr = "";
3396 switch (ap->second)
3398 case cmProperty::TARGET:
3399 scopeStr = "TARGET";
3400 break;
3401 case cmProperty::SOURCE_FILE:
3402 scopeStr = "SOURCE_FILE";
3403 break;
3404 case cmProperty::DIRECTORY:
3405 scopeStr = "DIRECTORY";
3406 break;
3407 case cmProperty::TEST:
3408 scopeStr = "TEST";
3409 break;
3410 case cmProperty::VARIABLE:
3411 scopeStr = "VARIABLE";
3412 break;
3413 case cmProperty::CACHED_VARIABLE:
3414 scopeStr = "CACHED_VARIABLE";
3415 break;
3416 default:
3417 scopeStr = "unknown";
3418 break;
3420 fprintf(progFile,"%s with scope %s\n",ap->first.c_str(),scopeStr);
3423 fclose(progFile);
3426 bool cmake::IsPropertyDefined(const char *name, cmProperty::ScopeType scope)
3428 return this->PropertyDefinitions[scope].IsPropertyDefined(name);
3431 bool cmake::IsPropertyChained(const char *name, cmProperty::ScopeType scope)
3433 return this->PropertyDefinitions[scope].IsPropertyChained(name);
3436 void cmake::SetProperty(const char* prop, const char* value)
3438 if (!prop)
3440 return;
3442 if (!value)
3444 value = "NOTFOUND";
3447 this->Properties.SetProperty(prop, value, cmProperty::GLOBAL);
3450 void cmake::AppendProperty(const char* prop, const char* value)
3452 if (!prop)
3454 return;
3456 this->Properties.AppendProperty(prop, value, cmProperty::GLOBAL);
3459 const char *cmake::GetProperty(const char* prop)
3461 return this->GetProperty(prop, cmProperty::GLOBAL);
3464 const char *cmake::GetProperty(const char* prop, cmProperty::ScopeType scope)
3466 bool chain = false;
3468 // watch for special properties
3469 std::string propname = prop;
3470 std::string output = "";
3471 if ( propname == "CACHE_VARIABLES" )
3473 cmCacheManager::CacheIterator cit =
3474 this->GetCacheManager()->GetCacheIterator();
3475 for ( cit.Begin(); !cit.IsAtEnd(); cit.Next() )
3477 if ( output.size() )
3479 output += ";";
3481 output += cit.GetName();
3483 this->SetProperty("CACHE_VARIABLES", output.c_str());
3485 else if ( propname == "COMMANDS" )
3487 cmake::RegisteredCommandsMap::iterator cmds
3488 = this->GetCommands()->begin();
3489 for (unsigned int cc=0 ; cmds != this->GetCommands()->end(); ++ cmds )
3491 if ( cc > 0 )
3493 output += ";";
3495 output += cmds->first.c_str();
3496 cc++;
3498 this->SetProperty("COMMANDS",output.c_str());
3501 return this->Properties.GetPropertyValue(prop, scope, chain);
3504 bool cmake::GetPropertyAsBool(const char* prop)
3506 return cmSystemTools::IsOn(this->GetProperty(prop));
3509 int cmake::GetSystemInformation(std::vector<std::string>& args)
3511 // so create the directory
3512 std::string resultFile;
3513 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
3514 std::string destPath = cwd + "/__cmake_systeminformation";
3515 cmSystemTools::RemoveADirectory(destPath.c_str());
3516 if (!cmSystemTools::MakeDirectory(destPath.c_str()))
3518 std::cerr << "Error: --system-information must be run from a "
3519 "writable directory!\n";
3520 return 1;
3523 // process the arguments
3524 bool writeToStdout = true;
3525 for(unsigned int i=1; i < args.size(); ++i)
3527 std::string arg = args[i];
3528 if(arg.find("-V",0) == 0)
3530 this->Verbose = true;
3532 else if(arg.find("-G",0) == 0)
3534 std::string value = arg.substr(2);
3535 if(value.size() == 0)
3537 ++i;
3538 if(i >= args.size())
3540 cmSystemTools::Error("No generator specified for -G");
3541 return -1;
3543 value = args[i];
3545 cmGlobalGenerator* gen =
3546 this->CreateGlobalGenerator(value.c_str());
3547 if(!gen)
3549 cmSystemTools::Error("Could not create named generator ",
3550 value.c_str());
3552 else
3554 this->SetGlobalGenerator(gen);
3557 // no option assume it is the output file
3558 else
3560 if (!cmSystemTools::FileIsFullPath(arg.c_str()))
3562 resultFile = cwd;
3563 resultFile += "/";
3565 resultFile += arg;
3566 writeToStdout = false;
3571 // we have to find the module directory, so we can copy the files
3572 this->AddCMakePaths();
3573 std::string modulesPath =
3574 this->CacheManager->GetCacheValue("CMAKE_ROOT");
3575 modulesPath += "/Modules";
3576 std::string inFile = modulesPath;
3577 inFile += "/SystemInformation.cmake";
3578 std::string outFile = destPath;
3579 outFile += "/CMakeLists.txt";
3581 // Copy file
3582 if(!cmSystemTools::cmCopyFile(inFile.c_str(), outFile.c_str()))
3584 std::cerr << "Error copying file \"" << inFile.c_str()
3585 << "\" to \"" << outFile.c_str() << "\".\n";
3586 return 1;
3589 // do we write to a file or to stdout?
3590 if (resultFile.size() == 0)
3592 resultFile = cwd;
3593 resultFile += "/__cmake_systeminformation/results.txt";
3596 // now run cmake on the CMakeLists file
3597 cmSystemTools::ChangeDirectory(destPath.c_str());
3598 std::vector<std::string> args2;
3599 args2.push_back(args[0]);
3600 args2.push_back(destPath);
3601 std::string resultArg = "-DRESULT_FILE=";
3602 resultArg += resultFile;
3603 args2.push_back(resultArg);
3604 int res = this->Run(args2, false);
3606 if (res != 0)
3608 std::cerr << "Error: --system-information failed on internal CMake!\n";
3609 return res;
3612 // change back to the original directory
3613 cmSystemTools::ChangeDirectory(cwd.c_str());
3615 // echo results to stdout if needed
3616 if (writeToStdout)
3618 FILE* fin = fopen(resultFile.c_str(), "r");
3619 if(fin)
3621 const int bufferSize = 4096;
3622 char buffer[bufferSize];
3623 size_t n;
3624 while((n = fread(buffer, 1, bufferSize, fin)) > 0)
3626 for(char* c = buffer; c < buffer+n; ++c)
3628 putc(*c, stdout);
3630 fflush(stdout);
3632 fclose(fin);
3636 // clean up the directory
3637 cmSystemTools::RemoveADirectory(destPath.c_str());
3638 return 0;
3641 //----------------------------------------------------------------------------
3642 static bool cmakeCheckStampFile(const char* stampName)
3644 // If the stamp file still exists then it must really be out of
3645 // date.
3646 if(cmSystemTools::FileExists(stampName))
3648 return false;
3651 // The stamp file does not exist. Use the stamp dependencies to
3652 // determine whether it is really out of date. This works in
3653 // conjunction with cmLocalVisualStudio7Generator to avoid
3654 // repeatedly re-running CMake when the user rebuilds the entire
3655 // solution.
3656 std::string stampDepends = stampName;
3657 stampDepends += ".depend";
3658 #if defined(_WIN32) || defined(__CYGWIN__)
3659 std::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
3660 #else
3661 std::ifstream fin(stampDepends.c_str(), std::ios::in);
3662 #endif
3663 if(!fin)
3665 // The stamp dependencies file cannot be read. Just assume the
3666 // build system is really out of date.
3667 return false;
3670 // Compare the stamp dependencies against the dependency file itself.
3671 cmFileTimeComparison ftc;
3672 std::string dep;
3673 while(cmSystemTools::GetLineFromStream(fin, dep))
3675 int result;
3676 if(dep.length() >= 1 && dep[0] != '#' &&
3677 (!ftc.FileTimeCompare(stampDepends.c_str(), dep.c_str(), &result)
3678 || result < 0))
3680 // The stamp depends file is older than this dependency. The
3681 // build system is really out of date.
3682 return false;
3686 // The build system is up to date. The stamp file has been removed
3687 // by the VS IDE due to a "rebuild" request. Just restore it.
3688 std::ofstream stamp(stampName);
3689 stamp << "# CMake generation timestamp file this directory.\n";
3690 if(stamp)
3692 // Notify the user why CMake is not re-running. It is safe to
3693 // just print to stdout here because this code is only reachable
3694 // through an undocumented flag used by the VS generator.
3695 std::cout << "CMake does not need to re-run because the "
3696 << "generation timestamp is up-to-date.\n";
3697 return true;
3699 else
3701 cmSystemTools::Error("Cannot restore timestamp ", stampName);
3702 return false;
3706 // For visual studio 2005 and newer manifest files need to be embeded into
3707 // exe and dll's. This code does that in such a way that incremental linking
3708 // still works.
3709 int cmake::VisualStudioLink(std::vector<std::string>& args, int type)
3711 if(args.size() < 2)
3713 return -1;
3715 bool verbose = false;
3716 if(cmSystemTools::GetEnv("VERBOSE"))
3718 verbose = true;
3720 std::vector<std::string> expandedArgs;
3721 for(std::vector<std::string>::iterator i = args.begin();
3722 i != args.end(); ++i)
3724 // check for nmake temporary files
3725 if((*i)[0] == '@')
3727 std::ifstream fin(i->substr(1).c_str());
3728 std::string line;
3729 while(cmSystemTools::GetLineFromStream(fin,
3730 line))
3732 cmSystemTools::ParseWindowsCommandLine(line.c_str(), expandedArgs);
3735 else
3737 expandedArgs.push_back(*i);
3740 // figure out if this is an incremental link or not and run the correct
3741 // link function.
3742 for(std::vector<std::string>::iterator i = expandedArgs.begin();
3743 i != expandedArgs.end(); ++i)
3745 if(cmSystemTools::Strucmp(i->c_str(), "/INCREMENTAL:YES") == 0)
3747 if(verbose)
3749 std::cout << "Visual Studio Incremental Link\n";
3751 return cmake::VisualStudioLinkIncremental(expandedArgs, type, verbose);
3754 if(verbose)
3756 std::cout << "Visual Studio Non-Incremental Link\n";
3758 return cmake::VisualStudioLinkNonIncremental(expandedArgs, type, verbose);
3761 int cmake::ParseVisualStudioLinkCommand(std::vector<std::string>& args,
3762 std::vector<cmStdString>& command,
3763 std::string& targetName)
3765 std::vector<std::string>::iterator i = args.begin();
3766 i++; // skip -E
3767 i++; // skip vs_link_dll or vs_link_exe
3768 command.push_back(*i);
3769 i++; // move past link command
3770 for(; i != args.end(); ++i)
3772 command.push_back(*i);
3773 if(i->find("/Fe") == 0)
3775 targetName = i->substr(3);
3777 if(i->find("/out:") == 0)
3779 targetName = i->substr(5);
3782 if(targetName.size() == 0 || command.size() == 0)
3784 return -1;
3786 return 0;
3789 bool cmake::RunCommand(const char* comment,
3790 std::vector<cmStdString>& command,
3791 bool verbose,
3792 int* retCodeOut)
3794 if(verbose)
3796 std::cout << comment << ":\n";
3797 for(std::vector<cmStdString>::iterator i = command.begin();
3798 i != command.end(); ++i)
3800 std::cout << i->c_str() << " ";
3802 std::cout << "\n";
3804 std::string output;
3805 int retCode =0;
3806 // use rc command to create .res file
3807 cmSystemTools::RunSingleCommand(command,
3808 &output,
3809 &retCode);
3810 if(verbose)
3812 std::cout << output << "\n";
3814 // if retCodeOut is requested then always return true
3815 // and set the retCodeOut to retCode
3816 if(retCodeOut)
3818 *retCodeOut = retCode;
3819 return true;
3821 if(retCode != 0)
3823 std::cout << comment << " failed. with " << retCode << "\n";
3825 return retCode == 0;
3828 int cmake::VisualStudioLinkIncremental(std::vector<std::string>& args,
3829 int type, bool verbose)
3831 // This follows the steps listed here:
3832 // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx
3834 // 1. Compiler compiles the application and generates the *.obj files.
3835 // 2. An empty manifest file is generated if this is a clean build and if
3836 // not the previous one is reused.
3837 // 3. The resource compiler (rc.exe) compiles the *.manifest file to a
3838 // *.res file.
3839 // 4. Linker generates the binary (EXE or DLL) with the /incremental
3840 // switch and embeds the dummy manifest file. The linker also generates
3841 // the real manifest file based on the binaries that your binary depends
3842 // on.
3843 // 5. The manifest tool (mt.exe) is then used to generate the final
3844 // manifest.
3846 // If the final manifest is changed, then 6 and 7 are run, if not
3847 // they are skipped, and it is done.
3849 // 6. The resource compiler is invoked one more time.
3850 // 7. Finally, the Linker does another incremental link, but since the
3851 // only thing that has changed is the *.res file that contains the
3852 // manifest it is a short link.
3853 std::vector<cmStdString> linkCommand;
3854 std::string targetName;
3855 if(cmake::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1)
3857 return -1;
3859 std::string manifestArg = "/MANIFESTFILE:";
3860 std::vector<cmStdString> rcCommand;
3861 rcCommand.push_back(cmSystemTools::FindProgram("rc.exe"));
3862 std::vector<cmStdString> mtCommand;
3863 mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
3864 std::string tempManifest;
3865 tempManifest = targetName;
3866 tempManifest += ".intermediate.manifest";
3867 std::string resourceInputFile = targetName;
3868 resourceInputFile += ".resource.txt";
3869 if(verbose)
3871 std::cout << "Create " << resourceInputFile.c_str() << "\n";
3873 // Create input file for rc command
3874 std::ofstream fout(resourceInputFile.c_str());
3875 if(!fout)
3877 return -1;
3879 std::string manifestFile = targetName;
3880 manifestFile += ".embed.manifest";
3881 std::string fullPath= cmSystemTools::CollapseFullPath(manifestFile.c_str());
3882 fout << type << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID "
3883 "*/ 24 /* RT_MANIFEST */ " << "\"" << fullPath.c_str() << "\"";
3884 fout.close();
3885 manifestArg += tempManifest;
3886 // add the manifest arg to the linkCommand
3887 linkCommand.push_back(manifestArg);
3888 // if manifestFile is not yet created, create an
3889 // empty one
3890 if(!cmSystemTools::FileExists(manifestFile.c_str()))
3892 if(verbose)
3894 std::cout << "Create empty: " << manifestFile.c_str() << "\n";
3896 std::ofstream foutTmp(manifestFile.c_str());
3898 std::string resourceFile = manifestFile;
3899 resourceFile += ".res";
3900 // add the resource file to the end of the link command
3901 linkCommand.push_back(resourceFile);
3902 std::string outputOpt = "/fo";
3903 outputOpt += resourceFile;
3904 rcCommand.push_back(outputOpt);
3905 rcCommand.push_back(resourceInputFile);
3906 // Run rc command to create resource
3907 if(!cmake::RunCommand("RC Pass 1", rcCommand, verbose))
3909 return -1;
3911 // Now run the link command to link and create manifest
3912 if(!cmake::RunCommand("LINK Pass 1", linkCommand, verbose))
3914 return -1;
3916 // create mt command
3917 std::string outArg("/out:");
3918 outArg+= manifestFile;
3919 mtCommand.push_back("/nologo");
3920 mtCommand.push_back(outArg);
3921 mtCommand.push_back("/notify_update");
3922 mtCommand.push_back("/manifest");
3923 mtCommand.push_back(tempManifest);
3924 // now run mt.exe to create the final manifest file
3925 int mtRet =0;
3926 cmake::RunCommand("MT", mtCommand, verbose, &mtRet);
3927 // if mt returns 0, then the manifest was not changed and
3928 // we do not need to do another link step
3929 if(mtRet == 0)
3931 return 0;
3933 // check for magic mt return value if mt returns the magic number
3934 // 1090650113 then it means that it updated the manifest file and we need
3935 // to do the final link. If mt has any value other than 0 or 1090650113
3936 // then there was some problem with the command itself and there was an
3937 // error so return the error code back out of cmake so make can report it.
3938 if(mtRet != 1090650113)
3940 return mtRet;
3942 // update the resource file with the new manifest from the mt command.
3943 if(!cmake::RunCommand("RC Pass 2", rcCommand, verbose))
3945 return -1;
3947 // Run the final incremental link that will put the new manifest resource
3948 // into the file incrementally.
3949 if(!cmake::RunCommand("FINAL LINK", linkCommand, verbose))
3951 return -1;
3953 return 0;
3956 int cmake::VisualStudioLinkNonIncremental(std::vector<std::string>& args,
3957 int type,
3958 bool verbose)
3960 std::vector<cmStdString> linkCommand;
3961 std::string targetName;
3962 if(cmake::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1)
3964 return -1;
3966 // Run the link command as given
3967 if(!cmake::RunCommand("LINK", linkCommand, verbose))
3969 return -1;
3971 std::vector<cmStdString> mtCommand;
3972 mtCommand.push_back(cmSystemTools::FindProgram("mt.exe"));
3973 mtCommand.push_back("/nologo");
3974 mtCommand.push_back("/manifest");
3975 std::string manifestFile = targetName;
3976 manifestFile += ".manifest";
3977 mtCommand.push_back(manifestFile);
3978 std::string outresource = "/outputresource:";
3979 outresource += targetName;
3980 outresource += ";#";
3981 if(type == 1)
3983 outresource += "1";
3985 else if(type == 2)
3987 outresource += "2";
3989 mtCommand.push_back(outresource);
3990 // Now use the mt tool to embed the manifest into the exe or dll
3991 if(!cmake::RunCommand("MT", mtCommand, verbose))
3993 return -1;
3995 return 0;