summaryrefslogtreecommitdiff
path: root/Source/cmGlobalGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGlobalGenerator.cxx')
-rw-r--r--Source/cmGlobalGenerator.cxx2510
1 files changed, 2510 insertions, 0 deletions
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
new file mode 100644
index 000000000..a47ca3677
--- /dev/null
+++ b/Source/cmGlobalGenerator.cxx
@@ -0,0 +1,2510 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include "windows.h" // this must be first to define GetCurrentDirectory
+#endif
+
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmExternalMakefileProjectGenerator.h"
+#include "cmake.h"
+#include "cmMakefile.h"
+#include "cmQtAutomoc.h"
+#include "cmSourceFile.h"
+#include "cmVersion.h"
+#include "cmExportInstallFileGenerator.h"
+#include "cmComputeTargetDepends.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+
+#include <cmsys/Directory.hxx>
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+# include <cmsys/MD5.h>
+#endif
+
+#include <stdlib.h> // required for atof
+
+#include <assert.h>
+
+cmGlobalGenerator::cmGlobalGenerator()
+{
+ // By default the .SYMBOLIC dependency is not needed on symbolic rules.
+ this->NeedSymbolicMark = false;
+
+ // by default use the native paths
+ this->ForceUnixPaths = false;
+
+ // By default do not try to support color.
+ this->ToolSupportsColor = false;
+
+ // By default do not use link scripts.
+ this->UseLinkScript = false;
+
+ // Whether an install target is needed.
+ this->InstallTargetEnabled = false;
+
+ // how long to let try compiles run
+ this->TryCompileTimeout = 0;
+
+ this->ExtraGenerator = 0;
+ this->CurrentLocalGenerator = 0;
+ this->TryCompileOuterMakefile = 0;
+}
+
+cmGlobalGenerator::~cmGlobalGenerator()
+{
+ // Delete any existing cmLocalGenerators
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ delete this->LocalGenerators[i];
+ }
+ this->LocalGenerators.clear();
+
+ if (this->ExtraGenerator)
+ {
+ delete this->ExtraGenerator;
+ }
+
+ this->ClearGeneratorTargets();
+ this->ClearExportSets();
+}
+
+void cmGlobalGenerator::ResolveLanguageCompiler(const std::string &lang,
+ cmMakefile *mf,
+ bool optional) {
+ std::string langComp = "CMAKE_";
+ langComp += lang;
+ langComp += "_COMPILER";
+
+ if(!mf->GetDefinition(langComp.c_str()))
+ {
+ if(!optional)
+ {
+ cmSystemTools::Error(langComp.c_str(),
+ " not set, after EnableLanguage");
+ }
+ return;
+ }
+ const char* name = mf->GetRequiredDefinition(langComp.c_str());
+ std::string path;
+ if(!cmSystemTools::FileIsFullPath(name))
+ {
+ path = cmSystemTools::FindProgram(name);
+ }
+ else
+ {
+ path = name;
+ }
+ if((path.size() == 0 || !cmSystemTools::FileExists(path.c_str()))
+ && (optional==false))
+ {
+ std::string message = "your ";
+ message += lang;
+ message += " compiler: \"";
+ message += name;
+ message += "\" was not found. Please set ";
+ message += langComp;
+ message += " to a valid compiler path or name.";
+ cmSystemTools::Error(message.c_str());
+ path = name;
+ }
+ std::string doc = lang;
+ doc += " compiler.";
+ const char* cname = this->GetCMakeInstance()->
+ GetCacheManager()->GetCacheValue(langComp.c_str());
+ std::string changeVars;
+ if(cname && (path != cname) && (optional==false))
+ {
+ std::string cnameString = cname;
+ std::string pathString = path;
+ // get rid of potentially multiple slashes:
+ cmSystemTools::ConvertToUnixSlashes(cnameString);
+ cmSystemTools::ConvertToUnixSlashes(pathString);
+ if (cnameString != pathString)
+ {
+ const char* cvars =
+ this->GetCMakeInstance()->GetProperty(
+ "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
+ if(cvars)
+ {
+ changeVars += cvars;
+ changeVars += ";";
+ }
+ changeVars += langComp;
+ changeVars += ";";
+ changeVars += cname;
+ this->GetCMakeInstance()->SetProperty(
+ "__CMAKE_DELETE_CACHE_CHANGE_VARS_",
+ changeVars.c_str());
+ }
+ }
+ mf->AddCacheDefinition(langComp.c_str(), path.c_str(),
+ doc.c_str(), cmCacheManager::FILEPATH);
+}
+
+// Find the make program for the generator, required for try compiles
+void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
+{
+ if(this->FindMakeProgramFile.size() == 0)
+ {
+ cmSystemTools::Error(
+ "Generator implementation error, "
+ "all generators must specify this->FindMakeProgramFile");
+ }
+ if(!mf->GetDefinition("CMAKE_MAKE_PROGRAM")
+ || cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM")))
+ {
+ std::string setMakeProgram =
+ mf->GetModulesFile(this->FindMakeProgramFile.c_str());
+ if(setMakeProgram.size())
+ {
+ mf->ReadListFile(0, setMakeProgram.c_str());
+ }
+ }
+ if(!mf->GetDefinition("CMAKE_MAKE_PROGRAM")
+ || cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM")))
+ {
+ cmOStringStream err;
+ err << "CMake was unable to find a build program corresponding to \""
+ << this->GetName() << "\". CMAKE_MAKE_PROGRAM is not set. You "
+ << "probably need to select a different build tool.";
+ cmSystemTools::Error(err.str().c_str());
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ // if there are spaces in the make program use short path
+ // but do not short path the actual program name, as
+ // this can cause trouble with VSExpress
+ if(makeProgram.find(' ') != makeProgram.npos)
+ {
+ std::string dir;
+ std::string file;
+ cmSystemTools::SplitProgramPath(makeProgram.c_str(),
+ dir, file);
+ std::string saveFile = file;
+ cmSystemTools::GetShortPath(makeProgram.c_str(), makeProgram);
+ cmSystemTools::SplitProgramPath(makeProgram.c_str(),
+ dir, file);
+ makeProgram = dir;
+ makeProgram += "/";
+ makeProgram += saveFile;
+ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram.c_str(),
+ "make program",
+ cmCacheManager::FILEPATH);
+ }
+
+ if(makeProgram.find("xcodebuild") != makeProgram.npos)
+ {
+ // due to the text file busy /bin/sh problem with xcodebuild
+ // use the cmakexbuild wrapper instead. This program
+ // will run xcodebuild and if it sees the error text file busy
+ // it will stop forwarding output, and let the build finish.
+ // Then it will retry the build. It will continue this
+ // untill no text file busy errors occur.
+ std::string cmakexbuild =
+ this->CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_COMMAND");
+ cmakexbuild = cmakexbuild.substr(0, cmakexbuild.length()-5);
+ cmakexbuild += "cmakexbuild";
+
+ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM",
+ cmakexbuild.c_str(),
+ "make program",
+ cmCacheManager::FILEPATH);
+ }
+}
+
+// enable the given language
+//
+// The following files are loaded in this order:
+//
+// First figure out what OS we are running on:
+//
+// CMakeSystem.cmake - configured file created by CMakeDetermineSystem.cmake
+// CMakeDetermineSystem.cmake - figure out os info and create
+// CMakeSystem.cmake IF CMAKE_SYSTEM
+// not set
+// CMakeSystem.cmake - configured file created by
+// CMakeDetermineSystem.cmake IF CMAKE_SYSTEM_LOADED
+
+// Next try and enable all languages found in the languages vector
+//
+// FOREACH LANG in languages
+// CMake(LANG)Compiler.cmake - configured file create by
+// CMakeDetermine(LANG)Compiler.cmake
+// CMakeDetermine(LANG)Compiler.cmake - Finds compiler for LANG and
+// creates CMake(LANG)Compiler.cmake
+// CMake(LANG)Compiler.cmake - configured file created by
+// CMakeDetermine(LANG)Compiler.cmake
+//
+// CMakeSystemSpecificInformation.cmake
+// - includes Platform/${CMAKE_SYSTEM_NAME}.cmake
+// may use compiler stuff
+
+// FOREACH LANG in languages
+// CMake(LANG)Information.cmake
+// - loads Platform/${CMAKE_SYSTEM_NAME}-${COMPILER}.cmake
+// CMakeTest(LANG)Compiler.cmake
+// - Make sure the compiler works with a try compile if
+// CMakeDetermine(LANG) was loaded
+//
+// Now load a few files that can override values set in any of the above
+// (PROJECTNAME)Compatibility.cmake
+// - load any backwards compatibility stuff for current project
+// ${CMAKE_USER_MAKE_RULES_OVERRIDE}
+// - allow users a chance to override system variables
+//
+//
+
+void
+cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
+ cmMakefile *mf, bool)
+{
+ if(languages.size() == 0)
+ {
+ cmSystemTools::Error("EnableLanguage must have a lang specified!");
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+
+ if(this->TryCompileOuterMakefile)
+ {
+ // In a try-compile we can only enable languages provided by caller.
+ for(std::vector<std::string>::const_iterator li = languages.begin();
+ li != languages.end(); ++li)
+ {
+ if(*li == "NONE")
+ {
+ this->SetLanguageEnabled("NONE", mf);
+ }
+ else
+ {
+ const char* lang = li->c_str();
+ if(this->LanguagesReady.find(lang) == this->LanguagesReady.end())
+ {
+ cmOStringStream e;
+ e << "The test project needs language "
+ << lang << " which is not enabled.";
+ this->TryCompileOuterMakefile
+ ->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return;
+ }
+ }
+ }
+ }
+
+ mf->AddDefinition("RUN_CONFIGURE", true);
+ std::string rootBin = mf->GetHomeOutputDirectory();
+ rootBin += cmake::GetCMakeFilesDirectory();
+
+ // If the configuration files path has been set,
+ // then we are in a try compile and need to copy the enable language
+ // files from the parent cmake bin dir, into the try compile bin dir
+ if(this->ConfiguredFilesPath.size())
+ {
+ rootBin = this->ConfiguredFilesPath;
+ }
+
+ // set the dir for parent files so they can be used by modules
+ mf->AddDefinition("CMAKE_PLATFORM_ROOT_BIN",rootBin.c_str());
+
+ // find and make sure CMAKE_MAKE_PROGRAM is defined
+ this->FindMakeProgram(mf);
+
+ // try and load the CMakeSystem.cmake if it is there
+ std::string fpath = rootBin;
+ if(!mf->GetDefinition("CMAKE_SYSTEM_LOADED"))
+ {
+ fpath += "/CMakeSystem.cmake";
+ if(cmSystemTools::FileExists(fpath.c_str()))
+ {
+ mf->ReadListFile(0,fpath.c_str());
+ }
+ }
+ // Load the CMakeDetermineSystem.cmake file and find out
+ // what platform we are running on
+ if (!mf->GetDefinition("CMAKE_SYSTEM"))
+ {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ /* Windows version number data. */
+ OSVERSIONINFO osvi;
+ ZeroMemory(&osvi, sizeof(osvi));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx (&osvi);
+ cmOStringStream windowsVersionString;
+ windowsVersionString << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
+ windowsVersionString.str();
+ mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
+ windowsVersionString.str().c_str());
+#endif
+ // Read the DetermineSystem file
+ std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
+ mf->ReadListFile(0, systemFile.c_str());
+ // load the CMakeSystem.cmake from the binary directory
+ // this file is configured by the CMakeDetermineSystem.cmake file
+ fpath = rootBin;
+ fpath += "/CMakeSystem.cmake";
+ mf->ReadListFile(0,fpath.c_str());
+ }
+ std::map<cmStdString, bool> needTestLanguage;
+ std::map<cmStdString, bool> needSetLanguageEnabledMaps;
+ // foreach language
+ // load the CMakeDetermine(LANG)Compiler.cmake file to find
+ // the compiler
+
+ for(std::vector<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l)
+ {
+ const char* lang = l->c_str();
+ needSetLanguageEnabledMaps[lang] = false;
+ if(*l == "NONE")
+ {
+ this->SetLanguageEnabled("NONE", mf);
+ continue;
+ }
+ std::string loadedLang = "CMAKE_";
+ loadedLang += lang;
+ loadedLang += "_COMPILER_LOADED";
+ // If the existing build tree was already configured with this
+ // version of CMake then try to load the configured file first
+ // to avoid duplicate compiler tests.
+ unsigned int cacheMajor = mf->GetCacheMajorVersion();
+ unsigned int cacheMinor = mf->GetCacheMinorVersion();
+ unsigned int selfMajor = cmVersion::GetMajorVersion();
+ unsigned int selfMinor = cmVersion::GetMinorVersion();
+ if((this->CMakeInstance->GetIsInTryCompile() ||
+ (selfMajor == cacheMajor && selfMinor == cacheMinor))
+ && !mf->GetDefinition(loadedLang.c_str()))
+ {
+ fpath = rootBin;
+ fpath += "/CMake";
+ fpath += lang;
+ fpath += "Compiler.cmake";
+ if(cmSystemTools::FileExists(fpath.c_str()))
+ {
+ if(!mf->ReadListFile(0,fpath.c_str()))
+ {
+ cmSystemTools::Error("Could not find cmake module file:",
+ fpath.c_str());
+ }
+ // if this file was found then the language was already determined
+ // to be working
+ needTestLanguage[lang] = false;
+ this->SetLanguageEnabledFlag(lang, mf);
+ needSetLanguageEnabledMaps[lang] = true;
+ // this can only be called after loading CMake(LANG)Compiler.cmake
+ }
+ }
+
+ if(!this->GetLanguageEnabled(lang) )
+ {
+ if (this->CMakeInstance->GetIsInTryCompile())
+ {
+ cmSystemTools::Error("This should not have happen. "
+ "If you see this message, you are probably "
+ "using a broken CMakeLists.txt file or a "
+ "problematic release of CMake");
+ }
+ // if the CMake(LANG)Compiler.cmake file was not found then
+ // load CMakeDetermine(LANG)Compiler.cmake
+ std::string determineCompiler = "CMakeDetermine";
+ determineCompiler += lang;
+ determineCompiler += "Compiler.cmake";
+ std::string determineFile =
+ mf->GetModulesFile(determineCompiler.c_str());
+ if(!mf->ReadListFile(0,determineFile.c_str()))
+ {
+ cmSystemTools::Error("Could not find cmake module file:",
+ determineFile.c_str());
+ }
+ needTestLanguage[lang] = true;
+ // Some generators like visual studio should not use the env variables
+ // So the global generator can specify that in this variable
+ if(!mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV"))
+ {
+ // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER
+ // into the environment, in case user scripts want to run
+ // configure, or sub cmakes
+ std::string compilerName = "CMAKE_";
+ compilerName += lang;
+ compilerName += "_COMPILER";
+ std::string compilerEnv = "CMAKE_";
+ compilerEnv += lang;
+ compilerEnv += "_COMPILER_ENV_VAR";
+ std::string envVar = mf->GetRequiredDefinition(compilerEnv.c_str());
+ std::string envVarValue =
+ mf->GetRequiredDefinition(compilerName.c_str());
+ std::string env = envVar;
+ env += "=";
+ env += envVarValue;
+ cmSystemTools::PutEnv(env.c_str());
+ }
+
+ // if determineLanguage was called then load the file it
+ // configures CMake(LANG)Compiler.cmake
+ fpath = rootBin;
+ fpath += "/CMake";
+ fpath += lang;
+ fpath += "Compiler.cmake";
+ if(!mf->ReadListFile(0,fpath.c_str()))
+ {
+ cmSystemTools::Error("Could not find cmake module file:",
+ fpath.c_str());
+ }
+ this->SetLanguageEnabledFlag(lang, mf);
+ needSetLanguageEnabledMaps[lang] = true;
+ // this can only be called after loading CMake(LANG)Compiler.cmake
+ // the language must be enabled for try compile to work, but we do
+ // not know if it is a working compiler yet so set the test language
+ // flag
+ needTestLanguage[lang] = true;
+ } // end if(!this->GetLanguageEnabled(lang) )
+ } // end loop over languages
+
+ // **** Load the system specific information if not yet loaded
+ if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED"))
+ {
+ fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake");
+ if(!mf->ReadListFile(0,fpath.c_str()))
+ {
+ cmSystemTools::Error("Could not find cmake module file:",
+ fpath.c_str());
+ }
+ }
+ // loop over languages again loading CMake(LANG)Information.cmake
+ //
+ for(std::vector<std::string>::const_iterator l = languages.begin();
+ l != languages.end(); ++l)
+ {
+ const char* lang = l->c_str();
+ if(*l == "NONE")
+ {
+ this->SetLanguageEnabled("NONE", mf);
+ continue;
+ }
+ std::string langLoadedVar = "CMAKE_";
+ langLoadedVar += lang;
+ langLoadedVar += "_INFORMATION_LOADED";
+ if (!mf->GetDefinition(langLoadedVar.c_str()))
+ {
+ fpath = "CMake";
+ fpath += lang;
+ fpath += "Information.cmake";
+ std::string informationFile = mf->GetModulesFile(fpath.c_str());
+ if (informationFile.empty())
+ {
+ cmSystemTools::Error("Could not find cmake module file:",
+ fpath.c_str());
+ }
+ else if(!mf->ReadListFile(0, informationFile.c_str()))
+ {
+ cmSystemTools::Error("Could not process cmake module file:",
+ informationFile.c_str());
+ }
+ }
+ if (needSetLanguageEnabledMaps[lang])
+ {
+ this->SetLanguageEnabledMaps(lang, mf);
+ }
+ this->LanguagesReady.insert(lang);
+
+ std::string compilerName = "CMAKE_";
+ compilerName += lang;
+ compilerName += "_COMPILER";
+ std::string compilerLangFile = rootBin;
+ compilerLangFile += "/CMake";
+ compilerLangFile += lang;
+ compilerLangFile += "Compiler.cmake";
+ // Test the compiler for the language just setup
+ // (but only if a compiler has been actually found)
+ // At this point we should have enough info for a try compile
+ // which is used in the backward stuff
+ // If the language is untested then test it now with a try compile.
+ if (!mf->IsSet(compilerName.c_str()))
+ {
+ // if the compiler did not work, then remove the
+ // CMake(LANG)Compiler.cmake file so that it will get tested the
+ // next time cmake is run
+ cmSystemTools::RemoveFile(compilerLangFile.c_str());
+ }
+ else if(needTestLanguage[lang])
+ {
+ if (!this->CMakeInstance->GetIsInTryCompile())
+ {
+ std::string testLang = "CMakeTest";
+ testLang += lang;
+ testLang += "Compiler.cmake";
+ std::string ifpath = mf->GetModulesFile(testLang.c_str());
+ if(!mf->ReadListFile(0,ifpath.c_str()))
+ {
+ cmSystemTools::Error("Could not find cmake module file:",
+ ifpath.c_str());
+ }
+ std::string compilerWorks = "CMAKE_";
+ compilerWorks += lang;
+ compilerWorks += "_COMPILER_WORKS";
+ // if the compiler did not work, then remove the
+ // CMake(LANG)Compiler.cmake file so that it will get tested the
+ // next time cmake is run
+ if(!mf->IsOn(compilerWorks.c_str()))
+ {
+ cmSystemTools::RemoveFile(compilerLangFile.c_str());
+ }
+ else
+ {
+ // load backwards compatibility stuff for C and CXX
+ // for old versions of CMake ListFiles C and CXX had some
+ // backwards compatibility files they have to load
+ // These files have a bunch of try compiles in them so
+ // should only be done
+ if (mf->NeedBackwardsCompatibility(1,4))
+ {
+ if(strcmp(lang, "C") == 0)
+ {
+ ifpath =
+ mf->GetModulesFile("CMakeBackwardCompatibilityC.cmake");
+ mf->ReadListFile(0,ifpath.c_str());
+ }
+ if(strcmp(lang, "CXX") == 0)
+ {
+ ifpath =
+ mf->GetModulesFile("CMakeBackwardCompatibilityCXX.cmake");
+ mf->ReadListFile(0,ifpath.c_str());
+ }
+ }
+ }
+ } // end if in try compile
+ } // end need test language
+ // Store the shared library flags so that we can satisfy CMP0018
+ std::string sharedLibFlagsVar = "CMAKE_SHARED_LIBRARY_";
+ sharedLibFlagsVar += lang;
+ sharedLibFlagsVar += "_FLAGS";
+ const char* sharedLibFlags =
+ mf->GetSafeDefinition(sharedLibFlagsVar.c_str());
+ if (sharedLibFlags)
+ {
+ this->LanguageToOriginalSharedLibFlags[lang] = sharedLibFlags;
+ }
+ } // end for each language
+
+ // Now load files that can override any settings on the platform or for
+ // the project First load the project compatibility file if it is in
+ // cmake
+ std::string projectCompatibility = mf->GetDefinition("CMAKE_ROOT");
+ projectCompatibility += "/Modules/";
+ projectCompatibility += mf->GetSafeDefinition("PROJECT_NAME");
+ projectCompatibility += "Compatibility.cmake";
+ if(cmSystemTools::FileExists(projectCompatibility.c_str()))
+ {
+ mf->ReadListFile(0,projectCompatibility.c_str());
+ }
+}
+
+//----------------------------------------------------------------------------
+const char*
+cmGlobalGenerator::GetLanguageOutputExtension(cmSourceFile const& source)
+{
+ if(const char* lang = source.GetLanguage())
+ {
+ if(this->LanguageToOutputExtension.count(lang) > 0)
+ {
+ return this->LanguageToOutputExtension[lang].c_str();
+ }
+ }
+ else
+ {
+ // if no language is found then check to see if it is already an
+ // ouput extension for some language. In that case it should be ignored
+ // and in this map, so it will not be compiled but will just be used.
+ std::string const& ext = source.GetExtension();
+ if(!ext.empty())
+ {
+ if(this->OutputExtensions.count(ext))
+ {
+ return ext.c_str();
+ }
+ }
+ }
+ return "";
+}
+
+
+const char* cmGlobalGenerator::GetLanguageFromExtension(const char* ext)
+{
+ // if there is an extension and it starts with . then move past the
+ // . because the extensions are not stored with a . in the map
+ if(ext && *ext == '.')
+ {
+ ++ext;
+ }
+ if(this->ExtensionToLanguage.count(ext) > 0)
+ {
+ return this->ExtensionToLanguage[ext].c_str();
+ }
+ return 0;
+}
+
+/* SetLanguageEnabled() is now split in two parts:
+at first the enabled-flag is set. This can then be used in EnabledLanguage()
+for checking whether the language is already enabled. After setting this
+flag still the values from the cmake variables have to be copied into the
+internal maps, this is done in SetLanguageEnabledMaps() which is called
+after the system- and compiler specific files have been loaded.
+
+This split was done originally so that compiler-specific configuration
+files could change the object file extension
+(CMAKE_<LANG>_OUTPUT_EXTENSION) before the CMake variables were copied
+to the C++ maps.
+*/
+void cmGlobalGenerator::SetLanguageEnabled(const char* l, cmMakefile* mf)
+{
+ this->SetLanguageEnabledFlag(l, mf);
+ this->SetLanguageEnabledMaps(l, mf);
+}
+
+void cmGlobalGenerator::SetLanguageEnabledFlag(const char* l, cmMakefile* mf)
+{
+ this->LanguageEnabled[l] = true;
+
+ // Fill the language-to-extension map with the current variable
+ // settings to make sure it is available for the try_compile()
+ // command source file signature. In SetLanguageEnabledMaps this
+ // will be done again to account for any compiler- or
+ // platform-specific entries.
+ this->FillExtensionToLanguageMap(l, mf);
+}
+
+void cmGlobalGenerator::SetLanguageEnabledMaps(const char* l, cmMakefile* mf)
+{
+ // use LanguageToLinkerPreference to detect whether this functions has
+ // run before
+ if (this->LanguageToLinkerPreference.find(l) !=
+ this->LanguageToLinkerPreference.end())
+ {
+ return;
+ }
+
+ std::string linkerPrefVar = std::string("CMAKE_") +
+ std::string(l) + std::string("_LINKER_PREFERENCE");
+ const char* linkerPref = mf->GetDefinition(linkerPrefVar.c_str());
+ int preference = 0;
+ if(linkerPref)
+ {
+ if (sscanf(linkerPref, "%d", &preference)!=1)
+ {
+ // backward compatibility: before 2.6 LINKER_PREFERENCE
+ // was either "None" or "Prefered", and only the first character was
+ // tested. So if there is a custom language out there and it is
+ // "Prefered", set its preference high
+ if (linkerPref[0]=='P')
+ {
+ preference = 100;
+ }
+ else
+ {
+ preference = 0;
+ }
+ }
+ }
+
+ if (preference < 0)
+ {
+ std::string msg = linkerPrefVar;
+ msg += " is negative, adjusting it to 0";
+ cmSystemTools::Message(msg.c_str(), "Warning");
+ preference = 0;
+ }
+
+ this->LanguageToLinkerPreference[l] = preference;
+
+ std::string outputExtensionVar = std::string("CMAKE_") +
+ std::string(l) + std::string("_OUTPUT_EXTENSION");
+ const char* outputExtension = mf->GetDefinition(outputExtensionVar.c_str());
+ if(outputExtension)
+ {
+ this->LanguageToOutputExtension[l] = outputExtension;
+ this->OutputExtensions[outputExtension] = outputExtension;
+ if(outputExtension[0] == '.')
+ {
+ this->OutputExtensions[outputExtension+1] = outputExtension+1;
+ }
+ }
+
+ // The map was originally filled by SetLanguageEnabledFlag, but
+ // since then the compiler- and platform-specific files have been
+ // loaded which might have added more entries.
+ this->FillExtensionToLanguageMap(l, mf);
+
+ std::string ignoreExtensionsVar = std::string("CMAKE_") +
+ std::string(l) + std::string("_IGNORE_EXTENSIONS");
+ std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar.c_str());
+ std::vector<std::string> extensionList;
+ cmSystemTools::ExpandListArgument(ignoreExts, extensionList);
+ for(std::vector<std::string>::iterator i = extensionList.begin();
+ i != extensionList.end(); ++i)
+ {
+ this->IgnoreExtensions[*i] = true;
+ }
+
+}
+
+void cmGlobalGenerator::FillExtensionToLanguageMap(const char* l,
+ cmMakefile* mf)
+{
+ std::string extensionsVar = std::string("CMAKE_") +
+ std::string(l) + std::string("_SOURCE_FILE_EXTENSIONS");
+ std::string exts = mf->GetSafeDefinition(extensionsVar.c_str());
+ std::vector<std::string> extensionList;
+ cmSystemTools::ExpandListArgument(exts, extensionList);
+ for(std::vector<std::string>::iterator i = extensionList.begin();
+ i != extensionList.end(); ++i)
+ {
+ this->ExtensionToLanguage[*i] = l;
+ }
+}
+
+bool cmGlobalGenerator::IgnoreFile(const char* l)
+{
+ if(this->GetLanguageFromExtension(l))
+ {
+ return false;
+ }
+ return (this->IgnoreExtensions.count(l) > 0);
+}
+
+bool cmGlobalGenerator::GetLanguageEnabled(const char* l) const
+{
+ return (this->LanguageEnabled.find(l)!= this->LanguageEnabled.end());
+}
+
+void cmGlobalGenerator::ClearEnabledLanguages()
+{
+ this->LanguageEnabled.clear();
+}
+
+bool cmGlobalGenerator::IsDependedOn(const char* project,
+ cmTarget* targetIn)
+{
+ // Get all local gens for this project
+ std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project];
+ // loop over local gens and get the targets for each one
+ for(unsigned int i = 0; i < gens->size(); ++i)
+ {
+ cmTargets& targets = (*gens)[i]->GetMakefile()->GetTargets();
+ for (cmTargets::iterator l = targets.begin();
+ l != targets.end(); l++)
+ {
+ cmTarget& target = l->second;
+ TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(target);
+ if(tgtdeps.count(targetIn))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void cmGlobalGenerator::Configure()
+{
+ this->FirstTimeProgress = 0.0f;
+ this->ClearGeneratorTargets();
+ this->ClearExportSets();
+ // Delete any existing cmLocalGenerators
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ delete this->LocalGenerators[i];
+ }
+ this->LocalGenerators.clear();
+ this->TargetDependencies.clear();
+ this->TotalTargets.clear();
+ this->LocalGeneratorToTargetMap.clear();
+ this->ProjectMap.clear();
+ this->RuleHashes.clear();
+ this->DirectoryContentMap.clear();
+ this->BinaryDirectories.clear();
+
+ // start with this directory
+ cmLocalGenerator *lg = this->CreateLocalGenerator();
+ this->LocalGenerators.push_back(lg);
+
+ // set the Start directories
+ cmMakefile* mf = lg->GetMakefile();
+ lg->GetMakefile()->SetStartDirectory
+ (this->CMakeInstance->GetStartDirectory());
+ lg->GetMakefile()->SetStartOutputDirectory
+ (this->CMakeInstance->GetStartOutputDirectory());
+ lg->GetMakefile()->MakeStartDirectoriesCurrent();
+
+ this->BinaryDirectories.insert(mf->GetStartOutputDirectory());
+
+ // now do it
+ lg->Configure();
+
+ // update the cache entry for the number of local generators, this is used
+ // for progress
+ char num[100];
+ sprintf(num,"%d",static_cast<int>(this->LocalGenerators.size()));
+ this->GetCMakeInstance()->AddCacheEntry
+ ("CMAKE_NUMBER_OF_LOCAL_GENERATORS", num,
+ "number of local generators", cmCacheManager::INTERNAL);
+
+ // check for link libraries and include directories containing "NOTFOUND"
+ // and for infinite loops
+ this->CheckLocalGenerators();
+
+ // at this point this->LocalGenerators has been filled,
+ // so create the map from project name to vector of local generators
+ this->FillProjectMap();
+
+ if ( this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE)
+ {
+ const char* msg = "Configuring done";
+ if(cmSystemTools::GetErrorOccuredFlag())
+ {
+ msg = "Configuring incomplete, errors occurred!";
+ }
+ this->CMakeInstance->UpdateProgress(msg, -1);
+ }
+}
+
+bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
+{
+ // If the property is not enabled then okay.
+ if(!this->CMakeInstance
+ ->GetPropertyAsBool("ALLOW_DUPLICATE_CUSTOM_TARGETS"))
+ {
+ return true;
+ }
+
+ // This generator does not support duplicate custom targets.
+ cmOStringStream e;
+ e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
+ << "global property. "
+ << "The \"" << this->GetName() << "\" generator does not support "
+ << "duplicate custom targets. "
+ << "Consider using a Makefiles generator or fix the project to not "
+ << "use duplicat target names.";
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+}
+
+void cmGlobalGenerator::Generate()
+{
+ // Some generators track files replaced during the Generate.
+ // Start with an empty vector:
+ this->FilesReplacedDuringGenerate.clear();
+
+ // Check whether this generator is allowed to run.
+ if(!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS())
+ {
+ return;
+ }
+
+ // Check that all targets are valid.
+ if(!this->CheckTargets())
+ {
+ return;
+ }
+
+ // Iterate through all targets and set up automoc for those which have
+ // the AUTOMOC property set
+ this->CreateAutomocTargets();
+
+ // For each existing cmLocalGenerator
+ unsigned int i;
+
+ // Put a copy of each global target in every directory.
+ cmTargets globalTargets;
+ this->CreateDefaultGlobalTargets(&globalTargets);
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ cmMakefile* mf = this->LocalGenerators[i]->GetMakefile();
+ cmTargets* targets = &(mf->GetTargets());
+ cmTargets::iterator tit;
+ for ( tit = globalTargets.begin(); tit != globalTargets.end(); ++ tit )
+ {
+ (*targets)[tit->first] = tit->second;
+ (*targets)[tit->first].SetMakefile(mf);
+ }
+ }
+
+ // Add generator specific helper commands
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ this->LocalGenerators[i]->AddHelperCommands();
+ }
+
+ // Trace the dependencies, after that no custom commands should be added
+ // because their dependencies might not be handled correctly
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ this->LocalGenerators[i]->TraceDependencies();
+ }
+
+ // Compute the manifest of main targets generated.
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ this->LocalGenerators[i]->GenerateTargetManifest();
+ }
+
+ // Create per-target generator information.
+ this->CreateGeneratorTargets();
+
+ // Compute the inter-target dependencies.
+ if(!this->ComputeTargetDepends())
+ {
+ return;
+ }
+
+ // Create a map from local generator to the complete set of targets
+ // it builds by default.
+ this->FillLocalGeneratorToTargetMap();
+
+ // Generate project files
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ this->SetCurrentLocalGenerator(this->LocalGenerators[i]);
+ this->LocalGenerators[i]->Generate();
+ this->LocalGenerators[i]->GenerateInstallRules();
+ this->LocalGenerators[i]->GenerateTestFiles();
+ this->CMakeInstance->UpdateProgress("Generating",
+ (static_cast<float>(i)+1.0f)/
+ static_cast<float>(this->LocalGenerators.size()));
+ }
+ this->SetCurrentLocalGenerator(0);
+
+ // Update rule hashes.
+ this->CheckRuleHashes();
+
+ this->WriteSummary();
+
+ if (this->ExtraGenerator != 0)
+ {
+ this->ExtraGenerator->Generate();
+ }
+
+ this->CMakeInstance->UpdateProgress("Generating done", -1);
+}
+
+//----------------------------------------------------------------------------
+bool cmGlobalGenerator::ComputeTargetDepends()
+{
+ cmComputeTargetDepends ctd(this);
+ if(!ctd.Compute())
+ {
+ return false;
+ }
+ std::vector<cmTarget*> const& targets = ctd.GetTargets();
+ for(std::vector<cmTarget*>::const_iterator ti = targets.begin();
+ ti != targets.end(); ++ti)
+ {
+ ctd.GetTargetDirectDepends(*ti, this->TargetDependencies[*ti]);
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmGlobalGenerator::CheckTargets()
+{
+ // Make sure all targets can find their source files.
+ for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
+ {
+ cmTargets& targets =
+ this->LocalGenerators[i]->GetMakefile()->GetTargets();
+ for(cmTargets::iterator ti = targets.begin();
+ ti != targets.end(); ++ti)
+ {
+ cmTarget& target = ti->second;
+ if(target.GetType() == cmTarget::EXECUTABLE ||
+ target.GetType() == cmTarget::STATIC_LIBRARY ||
+ target.GetType() == cmTarget::SHARED_LIBRARY ||
+ target.GetType() == cmTarget::MODULE_LIBRARY ||
+ target.GetType() == cmTarget::UTILITY)
+ {
+ if(!target.FindSourceFiles())
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::CreateAutomocTargets()
+{
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
+ {
+ cmTargets& targets =
+ this->LocalGenerators[i]->GetMakefile()->GetTargets();
+ for(cmTargets::iterator ti = targets.begin();
+ ti != targets.end(); ++ti)
+ {
+ cmTarget& target = ti->second;
+ if(target.GetType() == cmTarget::EXECUTABLE ||
+ target.GetType() == cmTarget::STATIC_LIBRARY ||
+ target.GetType() == cmTarget::SHARED_LIBRARY ||
+ target.GetType() == cmTarget::MODULE_LIBRARY)
+ {
+ if(target.GetPropertyAsBool("AUTOMOC") && !target.IsImported())
+ {
+ cmQtAutomoc automoc;
+ automoc.SetupAutomocTarget(&target);
+ }
+ }
+ }
+ }
+#endif
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::CreateGeneratorTargets()
+{
+ // Construct per-target generator information.
+ for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
+ {
+ cmTargets& targets =
+ this->LocalGenerators[i]->GetMakefile()->GetTargets();
+ for(cmTargets::iterator ti = targets.begin();
+ ti != targets.end(); ++ti)
+ {
+ cmTarget* t = &ti->second;
+ cmGeneratorTarget* gt = new cmGeneratorTarget(t);
+ this->GeneratorTargets[t] = gt;
+ this->ComputeTargetObjects(gt);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::ClearGeneratorTargets()
+{
+ for(GeneratorTargetsType::iterator i = this->GeneratorTargets.begin();
+ i != this->GeneratorTargets.end(); ++i)
+ {
+ delete i->second;
+ }
+ this->GeneratorTargets.clear();
+}
+
+//----------------------------------------------------------------------------
+cmGeneratorTarget* cmGlobalGenerator::GetGeneratorTarget(cmTarget* t) const
+{
+ GeneratorTargetsType::const_iterator ti = this->GeneratorTargets.find(t);
+ if(ti == this->GeneratorTargets.end())
+ {
+ this->CMakeInstance->IssueMessage(
+ cmake::INTERNAL_ERROR, "Missing cmGeneratorTarget instance!",
+ cmListFileBacktrace());
+ return 0;
+ }
+ return ti->second;
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::ComputeTargetObjects(cmGeneratorTarget*) const
+{
+ // Implemented in generator subclasses that need this.
+}
+
+void cmGlobalGenerator::CheckLocalGenerators()
+{
+ std::map<cmStdString, cmStdString> notFoundMap;
+// std::set<cmStdString> notFoundMap;
+ // after it is all done do a ConfigureFinalPass
+ cmCacheManager* manager = 0;
+ for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ manager = this->LocalGenerators[i]->GetMakefile()->GetCacheManager();
+ this->LocalGenerators[i]->ConfigureFinalPass();
+ cmTargets & targets =
+ this->LocalGenerators[i]->GetMakefile()->GetTargets();
+ for (cmTargets::iterator l = targets.begin();
+ l != targets.end(); l++)
+ {
+ const cmTarget::LinkLibraryVectorType& libs =
+ l->second.GetOriginalLinkLibraries();
+ for(cmTarget::LinkLibraryVectorType::const_iterator lib = libs.begin();
+ lib != libs.end(); ++lib)
+ {
+ if(lib->first.size() > 9 &&
+ cmSystemTools::IsNOTFOUND(lib->first.c_str()))
+ {
+ std::string varName = lib->first.substr(0, lib->first.size()-9);
+ cmCacheManager::CacheIterator it =
+ manager->GetCacheIterator(varName.c_str());
+ if(it.GetPropertyAsBool("ADVANCED"))
+ {
+ varName += " (ADVANCED)";
+ }
+ std::string text = notFoundMap[varName];
+ text += "\n linked by target \"";
+ text += l->second.GetName();
+ text += "\" in directory ";
+ text+=this->LocalGenerators[i]->GetMakefile()->GetCurrentDirectory();
+ notFoundMap[varName] = text;
+ }
+ }
+ std::vector<std::string> incs;
+ this->LocalGenerators[i]->GetIncludeDirectories(incs, &l->second);
+
+ for( std::vector<std::string>::const_iterator incDir = incs.begin();
+ incDir != incs.end(); ++incDir)
+ {
+ if(incDir->size() > 9 &&
+ cmSystemTools::IsNOTFOUND(incDir->c_str()))
+ {
+ std::string varName = incDir->substr(0, incDir->size()-9);
+ cmCacheManager::CacheIterator it =
+ manager->GetCacheIterator(varName.c_str());
+ if(it.GetPropertyAsBool("ADVANCED"))
+ {
+ varName += " (ADVANCED)";
+ }
+ std::string text = notFoundMap[varName];
+ text += "\n used as include directory in directory ";
+ text += this->LocalGenerators[i]
+ ->GetMakefile()->GetCurrentDirectory();
+ notFoundMap[varName] = text;
+ }
+ }
+ }
+ this->CMakeInstance->UpdateProgress
+ ("Configuring", 0.9f+0.1f*(static_cast<float>(i)+1.0f)/
+ static_cast<float>(this->LocalGenerators.size()));
+ }
+
+ if(notFoundMap.size())
+ {
+ std::string notFoundVars;
+ for(std::map<cmStdString, cmStdString>::const_iterator
+ ii = notFoundMap.begin();
+ ii != notFoundMap.end();
+ ++ii)
+ {
+ notFoundVars += ii->first;
+ notFoundVars += ii->second;
+ notFoundVars += "\n";
+ }
+ cmSystemTools::Error("The following variables are used in this project, "
+ "but they are set to NOTFOUND.\n"
+ "Please set them or make sure they are set and "
+ "tested correctly in the CMake files:\n",
+ notFoundVars.c_str());
+ }
+}
+
+int cmGlobalGenerator::TryCompile(const char *srcdir, const char *bindir,
+ const char *projectName,
+ const char *target, bool fast,
+ std::string *output, cmMakefile *mf)
+{
+ // if this is not set, then this is a first time configure
+ // and there is a good chance that the try compile stuff will
+ // take the bulk of the time, so try and guess some progress
+ // by getting closer and closer to 100 without actually getting there.
+ if (!this->CMakeInstance->GetCacheManager()->GetCacheValue
+ ("CMAKE_NUMBER_OF_LOCAL_GENERATORS"))
+ {
+ // If CMAKE_NUMBER_OF_LOCAL_GENERATORS is not set
+ // we are in the first time progress and we have no
+ // idea how long it will be. So, just move 1/10th of the way
+ // there each time, and don't go over 95%
+ this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) /30.0f);
+ if(this->FirstTimeProgress > 0.95f)
+ {
+ this->FirstTimeProgress = 0.95f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring",
+ this->FirstTimeProgress);
+ }
+
+ std::string makeCommand = this->CMakeInstance->
+ GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM");
+ if(makeCommand.size() == 0)
+ {
+ cmSystemTools::Error(
+ "Generator cannot find the appropriate make command.");
+ return 1;
+ }
+
+ std::string newTarget;
+ if (target && strlen(target))
+ {
+ newTarget += target;
+#if 0
+#if defined(_WIN32) || defined(__CYGWIN__)
+ std::string tmp = target;
+ // if the target does not already end in . something
+ // then assume .exe
+ if(tmp.size() < 4 || tmp[tmp.size()-4] != '.')
+ {
+ newTarget += ".exe";
+ }
+#endif // WIN32
+#endif
+ }
+ const char* config = mf->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+ return this->Build(srcdir,bindir,projectName,
+ newTarget.c_str(),
+ output,makeCommand.c_str(),config,false,fast,
+ this->TryCompileTimeout);
+}
+
+std::string cmGlobalGenerator
+::GenerateBuildCommand(const char* makeProgram, const char *projectName,
+ const char* additionalOptions, const char *targetName,
+ const char* config, bool ignoreErrors, bool)
+{
+ // Project name and config are not used yet.
+ (void)projectName;
+ (void)config;
+
+ std::string makeCommand =
+ cmSystemTools::ConvertToUnixOutputPath(makeProgram);
+
+ // Since we have full control over the invocation of nmake, let us
+ // make it quiet.
+ if ( strcmp(this->GetName(), "NMake Makefiles") == 0 )
+ {
+ makeCommand += " /NOLOGO ";
+ }
+ if ( ignoreErrors )
+ {
+ makeCommand += " -i";
+ }
+ if ( additionalOptions )
+ {
+ makeCommand += " ";
+ makeCommand += additionalOptions;
+ }
+ if ( targetName )
+ {
+ makeCommand += " ";
+ makeCommand += targetName;
+ }
+ return makeCommand;
+}
+
+int cmGlobalGenerator::Build(
+ const char *, const char *bindir,
+ const char *projectName, const char *target,
+ std::string *output,
+ const char *makeCommandCSTR,
+ const char *config,
+ bool clean, bool fast,
+ double timeout,
+ cmSystemTools::OutputOption outputflag,
+ const char* extraOptions,
+ std::vector<std::string> const& nativeOptions)
+{
+ /**
+ * Run an executable command and put the stdout in output.
+ */
+ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(bindir);
+ if(output)
+ {
+ *output += "Change Dir: ";
+ *output += bindir;
+ *output += "\n";
+ }
+
+ int retVal;
+ bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
+ cmSystemTools::SetRunCommandHideConsole(true);
+ std::string outputBuffer;
+ std::string* outputPtr = 0;
+ if(output)
+ {
+ outputPtr = &outputBuffer;
+ }
+
+ // should we do a clean first?
+ if (clean)
+ {
+ std::string cleanCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName,
+ 0, "clean", config, false, fast);
+ if(output)
+ {
+ *output += "\nRun Clean Command:";
+ *output += cleanCommand;
+ *output += "\n";
+ }
+
+ if (!cmSystemTools::RunSingleCommand(cleanCommand.c_str(), outputPtr,
+ &retVal, 0, outputflag, timeout))
+ {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ cmSystemTools::Error("Generator: execution of make clean failed.");
+ if (output)
+ {
+ *output += *outputPtr;
+ *output += "\nGenerator: execution of make clean failed.\n";
+ }
+
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd.c_str());
+ return 1;
+ }
+ if (output)
+ {
+ *output += *outputPtr;
+ }
+ }
+
+ // now build
+ std::string makeCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName,
+ extraOptions, target,
+ config, false, fast);
+ if(output)
+ {
+ *output += "\nRun Build Command:";
+ *output += makeCommand;
+ *output += "\n";
+ }
+
+ std::vector<cmStdString> command =
+ cmSystemTools::ParseArguments(makeCommand.c_str());
+ for(std::vector<std::string>::const_iterator ni = nativeOptions.begin();
+ ni != nativeOptions.end(); ++ni)
+ {
+ command.push_back(*ni);
+ }
+
+ if (!cmSystemTools::RunSingleCommand(command, outputPtr,
+ &retVal, 0, outputflag, timeout))
+ {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ cmSystemTools::Error
+ ("Generator: execution of make failed. Make command was: ",
+ makeCommand.c_str());
+ if (output)
+ {
+ *output += *outputPtr;
+ *output += "\nGenerator: execution of make failed. Make command was: "
+ + makeCommand + "\n";
+ }
+
+ // return to the original directory
+ cmSystemTools::ChangeDirectory(cwd.c_str());
+ return 1;
+ }
+ if (output)
+ {
+ *output += *outputPtr;
+ }
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+
+ // The SGI MipsPro 7.3 compiler does not return an error code when
+ // the source has a #error in it! This is a work-around for such
+ // compilers.
+ if((retVal == 0) && (output->find("#error") != std::string::npos))
+ {
+ retVal = 1;
+ }
+
+ cmSystemTools::ChangeDirectory(cwd.c_str());
+ return retVal;
+}
+
+void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg)
+{
+ this->LocalGenerators.push_back(lg);
+
+ // update progress
+ // estimate how many lg there will be
+ const char *numGenC =
+ this->CMakeInstance->GetCacheManager()->GetCacheValue
+ ("CMAKE_NUMBER_OF_LOCAL_GENERATORS");
+
+ if (!numGenC)
+ {
+ // If CMAKE_NUMBER_OF_LOCAL_GENERATORS is not set
+ // we are in the first time progress and we have no
+ // idea how long it will be. So, just move half way
+ // there each time, and don't go over 95%
+ this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) /30.0f);
+ if(this->FirstTimeProgress > 0.95f)
+ {
+ this->FirstTimeProgress = 0.95f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring",
+ this->FirstTimeProgress);
+ return;
+ }
+
+ int numGen = atoi(numGenC);
+ float prog = 0.9f*static_cast<float>(this->LocalGenerators.size())/
+ static_cast<float>(numGen);
+ if (prog > 0.9f)
+ {
+ prog = 0.9f;
+ }
+ this->CMakeInstance->UpdateProgress("Configuring", prog);
+}
+
+void cmGlobalGenerator::AddInstallComponent(const char* component)
+{
+ if(component && *component)
+ {
+ this->InstallComponents.insert(component);
+ }
+}
+
+void cmGlobalGenerator::AddTargetToExports(const char* exportSetName,
+ cmTarget* target,
+ cmInstallTargetGenerator* archive,
+ cmInstallTargetGenerator* runTime,
+ cmInstallTargetGenerator* library,
+ cmInstallTargetGenerator* framework,
+ cmInstallTargetGenerator* bundle,
+ cmInstallFilesGenerator* headers)
+{
+ if ((exportSetName) && (*exportSetName) && (target))
+ {
+ cmTargetExport* te = new cmTargetExport(target, archive, runTime, library,
+ framework, bundle, headers);
+ this->ExportSets[exportSetName].push_back(te);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::ClearExportSets()
+{
+ for(std::map<cmStdString, std::vector<cmTargetExport*> >::iterator
+ setIt = this->ExportSets.begin();
+ setIt != this->ExportSets.end(); ++setIt)
+ {
+ for(unsigned int i = 0; i < setIt->second.size(); ++i)
+ {
+ delete setIt->second[i];
+ }
+ }
+ this->ExportSets.clear();
+}
+
+const std::vector<cmTargetExport*>* cmGlobalGenerator::GetExportSet(
+ const char* name) const
+{
+ std::map<cmStdString, std::vector<cmTargetExport*> >::const_iterator
+ exportSetIt = this->ExportSets.find(name);
+ if (exportSetIt != this->ExportSets.end())
+ {
+ return &exportSetIt->second;
+ }
+
+ return 0;
+}
+
+
+void cmGlobalGenerator::EnableInstallTarget()
+{
+ this->InstallTargetEnabled = true;
+}
+
+cmLocalGenerator *cmGlobalGenerator::CreateLocalGenerator()
+{
+ cmLocalGenerator *lg = new cmLocalGenerator;
+ lg->SetGlobalGenerator(this);
+ return lg;
+}
+
+void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator *gen,
+ cmMakefile* mf)
+{
+ this->SetConfiguredFilesPath(gen);
+ this->TryCompileOuterMakefile = mf;
+ const char* make =
+ gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
+ this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", make,
+ "make program",
+ cmCacheManager::FILEPATH);
+ // copy the enabled languages
+ this->LanguageEnabled = gen->LanguageEnabled;
+ this->LanguagesReady = gen->LanguagesReady;
+ this->ExtensionToLanguage = gen->ExtensionToLanguage;
+ this->IgnoreExtensions = gen->IgnoreExtensions;
+ this->LanguageToOutputExtension = gen->LanguageToOutputExtension;
+ this->LanguageToLinkerPreference = gen->LanguageToLinkerPreference;
+ this->OutputExtensions = gen->OutputExtensions;
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen)
+{
+ if(!gen->ConfiguredFilesPath.empty())
+ {
+ this->ConfiguredFilesPath = gen->ConfiguredFilesPath;
+ }
+ else
+ {
+ this->ConfiguredFilesPath = gen->CMakeInstance->GetHomeOutputDirectory();
+ this->ConfiguredFilesPath += cmake::GetCMakeFilesDirectory();
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::GetDocumentation(cmDocumentationEntry& entry) const
+{
+ entry.Name = this->GetName();
+ entry.Brief = "";
+ entry.Full = "";
+}
+
+bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
+ cmLocalGenerator* gen)
+{
+ if(!gen || gen == root)
+ {
+ // No directory excludes itself.
+ return false;
+ }
+
+ if(gen->GetMakefile()->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
+ {
+ // This directory is excluded from its parent.
+ return true;
+ }
+
+ // This directory is included in its parent. Check whether the
+ // parent is excluded.
+ return this->IsExcluded(root, gen->GetParent());
+}
+
+bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
+ cmTarget& target)
+{
+ if(target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
+ {
+ // This target is excluded from its directory.
+ return true;
+ }
+ else
+ {
+ // This target is included in its directory. Check whether the
+ // directory is excluded.
+ return this->IsExcluded(root, target.GetMakefile()->GetLocalGenerator());
+ }
+}
+
+void cmGlobalGenerator::GetEnabledLanguages(std::vector<std::string>& lang)
+{
+ for(std::map<cmStdString, bool>::iterator i =
+ this->LanguageEnabled.begin(); i != this->LanguageEnabled.end(); ++i)
+ {
+ lang.push_back(i->first);
+ }
+}
+
+int cmGlobalGenerator::GetLinkerPreference(const char* lang)
+{
+ std::map<cmStdString, int>::const_iterator it =
+ this->LanguageToLinkerPreference.find(lang);
+ if (it != this->LanguageToLinkerPreference.end())
+ {
+ return it->second;
+ }
+ return 0;
+}
+
+void cmGlobalGenerator::FillProjectMap()
+{
+ this->ProjectMap.clear(); // make sure we start with a clean map
+ unsigned int i;
+ for(i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ // for each local generator add all projects
+ cmLocalGenerator *lg = this->LocalGenerators[i];
+ std::string name;
+ do
+ {
+ if (name != lg->GetMakefile()->GetProjectName())
+ {
+ name = lg->GetMakefile()->GetProjectName();
+ this->ProjectMap[name].push_back(this->LocalGenerators[i]);
+ }
+ lg = lg->GetParent();
+ }
+ while (lg);
+ }
+}
+
+
+// Build a map that contains a the set of targets used by each local
+// generator directory level.
+void cmGlobalGenerator::FillLocalGeneratorToTargetMap()
+{
+ this->LocalGeneratorToTargetMap.clear();
+ // Loop over all targets in all local generators.
+ for(std::vector<cmLocalGenerator*>::const_iterator
+ lgi = this->LocalGenerators.begin();
+ lgi != this->LocalGenerators.end(); ++lgi)
+ {
+ cmLocalGenerator* lg = *lgi;
+ cmMakefile* mf = lg->GetMakefile();
+ cmTargets& targets = mf->GetTargets();
+ for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
+ {
+ cmTarget& target = t->second;
+
+ // Consider the directory containing the target and all its
+ // parents until something excludes the target.
+ for(cmLocalGenerator* clg = lg; clg && !this->IsExcluded(clg, target);
+ clg = clg->GetParent())
+ {
+ // This local generator includes the target.
+ std::set<cmTarget*>& targetSet =
+ this->LocalGeneratorToTargetMap[clg];
+ targetSet.insert(&target);
+
+ // Add dependencies of the included target. An excluded
+ // target may still be included if it is a dependency of a
+ // non-excluded target.
+ TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(target);
+ for(TargetDependSet::const_iterator ti = tgtdeps.begin();
+ ti != tgtdeps.end(); ++ti)
+ {
+ targetSet.insert(*ti);
+ }
+ }
+ }
+ }
+}
+
+
+///! Find a local generator by its startdirectory
+cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(const char* start_dir)
+{
+ std::vector<cmLocalGenerator*>* gens = &this->LocalGenerators;
+ for(unsigned int i = 0; i < gens->size(); ++i)
+ {
+ std::string sd = (*gens)[i]->GetMakefile()->GetStartDirectory();
+ if (sd == start_dir)
+ {
+ return (*gens)[i];
+ }
+ }
+ return 0;
+}
+
+
+//----------------------------------------------------------------------------
+cmTarget*
+cmGlobalGenerator::FindTarget(const char* project, const char* name)
+{
+ // if project specific
+ if(project)
+ {
+ std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project];
+ for(unsigned int i = 0; i < gens->size(); ++i)
+ {
+ cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name);
+ if(ret)
+ {
+ return ret;
+ }
+ }
+ }
+ // if all projects/directories
+ else
+ {
+ std::map<cmStdString,cmTarget *>::iterator i =
+ this->TotalTargets.find ( name );
+ if ( i != this->TotalTargets.end() )
+ {
+ return i->second;
+ }
+ i = this->ImportedTargets.find(name);
+ if ( i != this->ImportedTargets.end() )
+ {
+ return i->second;
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+bool cmGlobalGenerator::NameResolvesToFramework(const std::string& libname)
+{
+ if(cmSystemTools::IsPathToFramework(libname.c_str()))
+ {
+ return true;
+ }
+
+ if(cmTarget* tgt = this->FindTarget(0, libname.c_str()))
+ {
+ if(tgt->IsFrameworkOnApple())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------------
+inline std::string removeQuotes(const std::string& s)
+{
+ if(s[0] == '\"' && s[s.size()-1] == '\"')
+ {
+ return s.substr(1, s.size()-2);
+ }
+ return s;
+}
+
+void cmGlobalGenerator::SetCMakeInstance(cmake* cm)
+{
+ // Store a pointer to the cmake object instance.
+ this->CMakeInstance = cm;
+}
+
+void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets)
+{
+ cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
+ const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
+ const char* cmakeCommand = mf->GetRequiredDefinition("CMAKE_COMMAND");
+
+ // CPack
+ std::string workingDir = mf->GetStartOutputDirectory();
+ cmCustomCommandLines cpackCommandLines;
+ std::vector<std::string> depends;
+ cmCustomCommandLine singleLine;
+ singleLine.push_back(this->GetCMakeInstance()->GetCPackCommand());
+ if ( cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.' )
+ {
+ singleLine.push_back("-C");
+ singleLine.push_back(cmakeCfgIntDir);
+ }
+ singleLine.push_back("--config");
+ std::string configFile = mf->GetStartOutputDirectory();;
+ configFile += "/CPackConfig.cmake";
+ std::string relConfigFile = "./CPackConfig.cmake";
+ singleLine.push_back(relConfigFile);
+ cpackCommandLines.push_back(singleLine);
+ if ( this->GetPreinstallTargetName() )
+ {
+ depends.push_back(this->GetPreinstallTargetName());
+ }
+ else
+ {
+ const char* noPackageAll =
+ mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
+ if(!noPackageAll || cmSystemTools::IsOff(noPackageAll))
+ {
+ depends.push_back(this->GetAllTargetName());
+ }
+ }
+ if(cmSystemTools::FileExists(configFile.c_str()))
+ {
+ (*targets)[this->GetPackageTargetName()]
+ = this->CreateGlobalTarget(this->GetPackageTargetName(),
+ "Run CPack packaging tool...",
+ &cpackCommandLines, depends,
+ workingDir.c_str());
+ }
+ // CPack source
+ const char* packageSourceTargetName = this->GetPackageSourceTargetName();
+ if ( packageSourceTargetName )
+ {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ singleLine.push_back(this->GetCMakeInstance()->GetCPackCommand());
+ singleLine.push_back("--config");
+ configFile = mf->GetStartOutputDirectory();;
+ configFile += "/CPackSourceConfig.cmake";
+ relConfigFile = "./CPackSourceConfig.cmake";
+ singleLine.push_back(relConfigFile);
+ if(cmSystemTools::FileExists(configFile.c_str()))
+ {
+ singleLine.push_back(configFile);
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[packageSourceTargetName]
+ = this->CreateGlobalTarget(packageSourceTargetName,
+ "Run CPack packaging tool for source...",
+ &cpackCommandLines, depends,
+ workingDir.c_str()
+ );
+ }
+ }
+
+ // Test
+ if(mf->IsOn("CMAKE_TESTING_ENABLED"))
+ {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ singleLine.push_back(this->GetCMakeInstance()->GetCTestCommand());
+ singleLine.push_back("--force-new-ctest-process");
+ if(cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.')
+ {
+ singleLine.push_back("-C");
+ singleLine.push_back(cmakeCfgIntDir);
+ }
+ else // TODO: This is a hack. Should be something to do with the generator
+ {
+ singleLine.push_back("$(ARGS)");
+ }
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[this->GetTestTargetName()]
+ = this->CreateGlobalTarget(this->GetTestTargetName(),
+ "Running tests...", &cpackCommandLines, depends, 0);
+ }
+
+ //Edit Cache
+ const char* editCacheTargetName = this->GetEditCacheTargetName();
+ if ( editCacheTargetName )
+ {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+
+ // Use CMAKE_EDIT_COMMAND for the edit_cache rule if it is defined.
+ // Otherwise default to the interactive command-line interface.
+ if(mf->GetDefinition("CMAKE_EDIT_COMMAND"))
+ {
+ singleLine.push_back(mf->GetDefinition("CMAKE_EDIT_COMMAND"));
+ singleLine.push_back("-H$(CMAKE_SOURCE_DIR)");
+ singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[editCacheTargetName] =
+ this->CreateGlobalTarget(
+ editCacheTargetName, "Running CMake cache editor...",
+ &cpackCommandLines, depends, 0);
+ }
+ else
+ {
+ singleLine.push_back(cmakeCommand);
+ singleLine.push_back("-i");
+ singleLine.push_back(".");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[editCacheTargetName] =
+ this->CreateGlobalTarget(
+ editCacheTargetName,
+ "Running interactive CMake command-line interface...",
+ &cpackCommandLines, depends, 0);
+ }
+ }
+
+ //Rebuild Cache
+ const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
+ if ( rebuildCacheTargetName )
+ {
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ singleLine.push_back(cmakeCommand);
+ singleLine.push_back("-H$(CMAKE_SOURCE_DIR)");
+ singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[rebuildCacheTargetName] =
+ this->CreateGlobalTarget(
+ rebuildCacheTargetName, "Running CMake to regenerate build system...",
+ &cpackCommandLines, depends, 0);
+ }
+
+ //Install
+ if(this->InstallTargetEnabled)
+ {
+ if(!cmakeCfgIntDir || !*cmakeCfgIntDir || cmakeCfgIntDir[0] == '.')
+ {
+ std::set<cmStdString>* componentsSet = &this->InstallComponents;
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ depends.erase(depends.begin(), depends.end());
+ cmOStringStream ostr;
+ if ( componentsSet->size() > 0 )
+ {
+ ostr << "Available install components are:";
+ std::set<cmStdString>::iterator it;
+ for (
+ it = componentsSet->begin();
+ it != componentsSet->end();
+ ++ it )
+ {
+ ostr << " \"" << it->c_str() << "\"";
+ }
+ }
+ else
+ {
+ ostr << "Only default component available";
+ }
+ singleLine.push_back(ostr.str().c_str());
+ (*targets)["list_install_components"]
+ = this->CreateGlobalTarget("list_install_components",
+ ostr.str().c_str(),
+ &cpackCommandLines, depends, 0);
+ }
+ std::string cmd = cmakeCommand;
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ singleLine.erase(singleLine.begin(), singleLine.end());
+ depends.erase(depends.begin(), depends.end());
+ if ( this->GetPreinstallTargetName() )
+ {
+ depends.push_back(this->GetPreinstallTargetName());
+ }
+ else
+ {
+ const char* noall =
+ mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
+ if(!noall || cmSystemTools::IsOff(noall))
+ {
+ depends.push_back(this->GetAllTargetName());
+ }
+ }
+ if(mf->GetDefinition("CMake_BINARY_DIR"))
+ {
+ // We are building CMake itself. We cannot use the original
+ // executable to install over itself. The generator will
+ // automatically convert this name to the build-time location.
+ cmd = "cmake";
+ }
+ singleLine.push_back(cmd.c_str());
+ if ( cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.' )
+ {
+ std::string cfgArg = "-DBUILD_TYPE=";
+ cfgArg += mf->GetDefinition("CMAKE_CFG_INTDIR");
+ singleLine.push_back(cfgArg);
+ }
+ singleLine.push_back("-P");
+ singleLine.push_back("cmake_install.cmake");
+ cpackCommandLines.push_back(singleLine);
+ (*targets)[this->GetInstallTargetName()] =
+ this->CreateGlobalTarget(
+ this->GetInstallTargetName(), "Install the project...",
+ &cpackCommandLines, depends, 0);
+
+ // install_local
+ if(const char* install_local = this->GetInstallLocalTargetName())
+ {
+ cmCustomCommandLine localCmdLine = singleLine;
+
+ localCmdLine.insert(localCmdLine.begin()+1,
+ "-DCMAKE_INSTALL_LOCAL_ONLY=1");
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ cpackCommandLines.push_back(localCmdLine);
+
+ (*targets)[install_local] =
+ this->CreateGlobalTarget(
+ install_local, "Installing only the local directory...",
+ &cpackCommandLines, depends, 0);
+ }
+
+ // install_strip
+ const char* install_strip = this->GetInstallStripTargetName();
+ if((install_strip !=0) && (mf->IsSet("CMAKE_STRIP")))
+ {
+ cmCustomCommandLine stripCmdLine = singleLine;
+
+ stripCmdLine.insert(stripCmdLine.begin()+1,"-DCMAKE_INSTALL_DO_STRIP=1");
+ cpackCommandLines.erase(cpackCommandLines.begin(),
+ cpackCommandLines.end());
+ cpackCommandLines.push_back(stripCmdLine);
+
+ (*targets)[install_strip] =
+ this->CreateGlobalTarget(
+ install_strip, "Installing the project stripped...",
+ &cpackCommandLines, depends, 0);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+const char* cmGlobalGenerator::GetPredefinedTargetsFolder()
+{
+ const char* prop =
+ this->GetCMakeInstance()->GetProperty("PREDEFINED_TARGETS_FOLDER");
+
+ if (prop)
+ {
+ return prop;
+ }
+
+ return "CMakePredefinedTargets";
+}
+
+//----------------------------------------------------------------------------
+bool cmGlobalGenerator::UseFolderProperty()
+{
+ const char* prop = this->GetCMakeInstance()->GetProperty("USE_FOLDERS");
+
+ // If this property is defined, let the setter turn this on or off...
+ //
+ if (prop)
+ {
+ return cmSystemTools::IsOn(prop);
+ }
+
+ // By default, this feature is OFF, since it is not supported in the
+ // Visual Studio Express editions:
+ //
+ return false;
+}
+
+//----------------------------------------------------------------------------
+cmTarget cmGlobalGenerator::CreateGlobalTarget(
+ const char* name, const char* message,
+ const cmCustomCommandLines* commandLines,
+ std::vector<std::string> depends,
+ const char* workingDirectory)
+{
+ // Package
+ cmTarget target;
+ target.GetProperties().SetCMakeInstance(this->CMakeInstance);
+ target.SetType(cmTarget::GLOBAL_TARGET, name);
+ target.SetProperty("EXCLUDE_FROM_ALL","TRUE");
+
+ std::vector<std::string> no_outputs;
+ std::vector<std::string> no_depends;
+ // Store the custom command in the target.
+ cmCustomCommand cc(0, no_outputs, no_depends, *commandLines, 0,
+ workingDirectory);
+ target.GetPostBuildCommands().push_back(cc);
+ target.SetProperty("EchoString", message);
+ std::vector<std::string>::iterator dit;
+ for ( dit = depends.begin(); dit != depends.end(); ++ dit )
+ {
+ target.AddUtility(dit->c_str());
+ }
+
+ // Organize in the "predefined targets" folder:
+ //
+ if (this->UseFolderProperty())
+ {
+ target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+ }
+
+ return target;
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmGlobalGenerator::GenerateRuleFile(std::string const& output) const
+{
+ std::string ruleFile = output;
+ ruleFile += ".rule";
+ const char* dir = this->GetCMakeCFGIntDir();
+ if(dir && dir[0] == '$')
+ {
+ cmSystemTools::ReplaceString(ruleFile, dir,
+ cmake::GetCMakeFilesDirectory());
+ }
+ return ruleFile;
+}
+
+//----------------------------------------------------------------------------
+std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
+ std::string const& l)
+{
+ if(this->LanguageToOriginalSharedLibFlags.count(l) > 0)
+ {
+ return this->LanguageToOriginalSharedLibFlags[l];
+ }
+ return "";
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::AppendDirectoryForConfig(const char*, const char*,
+ const char*, std::string&)
+{
+ // Subclasses that support multiple configurations should implement
+ // this method to append the subdirectory for the given build
+ // configuration.
+}
+
+//----------------------------------------------------------------------------
+cmGlobalGenerator::TargetDependSet const&
+cmGlobalGenerator::GetTargetDirectDepends(cmTarget & target)
+{
+ return this->TargetDependencies[&target];
+}
+
+void cmGlobalGenerator::AddTarget(cmTarget* t)
+{
+ if(t->IsImported())
+ {
+ this->ImportedTargets[t->GetName()] = t;
+ }
+ else
+ {
+ this->TotalTargets[t->GetName()] = t;
+ }
+}
+
+void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
+ cmExternalMakefileProjectGenerator *extraGenerator)
+{
+ this->ExtraGenerator = extraGenerator;
+ if (this->ExtraGenerator!=0)
+ {
+ this->ExtraGenerator->SetGlobalGenerator(this);
+ }
+}
+
+const char* cmGlobalGenerator::GetExtraGeneratorName() const
+{
+ return this->ExtraGenerator==0 ? 0 : this->ExtraGenerator->GetName();
+}
+
+void cmGlobalGenerator::FileReplacedDuringGenerate(const std::string& filename)
+{
+ this->FilesReplacedDuringGenerate.push_back(filename);
+}
+
+void
+cmGlobalGenerator
+::GetFilesReplacedDuringGenerate(std::vector<std::string>& filenames)
+{
+ filenames.clear();
+ std::copy(
+ this->FilesReplacedDuringGenerate.begin(),
+ this->FilesReplacedDuringGenerate.end(),
+ std::back_inserter(filenames));
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::GetTargetSets(TargetDependSet& projectTargets,
+ TargetDependSet& originalTargets,
+ cmLocalGenerator* root,
+ GeneratorVector const& generators)
+{
+ // loop over all local generators
+ for(std::vector<cmLocalGenerator*>::const_iterator i = generators.begin();
+ i != generators.end(); ++i)
+ {
+ // check to make sure generator is not excluded
+ if(this->IsExcluded(root, *i))
+ {
+ continue;
+ }
+ cmMakefile* mf = (*i)->GetMakefile();
+ // Get the targets in the makefile
+ cmTargets &tgts = mf->GetTargets();
+ // loop over all the targets
+ for (cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l)
+ {
+ cmTarget* target = &l->second;
+ if(this->IsRootOnlyTarget(target) &&
+ target->GetMakefile() != root->GetMakefile())
+ {
+ continue;
+ }
+ // put the target in the set of original targets
+ originalTargets.insert(target);
+ // Get the set of targets that depend on target
+ this->AddTargetDepends(target, projectTargets);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+bool cmGlobalGenerator::IsRootOnlyTarget(cmTarget* target)
+{
+ return (target->GetType() == cmTarget::GLOBAL_TARGET ||
+ strcmp(target->GetName(), this->GetAllTargetName()) == 0);
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::AddTargetDepends(cmTarget* target,
+ TargetDependSet& projectTargets)
+{
+ // add the target itself
+ if(projectTargets.insert(target).second)
+ {
+ // This is the first time we have encountered the target.
+ // Recursively follow its dependencies.
+ TargetDependSet const& ts = this->GetTargetDirectDepends(*target);
+ for(TargetDependSet::const_iterator i = ts.begin(); i != ts.end(); ++i)
+ {
+ cmTarget* dtarget = *i;
+ this->AddTargetDepends(dtarget, projectTargets);
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::AddToManifest(const char* config,
+ std::string const& f)
+{
+ // Add to the main manifest for this configuration.
+ this->TargetManifest[config].insert(f);
+
+ // Add to the content listing for the file's directory.
+ std::string dir = cmSystemTools::GetFilenamePath(f);
+ std::string file = cmSystemTools::GetFilenameName(f);
+ this->DirectoryContentMap[dir].insert(file);
+}
+
+//----------------------------------------------------------------------------
+std::set<cmStdString> const&
+cmGlobalGenerator::GetDirectoryContent(std::string const& dir, bool needDisk)
+{
+ DirectoryContent& dc = this->DirectoryContentMap[dir];
+ if(needDisk && !dc.LoadedFromDisk)
+ {
+ // Load the directory content from disk.
+ cmsys::Directory d;
+ if(d.Load(dir.c_str()))
+ {
+ unsigned long n = d.GetNumberOfFiles();
+ for(unsigned long i = 0; i < n; ++i)
+ {
+ const char* f = d.GetFile(i);
+ if(strcmp(f, ".") != 0 && strcmp(f, "..") != 0)
+ {
+ dc.insert(f);
+ }
+ }
+ }
+ dc.LoadedFromDisk = true;
+ }
+ return dc;
+}
+
+//----------------------------------------------------------------------------
+void
+cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
+ std::string const& content)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Ignore if there are no outputs.
+ if(outputs.empty())
+ {
+ return;
+ }
+
+ // Compute a hash of the rule.
+ RuleHash hash;
+ {
+ unsigned char const* data =
+ reinterpret_cast<unsigned char const*>(content.c_str());
+ int length = static_cast<int>(content.length());
+ cmsysMD5* sum = cmsysMD5_New();
+ cmsysMD5_Initialize(sum);
+ cmsysMD5_Append(sum, data, length);
+ cmsysMD5_FinalizeHex(sum, hash.Data);
+ cmsysMD5_Delete(sum);
+ }
+
+ // Shorten the output name (in expected use case).
+ cmLocalGenerator* lg = this->GetLocalGenerators()[0];
+ std::string fname = lg->Convert(outputs[0].c_str(),
+ cmLocalGenerator::HOME_OUTPUT);
+
+ // Associate the hash with this output.
+ this->RuleHashes[fname] = hash;
+#else
+ (void)outputs;
+ (void)content;
+#endif
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::CheckRuleHashes()
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
+ std::string pfile = home;
+ pfile += this->GetCMakeInstance()->GetCMakeFilesDirectory();
+ pfile += "/CMakeRuleHashes.txt";
+ this->CheckRuleHashes(pfile, home);
+ this->WriteRuleHashes(pfile);
+#endif
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
+ std::string const& home)
+{
+#if defined(_WIN32) || defined(__CYGWIN__)
+ std::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
+#else
+ std::ifstream fin(pfile.c_str(), std::ios::in);
+#endif
+ if(!fin)
+ {
+ return;
+ }
+ std::string line;
+ std::string fname;
+ while(cmSystemTools::GetLineFromStream(fin, line))
+ {
+ // Line format is a 32-byte hex string followed by a space
+ // followed by a file name (with no escaping).
+
+ // Skip blank and comment lines.
+ if(line.size() < 34 || line[0] == '#')
+ {
+ continue;
+ }
+
+ // Get the filename.
+ fname = line.substr(33, line.npos);
+
+ // Look for a hash for this file's rule.
+ std::map<cmStdString, RuleHash>::const_iterator rhi =
+ this->RuleHashes.find(fname);
+ if(rhi != this->RuleHashes.end())
+ {
+ // Compare the rule hash in the file to that we were given.
+ if(strncmp(line.c_str(), rhi->second.Data, 32) != 0)
+ {
+ // The rule has changed. Delete the output so it will be
+ // built again.
+ fname = cmSystemTools::CollapseFullPath(fname.c_str(), home.c_str());
+ cmSystemTools::RemoveFile(fname.c_str());
+ }
+ }
+ else
+ {
+ // We have no hash for a rule previously listed. This may be a
+ // case where a user has turned off a build option and might
+ // want to turn it back on later, so do not delete the file.
+ // Instead, we keep the rule hash as long as the file exists so
+ // that if the feature is turned back on and the rule has
+ // changed the file is still rebuilt.
+ std::string fpath =
+ cmSystemTools::CollapseFullPath(fname.c_str(), home.c_str());
+ if(cmSystemTools::FileExists(fpath.c_str()))
+ {
+ RuleHash hash;
+ strncpy(hash.Data, line.c_str(), 32);
+ this->RuleHashes[fname] = hash;
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
+{
+ // Now generate a new persistence file with the current hashes.
+ if(this->RuleHashes.empty())
+ {
+ cmSystemTools::RemoveFile(pfile.c_str());
+ }
+ else
+ {
+ cmGeneratedFileStream fout(pfile.c_str());
+ fout << "# Hashes of file build rules.\n";
+ for(std::map<cmStdString, RuleHash>::const_iterator
+ rhi = this->RuleHashes.begin(); rhi != this->RuleHashes.end(); ++rhi)
+ {
+ fout.write(rhi->second.Data, 32);
+ fout << " " << rhi->first << "\n";
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::WriteSummary()
+{
+ cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
+
+ // Record all target directories in a central location.
+ std::string fname = mf->GetHomeOutputDirectory();
+ fname += cmake::GetCMakeFilesDirectory();
+ fname += "/TargetDirectories.txt";
+ cmGeneratedFileStream fout(fname.c_str());
+
+ // Generate summary information files for each target.
+ std::string dir;
+ for(std::map<cmStdString,cmTarget *>::const_iterator ti =
+ this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti)
+ {
+ this->WriteSummary(ti->second);
+ fout << ti->second->GetSupportDirectory() << "\n";
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::WriteSummary(cmTarget* target)
+{
+ // Place the labels file in a per-target support directory.
+ std::string dir = target->GetSupportDirectory();
+ std::string file = dir;
+ file += "/Labels.txt";
+
+ // Check whether labels are enabled for this target.
+ if(const char* value = target->GetProperty("LABELS"))
+ {
+ cmSystemTools::MakeDirectory(dir.c_str());
+ cmGeneratedFileStream fout(file.c_str());
+
+ // List the target-wide labels. All sources in the target get
+ // these labels.
+ std::vector<std::string> labels;
+ cmSystemTools::ExpandListArgument(value, labels);
+ if(!labels.empty())
+ {
+ fout << "# Target labels\n";
+ for(std::vector<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li)
+ {
+ fout << " " << *li << "\n";
+ }
+ }
+
+ // List the source files with any per-source labels.
+ fout << "# Source files and their labels\n";
+ std::vector<cmSourceFile*> const& sources = target->GetSourceFiles();
+ for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+ si != sources.end(); ++si)
+ {
+ cmSourceFile* sf = *si;
+ fout << sf->GetFullPath() << "\n";
+ if(const char* svalue = sf->GetProperty("LABELS"))
+ {
+ labels.clear();
+ cmSystemTools::ExpandListArgument(svalue, labels);
+ for(std::vector<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li)
+ {
+ fout << " " << *li << "\n";
+ }
+ }
+ }
+ }
+ else
+ {
+ cmSystemTools::RemoveFile(file.c_str());
+ }
+}
+
+//----------------------------------------------------------------------------
+// static
+std::string cmGlobalGenerator::EscapeJSON(const std::string& s) {
+ std::string result;
+ for (std::string::size_type i = 0; i < s.size(); ++i) {
+ if (s[i] == '"' || s[i] == '\\') {
+ result += '\\';
+ }
+ result += s[i];
+ }
+ return result;
+}