diff options
Diffstat (limited to 'Source/cmGlobalGenerator.cxx')
-rw-r--r-- | Source/cmGlobalGenerator.cxx | 3081 |
1 files changed, 3081 insertions, 0 deletions
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx new file mode 100644 index 0000000..88ac0bc --- /dev/null +++ b/Source/cmGlobalGenerator.cxx @@ -0,0 +1,3081 @@ +/*============================================================================ + 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 +#if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx +#endif +#endif + +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" +#include "cmExternalMakefileProjectGenerator.h" +#include "cmake.h" +#include "cmState.h" +#include "cmMakefile.h" +#include "cmQtAutoGenerators.h" +#include "cmSourceFile.h" +#include "cmVersion.h" +#include "cmTargetExport.h" +#include "cmComputeTargetDepends.h" +#include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" +#include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionEvaluationFile.h" +#include "cmExportBuildFileGenerator.h" +#include "cmCPackPropertiesGenerator.h" +#include "cmAlgorithms.h" + +#include <cmsys/Directory.hxx> +#include <cmsys/FStream.hxx> + +#if defined(CMAKE_BUILD_WITH_CMAKE) +# include <cmsys/MD5.h> +# include "cm_jsoncpp_value.h" +# include "cm_jsoncpp_writer.h" +#endif + +#include <stdlib.h> // required for atof + +#include <assert.h> + +cmGlobalGenerator::cmGlobalGenerator(cmake* cm) + : CMakeInstance(cm) +{ + // 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->CurrentMakefile = 0; + this->TryCompileOuterMakefile = 0; +} + +cmGlobalGenerator::~cmGlobalGenerator() +{ + this->ClearGeneratorMembers(); + delete this->ExtraGenerator; +} + +bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p, + cmMakefile* mf) +{ + if(p.empty()) + { + return true; + } + + std::ostringstream e; + e << + "Generator\n" + " " << this->GetName() << "\n" + "does not support platform specification, but platform\n" + " " << p << "\n" + "was specified."; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; +} + +bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, + cmMakefile* mf) +{ + if(ts.empty()) + { + return true; + } + std::ostringstream e; + e << + "Generator\n" + " " << this->GetName() << "\n" + "does not support toolset specification, but toolset\n" + " " << ts << "\n" + "was specified."; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; +} + +std::string cmGlobalGenerator::SelectMakeProgram( + const std::string& inMakeProgram, + const std::string& makeDefault) const +{ + std::string makeProgram = inMakeProgram; + if(cmSystemTools::IsOff(makeProgram.c_str())) + { + const char* makeProgramCSTR = + this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM"); + if(cmSystemTools::IsOff(makeProgramCSTR)) + { + makeProgram = makeDefault; + } + else + { + makeProgram = makeProgramCSTR; + } + if(cmSystemTools::IsOff(makeProgram.c_str()) && + !makeProgram.empty()) + { + makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND"; + } + } + return makeProgram; +} + +void cmGlobalGenerator::ResolveLanguageCompiler(const std::string &lang, + cmMakefile *mf, + bool optional) const +{ + std::string langComp = "CMAKE_"; + langComp += lang; + langComp += "_COMPILER"; + + if(!mf->GetDefinition(langComp)) + { + if(!optional) + { + cmSystemTools::Error(langComp.c_str(), + " not set, after EnableLanguage"); + } + return; + } + const char* name = mf->GetRequiredDefinition(langComp); + std::string path; + if(!cmSystemTools::FileIsFullPath(name)) + { + path = cmSystemTools::FindProgram(name); + } + else + { + path = name; + } + if((path.empty() || !cmSystemTools::FileExists(path.c_str())) + && (optional==false)) + { + return; + } + const char* cname = this->GetCMakeInstance()-> + GetState()->GetInitializedCacheValue(langComp); + std::string changeVars; + if(cname && !optional) + { + std::string cnameString; + if(!cmSystemTools::FileIsFullPath(cname)) + { + cnameString = cmSystemTools::FindProgram(cname); + } + else + { + 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()->GetState()->GetGlobalProperty( + "__CMAKE_DELETE_CACHE_CHANGE_VARS_"); + if(cvars) + { + changeVars += cvars; + changeVars += ";"; + } + changeVars += langComp; + changeVars += ";"; + changeVars += cname; + this->GetCMakeInstance()->GetState()->SetGlobalProperty( + "__CMAKE_DELETE_CACHE_CHANGE_VARS_", + changeVars.c_str()); + } + } +} + +void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen) +{ + this->BuildExportSets[gen->GetMainExportFileName()] = gen; +} + +void +cmGlobalGenerator::AddBuildExportExportSet(cmExportBuildFileGenerator* gen) +{ + this->BuildExportSets[gen->GetMainExportFileName()] = gen; + this->BuildExportExportSets[gen->GetMainExportFileName()] = gen; +} + +bool cmGlobalGenerator::GenerateImportFile(const std::string &file) +{ + std::map<std::string, cmExportBuildFileGenerator*>::iterator it + = this->BuildExportSets.find(file); + if (it != this->BuildExportSets.end()) + { + bool result = it->second->GenerateImportFile(); + delete it->second; + it->second = 0; + this->BuildExportSets.erase(it); + return result; + } + return false; +} + +void cmGlobalGenerator::ForceLinkerLanguages() +{ + +} + +bool +cmGlobalGenerator::IsExportedTargetsFile(const std::string &filename) const +{ + const std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it + = this->BuildExportSets.find(filename); + if (it == this->BuildExportSets.end()) + { + return false; + } + return this->BuildExportExportSets.find(filename) + == this->BuildExportExportSets.end(); +} + +// Find the make program for the generator, required for try compiles +void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf) +{ + if(this->FindMakeProgramFile.empty()) + { + 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.empty()) + { + mf->ReadListFile(setMakeProgram.c_str()); + } + } + if(!mf->GetDefinition("CMAKE_MAKE_PROGRAM") + || cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) + { + std::ostringstream 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, + dir, file); + std::string saveFile = file; + cmSystemTools::GetShortPath(makeProgram, makeProgram); + cmSystemTools::SplitProgramPath(makeProgram, + dir, file); + makeProgram = dir; + makeProgram += "/"; + makeProgram += saveFile; + mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram.c_str(), + "make program", + cmState::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 + +// CMakeSystemSpecificInitialize.cmake +// - includes Platform/${CMAKE_SYSTEM_NAME}-Initialize.cmake + +// 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 optional) +{ + if(languages.empty()) + { + 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()) + { + std::ostringstream e; + e << "The test project needs language " + << lang << " which is not enabled."; + this->TryCompileOuterMakefile + ->IssueMessage(cmake::FATAL_ERROR, e.str()); + cmSystemTools::SetFatalErrorOccured(); + return; + } + } + } + } + + bool fatalError = false; + + 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.empty()) + { + rootBin = this->ConfiguredFilesPath; + } + rootBin += "/"; + rootBin += cmVersion::GetCMakeVersion(); + + // set the dir for parent files so they can be used by modules + mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR",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; + bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED"); + if(readCMakeSystem) + { + fpath += "/CMakeSystem.cmake"; + if(cmSystemTools::FileExists(fpath.c_str())) + { + mf->ReadListFile(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); +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning (push) +# pragma warning (disable:4996) +#endif + GetVersionEx (&osvi); +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning (pop) +#endif + std::ostringstream 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(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(fpath.c_str()); + } + + if(readCMakeSystem) + { + // Tell the generator about the target system. + std::string system = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME"); + if(!this->SetSystemName(system, mf)) + { + cmSystemTools::SetFatalErrorOccured(); + return; + } + + // Tell the generator about the platform, if any. + std::string platform = mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"); + if(!this->SetGeneratorPlatform(platform, mf)) + { + cmSystemTools::SetFatalErrorOccured(); + return; + } + + // Tell the generator about the toolset, if any. + std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"); + if(!this->SetGeneratorToolset(toolset, mf)) + { + cmSystemTools::SetFatalErrorOccured(); + return; + } + } + + // **** Load the system specific initialization if not yet loaded + if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED")) + { + fpath = mf->GetModulesFile("CMakeSystemSpecificInitialize.cmake"); + if(!mf->ReadListFile(fpath.c_str())) + { + cmSystemTools::Error("Could not find cmake module file: " + "CMakeSystemSpecificInitialize.cmake"); + } + } + + std::map<std::string, bool> needTestLanguage; + std::map<std::string, 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(!mf->GetDefinition(loadedLang)) + { + fpath = rootBin; + fpath += "/CMake"; + fpath += lang; + fpath += "Compiler.cmake"; + + // 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. + if(cmSystemTools::FileExists(fpath.c_str())) + { + if(!mf->ReadListFile(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 happened. " + "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(determineFile.c_str())) + { + cmSystemTools::Error("Could not find cmake module file: ", + determineCompiler.c_str()); + } + if (cmSystemTools::GetFatalErrorOccured()) + { + return; + } + 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); + std::string envVarValue = + mf->GetRequiredDefinition(compilerName); + std::string env = envVar; + env += "="; + env += envVarValue; + cmSystemTools::PutEnv(env); + } + + // 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(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(fpath.c_str())) + { + cmSystemTools::Error("Could not find cmake module file: " + "CMakeSystemSpecificInformation.cmake"); + } + } + // 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; + } + + // Check that the compiler was found. + std::string compilerName = "CMAKE_"; + compilerName += lang; + compilerName += "_COMPILER"; + std::string compilerEnv = "CMAKE_"; + compilerEnv += lang; + compilerEnv += "_COMPILER_ENV_VAR"; + std::ostringstream noCompiler; + const char* compilerFile = mf->GetDefinition(compilerName); + if(!compilerFile || !*compilerFile || + cmSystemTools::IsNOTFOUND(compilerFile)) + { + noCompiler << + "No " << compilerName << " could be found.\n" + ; + } + else if(strcmp(lang, "RC") != 0 && + strcmp(lang, "ASM_MASM") != 0) + { + if(!cmSystemTools::FileIsFullPath(compilerFile)) + { + noCompiler << + "The " << compilerName << ":\n" + " " << compilerFile << "\n" + "is not a full path and was not found in the PATH.\n" + ; + } + else if(!cmSystemTools::FileExists(compilerFile)) + { + noCompiler << + "The " << compilerName << ":\n" + " " << compilerFile << "\n" + "is not a full path to an existing compiler tool.\n" + ; + } + } + if(!noCompiler.str().empty()) + { + // Skip testing this language since the compiler is not found. + needTestLanguage[lang] = false; + if(!optional) + { + // The compiler was not found and it is not optional. Remove + // CMake(LANG)Compiler.cmake so we try again next time CMake runs. + std::string compilerLangFile = rootBin; + compilerLangFile += "/CMake"; + compilerLangFile += lang; + compilerLangFile += "Compiler.cmake"; + cmSystemTools::RemoveFile(compilerLangFile); + if(!this->CMakeInstance->GetIsInTryCompile()) + { + this->PrintCompilerAdvice(noCompiler, lang, + mf->GetDefinition(compilerEnv)); + mf->IssueMessage(cmake::FATAL_ERROR, noCompiler.str()); + fatalError = true; + } + } + } + + std::string langLoadedVar = "CMAKE_"; + langLoadedVar += lang; + langLoadedVar += "_INFORMATION_LOADED"; + if (!mf->GetDefinition(langLoadedVar)) + { + 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(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); + + // 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(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(ifpath.c_str())) + { + cmSystemTools::Error("Could not find cmake module file: ", + testLang.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)) + { + std::string compilerLangFile = rootBin; + compilerLangFile += "/CMake"; + compilerLangFile += lang; + compilerLangFile += "Compiler.cmake"; + cmSystemTools::RemoveFile(compilerLangFile); + } + } // 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); + if (sharedLibFlags) + { + this->LanguageToOriginalSharedLibFlags[lang] = sharedLibFlags; + } + + // Translate compiler ids for compatibility. + this->CheckCompilerIdCompatibility(mf, lang); + } // 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(projectCompatibility.c_str()); + } + // Inform any extra generator of the new language. + if (this->ExtraGenerator) + { + this->ExtraGenerator->EnableLanguage(languages, mf, false); + } + + if(fatalError) + { + cmSystemTools::SetFatalErrorOccured(); + } +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os, + std::string const& lang, + const char* envVar) const +{ + // Subclasses override this method if they do not support this advice. + os << + "Tell CMake where to find the compiler by setting " + ; + if(envVar) + { + os << + "either the environment variable \"" << envVar << "\" or " + ; + } + os << + "the CMake cache entry CMAKE_" << lang << "_COMPILER " + "to the full path to the compiler, or to the compiler name " + "if it is in the PATH." + ; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::CheckCompilerIdCompatibility(cmMakefile* mf, + std::string const& lang) const +{ + std::string compilerIdVar = "CMAKE_" + lang + "_COMPILER_ID"; + const char* compilerId = mf->GetDefinition(compilerIdVar); + if(!compilerId) + { + return; + } + + if(strcmp(compilerId, "AppleClang") == 0) + { + switch(mf->GetPolicyStatus(cmPolicies::CMP0025)) + { + case cmPolicies::WARN: + if(!this->CMakeInstance->GetIsInTryCompile() && + mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0025")) + { + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n" + "Converting " << lang << + " compiler id \"AppleClang\" to \"Clang\" for compatibility." + ; + mf->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } + case cmPolicies::OLD: + // OLD behavior is to convert AppleClang to Clang. + mf->AddDefinition(compilerIdVar, "Clang"); + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + mf->IssueMessage( + cmake::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0025) + ); + case cmPolicies::NEW: + // NEW behavior is to keep AppleClang. + break; + } + } + + if(strcmp(compilerId, "QCC") == 0) + { + switch(mf->GetPolicyStatus(cmPolicies::CMP0047)) + { + case cmPolicies::WARN: + if(!this->CMakeInstance->GetIsInTryCompile() && + mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0047")) + { + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n" + "Converting " << lang << + " compiler id \"QCC\" to \"GNU\" for compatibility." + ; + mf->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } + case cmPolicies::OLD: + // OLD behavior is to convert QCC to GNU. + mf->AddDefinition(compilerIdVar, "GNU"); + if(lang == "C") + { + mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1"); + } + else if(lang == "CXX") + { + mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1"); + } + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + mf->IssueMessage( + cmake::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0047) + ); + case cmPolicies::NEW: + // NEW behavior is to keep QCC. + break; + } + } +} + +//---------------------------------------------------------------------------- +std::string +cmGlobalGenerator::GetLanguageOutputExtension(cmSourceFile const& source) const +{ + const std::string& lang = source.GetLanguage(); + if(!lang.empty()) + { + std::map<std::string, std::string>::const_iterator it = + this->LanguageToOutputExtension.find(lang); + + if(it != this->LanguageToOutputExtension.end()) + { + return it->second; + } + } + 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; + } + } + } + return ""; +} + + +std::string cmGlobalGenerator::GetLanguageFromExtension(const char* ext) const +{ + // 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; + } + std::map<std::string, std::string>::const_iterator it + = this->ExtensionToLanguage.find(ext); + if(it != this->ExtensionToLanguage.end()) + { + return it->second; + } + return ""; +} + +/* 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 std::string& l, + cmMakefile* mf) +{ + this->SetLanguageEnabledFlag(l, mf); + this->SetLanguageEnabledMaps(l, mf); +} + +void cmGlobalGenerator::SetLanguageEnabledFlag(const std::string& l, + cmMakefile* mf) +{ + this->CMakeInstance->GetState()->SetLanguageEnabled(l); + + // 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 std::string& 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); + int preference = 0; + if(linkerPref) + { + if (sscanf(linkerPref, "%d", &preference)!=1) + { + // backward compatibility: before 2.6 LINKER_PREFERENCE + // was either "None" or "Preferred", and only the first character was + // tested. So if there is a custom language out there and it is + // "Preferred", 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); + 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); + 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 std::string& l, + cmMakefile* mf) +{ + std::string extensionsVar = std::string("CMAKE_") + + std::string(l) + std::string("_SOURCE_FILE_EXTENSIONS"); + std::string exts = mf->GetSafeDefinition(extensionsVar); + 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* ext) const +{ + if(!this->GetLanguageFromExtension(ext).empty()) + { + return false; + } + return (this->IgnoreExtensions.count(ext) > 0); +} + +bool cmGlobalGenerator::GetLanguageEnabled(const std::string& l) const +{ + return this->CMakeInstance->GetState()->GetLanguageEnabled(l); +} + +void cmGlobalGenerator::ClearEnabledLanguages() +{ + return this->CMakeInstance->GetState()->ClearEnabledLanguages(); +} + +void cmGlobalGenerator::Configure() +{ + this->FirstTimeProgress = 0.0f; + this->ClearGeneratorMembers(); + + // start with this directory + cmLocalGenerator *lg = this->MakeLocalGenerator(); + this->LocalGenerators.push_back(lg); + + // set the Start directories + lg->GetMakefile()->SetCurrentSourceDirectory + (this->CMakeInstance->GetHomeDirectory()); + lg->GetMakefile()->SetCurrentBinaryDirectory + (this->CMakeInstance->GetHomeOutputDirectory()); + + this->BinaryDirectories.insert( + this->CMakeInstance->GetHomeOutputDirectory()); + + // now do it + lg->GetMakefile()->Configure(); + lg->GetMakefile()->EnforceDirectoryLevelRules(); + + // 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", cmState::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) + { + std::ostringstream msg; + if(cmSystemTools::GetErrorOccuredFlag()) + { + msg << "Configuring incomplete, errors occurred!"; + const char* logs[] = {"CMakeOutput.log", "CMakeError.log", 0}; + for(const char** log = logs; *log; ++log) + { + std::string f = this->CMakeInstance->GetHomeOutputDirectory(); + f += this->CMakeInstance->GetCMakeFilesDirectory(); + f += "/"; + f += *log; + if(cmSystemTools::FileExists(f.c_str())) + { + msg << "\nSee also \"" << f << "\"."; + } + } + } + else + { + msg << "Configuring done"; + } + this->CMakeInstance->UpdateProgress(msg.str().c_str(), -1); + } +} + +cmExportBuildFileGenerator* +cmGlobalGenerator::GetExportedTargetsFile(const std::string &filename) const +{ + std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it + = this->BuildExportSets.find(filename); + return it == this->BuildExportSets.end() ? 0 : it->second; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddCMP0042WarnTarget(const std::string& target) +{ + this->CMP0042WarnTargets.insert(target); +} + +bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const +{ + // If the property is not enabled then okay. + if(!this->CMakeInstance->GetState() + ->GetGlobalPropertyAsBool("ALLOW_DUPLICATE_CUSTOM_TARGETS")) + { + return true; + } + + // This generator does not support duplicate custom targets. + std::ostringstream 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 duplicate target names."; + cmSystemTools::Error(e.str().c_str()); + return false; +} + +void cmGlobalGenerator::DoGenerate() +{ + // Some generators track files replaced during the Generate. + // Start with an empty vector: + this->FilesReplacedDuringGenerate.clear(); + + // clear targets to issue warning CMP0042 for + this->CMP0042WarnTargets.clear(); + + this->Generate(); +} + +void cmGlobalGenerator::Generate() +{ + // Check whether this generator is allowed to run. + if(!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) + { + return; + } + + this->FinalizeTargetCompileInfo(); + +#ifdef CMAKE_BUILD_WITH_CMAKE + // Iterate through all targets and set up automoc for those which have + // the AUTOMOC, AUTOUIC or AUTORCC property set + AutogensType autogens; + this->CreateQtAutoGeneratorsTargets(autogens); +#endif + + // 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) + { + this->LocalGenerators[i]->ComputeObjectMaxPath(); + 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(); + } + + // Create per-target generator information. + this->CreateGeneratorTargets(); + +#ifdef CMAKE_BUILD_WITH_CMAKE + for (AutogensType::iterator it = autogens.begin(); it != autogens.end(); + ++it) + { + it->first.SetupAutoGenerateTarget(it->second); + } +#endif + + // 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(); + } + + this->ForceLinkerLanguages(); + + // Compute the manifest of main targets generated. + for (i = 0; i < this->LocalGenerators.size(); ++i) + { + this->LocalGenerators[i]->GenerateTargetManifest(); + } + + this->ProcessEvaluationFiles(); + + // 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(); + + for (i = 0; i < this->LocalGenerators.size(); ++i) + { + this->LocalGenerators[i]->ComputeHomeRelativeOutputPath(); + } + + // Generate project files + for (i = 0; i < this->LocalGenerators.size(); ++i) + { + this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile()); + this->LocalGenerators[i]->Generate(); + if(!this->LocalGenerators[i]->GetMakefile()->IsOn( + "CMAKE_SKIP_INSTALL_RULES")) + { + 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->SetCurrentMakefile(0); + + if(!this->GenerateCPackPropertiesFile()) + { + this->GetCMakeInstance()->IssueMessage( + cmake::FATAL_ERROR, "Could not write CPack properties file."); + } + + for (std::map<std::string, cmExportBuildFileGenerator*>::iterator + it = this->BuildExportSets.begin(); it != this->BuildExportSets.end(); + ++it) + { + if (!it->second->GenerateImportFile() + && !cmSystemTools::GetErrorOccuredFlag()) + { + this->GetCMakeInstance() + ->IssueMessage(cmake::FATAL_ERROR, "Could not write export file."); + return; + } + } + // Update rule hashes. + this->CheckRuleHashes(); + + this->WriteSummary(); + + if (this->ExtraGenerator != 0) + { + this->ExtraGenerator->Generate(); + } + + if(!this->CMP0042WarnTargets.empty()) + { + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n"; + w << "MACOSX_RPATH is not specified for" + " the following targets:\n"; + for(std::set<std::string>::iterator + iter = this->CMP0042WarnTargets.begin(); + iter != this->CMP0042WarnTargets.end(); + ++iter) + { + w << " " << *iter << "\n"; + } + this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } + + this->CMakeInstance->UpdateProgress("Generating done", -1); +} + +//---------------------------------------------------------------------------- +bool cmGlobalGenerator::ComputeTargetDepends() +{ + cmComputeTargetDepends ctd(this); + if(!ctd.Compute()) + { + return false; + } + std::vector<cmGeneratorTarget const*> const& targets = ctd.GetTargets(); + for(std::vector<cmGeneratorTarget const*>::const_iterator ti + = targets.begin(); ti != targets.end(); ++ti) + { + ctd.GetTargetDirectDepends(*ti, this->TargetDependencies[*ti]); + } + return true; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::CreateQtAutoGeneratorsTargets(AutogensType &autogens) +{ +#ifdef CMAKE_BUILD_WITH_CMAKE + for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) + { + cmTargets& targets = + this->LocalGenerators[i]->GetMakefile()->GetTargets(); + std::vector<std::string> targetNames; + targetNames.reserve(targets.size()); + for(cmTargets::iterator ti = targets.begin(); + ti != targets.end(); ++ti) + { + targetNames.push_back(ti->second.GetName()); + } + for(std::vector<std::string>::iterator ti = targetNames.begin(); + ti != targetNames.end(); ++ti) + { + cmTarget& target = *this->LocalGenerators[i] + ->GetMakefile()->FindTarget(*ti, true); + if(target.GetType() == cmTarget::EXECUTABLE || + target.GetType() == cmTarget::STATIC_LIBRARY || + target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY || + target.GetType() == cmTarget::OBJECT_LIBRARY) + { + if((target.GetPropertyAsBool("AUTOMOC") + || target.GetPropertyAsBool("AUTOUIC") + || target.GetPropertyAsBool("AUTORCC")) + && !target.IsImported()) + { + cmQtAutoGenerators autogen; + if(autogen.InitializeAutogenTarget(&target)) + { + autogens.push_back(std::make_pair(autogen, &target)); + } + } + } + } + } +#else + (void)autogens; +#endif +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::FinalizeTargetCompileInfo() +{ + // Construct per-target generator information. + for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) + { + cmMakefile *mf = this->LocalGenerators[i]->GetMakefile(); + + const std::vector<cmValueWithOrigin> noconfig_compile_definitions = + mf->GetCompileDefinitionsEntries(); + + cmTargets& targets = mf->GetTargets(); + for(cmTargets::iterator ti = targets.begin(); + ti != targets.end(); ++ti) + { + cmTarget* t = &ti->second; + + t->AppendBuildInterfaceIncludes(); + + if (t->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } + + for (std::vector<cmValueWithOrigin>::const_iterator it + = noconfig_compile_definitions.begin(); + it != noconfig_compile_definitions.end(); ++it) + { + t->InsertCompileDefinition(*it); + } + + cmPolicies::PolicyStatus polSt + = mf->GetPolicyStatus(cmPolicies::CMP0043); + if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) + { + std::vector<std::string> configs; + mf->GetConfigurations(configs); + + for(std::vector<std::string>::const_iterator ci = configs.begin(); + ci != configs.end(); ++ci) + { + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(*ci); + t->AppendProperty(defPropName, + mf->GetProperty(defPropName)); + } + } + } + } +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::CreateGeneratorTargets(cmLocalGenerator *lg) +{ + cmGeneratorTargetsType generatorTargets; + cmMakefile* mf = lg->GetMakefile(); + cmTargets& targets = mf->GetTargets(); + for(cmTargets::iterator ti = targets.begin(); + ti != targets.end(); ++ti) + { + cmTarget* t = &ti->second; + cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg); + this->ComputeTargetObjectDirectory(gt); + this->GeneratorTargets[t] = gt; + generatorTargets[t] = gt; + } + + for(std::vector<cmTarget*>::const_iterator + j = mf->GetOwnedImportedTargets().begin(); + j != mf->GetOwnedImportedTargets().end(); ++j) + { + cmGeneratorTarget* gt = new cmGeneratorTarget(*j, lg); + this->GeneratorTargets[*j] = gt; + generatorTargets[*j] = gt; + } + mf->SetGeneratorTargets(generatorTargets); +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::CreateGeneratorTargets() +{ + // Construct per-target generator information. + for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) + { + this->CreateGeneratorTargets(this->LocalGenerators[i]); + } +} + + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::ClearGeneratorMembers() +{ + cmDeleteAll(this->GeneratorTargets); + this->GeneratorTargets.clear(); + + cmDeleteAll(this->EvaluationFiles); + this->EvaluationFiles.clear(); + + cmDeleteAll(this->BuildExportSets); + this->BuildExportSets.clear(); + + cmDeleteAll(this->LocalGenerators); + this->LocalGenerators.clear(); + + this->ExportSets.clear(); + this->TargetDependencies.clear(); + this->TotalTargets.clear(); + this->ImportedTargets.clear(); + this->LocalGeneratorToTargetMap.clear(); + this->ProjectMap.clear(); + this->RuleHashes.clear(); + this->DirectoryContentMap.clear(); + this->BinaryDirectories.clear(); +} + +//---------------------------------------------------------------------------- +cmGeneratorTarget* +cmGlobalGenerator::GetGeneratorTarget(cmTarget const* t) const +{ + cmGeneratorTargetsType::const_iterator ti = this->GeneratorTargets.find(t); + if(ti == this->GeneratorTargets.end()) + { + this->CMakeInstance->IssueMessage( + cmake::INTERNAL_ERROR, "Missing cmGeneratorTarget instance!"); + return 0; + } + return ti->second; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::ComputeTargetObjectDirectory(cmGeneratorTarget*) const +{ +} + +void cmGlobalGenerator::CheckLocalGenerators() +{ + std::map<std::string, std::string> notFoundMap; +// std::set<std::string> notFoundMap; + // after it is all done do a ConfigureFinalPass + cmState* state = this->GetCMakeInstance()->GetState(); + for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) + { + this->LocalGenerators[i]->GetMakefile()->ConfigureFinalPass(); + cmTargets &targets = + this->LocalGenerators[i]->GetMakefile()->GetTargets(); + for (cmTargets::iterator l = targets.begin(); + l != targets.end(); l++) + { + if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } + 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); + if(state->GetCacheEntryPropertyAsBool(varName, "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() + ->GetCurrentSourceDirectory(); + notFoundMap[varName] = text; + } + } + std::vector<std::string> incs; + const char *incDirProp = l->second.GetProperty("INCLUDE_DIRECTORIES"); + if (!incDirProp) + { + continue; + } + + std::string incDirs = cmGeneratorExpression::Preprocess(incDirProp, + cmGeneratorExpression::StripAllGeneratorExpressions); + + cmSystemTools::ExpandListArgument(incDirs, incs); + + 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); + if(state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) + { + varName += " (ADVANCED)"; + } + std::string text = notFoundMap[varName]; + text += "\n used as include directory in directory "; + text += this->LocalGenerators[i] + ->GetMakefile()->GetCurrentSourceDirectory(); + 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.empty()) + { + std::string notFoundVars; + for(std::map<std::string, std::string>::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 std::string& srcdir, + const std::string& bindir, + const std::string& projectName, + const std::string& 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->GetState()->GetInitializedCacheValue + ("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 newTarget; + if (!target.empty()) + { + 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 + } + std::string config = + mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"); + return this->Build(srcdir,bindir,projectName, + newTarget, + output,"",config,false,fast,false, + this->TryCompileTimeout); +} + +void cmGlobalGenerator::GenerateBuildCommand( + std::vector<std::string>& makeCommand, const std::string&, + const std::string&, const std::string&, const std::string&, + const std::string&, bool, bool, + std::vector<std::string> const&) +{ + makeCommand.push_back( + "cmGlobalGenerator::GenerateBuildCommand not implemented"); +} + +int cmGlobalGenerator::Build( + const std::string&, const std::string& bindir, + const std::string& projectName, const std::string& target, + std::string& output, + const std::string& makeCommandCSTR, + const std::string& config, + bool clean, bool fast, bool verbose, + double timeout, + cmSystemTools::OutputOption outputflag, + std::vector<std::string> const& nativeOptions) +{ + /** + * Run an executable command and put the stdout in output. + */ + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + cmSystemTools::ChangeDirectory(bindir); + output += "Change Dir: "; + output += bindir; + output += "\n"; + + int retVal; + bool hideconsole = cmSystemTools::GetRunCommandHideConsole(); + cmSystemTools::SetRunCommandHideConsole(true); + std::string outputBuffer; + std::string* outputPtr = &outputBuffer; + + std::vector<std::string> makeCommand; + this->GenerateBuildCommand(makeCommand, makeCommandCSTR, projectName, + bindir, target, config, fast, verbose, + nativeOptions); + + // Workaround to convince VCExpress.exe to produce output. + if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH && + !makeCommand.empty() && cmSystemTools::LowerCase( + cmSystemTools::GetFilenameName(makeCommand[0])) == "vcexpress.exe") + { + outputflag = cmSystemTools::OUTPUT_NORMAL; + } + + // should we do a clean first? + if (clean) + { + std::vector<std::string> cleanCommand; + this->GenerateBuildCommand(cleanCommand, makeCommandCSTR, projectName, + bindir, "clean", config, fast, verbose); + output += "\nRun Clean Command:"; + output += cmSystemTools::PrintSingleCommand(cleanCommand); + output += "\n"; + + if (!cmSystemTools::RunSingleCommand(cleanCommand, outputPtr, outputPtr, + &retVal, 0, outputflag, timeout)) + { + cmSystemTools::SetRunCommandHideConsole(hideconsole); + cmSystemTools::Error("Generator: execution of make clean failed."); + output += *outputPtr; + output += "\nGenerator: execution of make clean failed.\n"; + + // return to the original directory + cmSystemTools::ChangeDirectory(cwd); + return 1; + } + output += *outputPtr; + } + + // now build + std::string makeCommandStr = cmSystemTools::PrintSingleCommand(makeCommand); + output += "\nRun Build Command:"; + output += makeCommandStr; + output += "\n"; + + if (!cmSystemTools::RunSingleCommand(makeCommand, outputPtr, outputPtr, + &retVal, 0, outputflag, timeout)) + { + cmSystemTools::SetRunCommandHideConsole(hideconsole); + cmSystemTools::Error + ("Generator: execution of make failed. Make command was: ", + makeCommandStr.c_str()); + output += *outputPtr; + output += "\nGenerator: execution of make failed. Make command was: " + + makeCommandStr + "\n"; + + // return to the original directory + cmSystemTools::ChangeDirectory(cwd); + return 1; + } + 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); + return retVal; +} + +//---------------------------------------------------------------------------- +std::string cmGlobalGenerator::GenerateCMakeBuildCommand( + const std::string& target, const std::string& config, + const std::string& native, + bool ignoreErrors) +{ + std::string makeCommand = cmSystemTools::GetCMakeCommand(); + makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str()); + makeCommand += " --build ."; + if(!config.empty()) + { + makeCommand += " --config \""; + makeCommand += config; + makeCommand += "\""; + } + if(!target.empty()) + { + makeCommand += " --target \""; + makeCommand += target; + makeCommand += "\""; + } + const char* sep = " -- "; + if(ignoreErrors) + { + const char* iflag = this->GetBuildIgnoreErrorsFlag(); + if(iflag && *iflag) + { + makeCommand += sep; + makeCommand += iflag; + sep = " "; + } + } + if(!native.empty()) + { + makeCommand += sep; + makeCommand += native; + } + return makeCommand; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg) +{ + this->LocalGenerators.push_back(lg); + + // update progress + // estimate how many lg there will be + const char *numGenC = + this->CMakeInstance->GetState()->GetInitializedCacheValue + ("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::EnableInstallTarget() +{ + this->InstallTargetEnabled = true; +} + +cmLocalGenerator * +cmGlobalGenerator::MakeLocalGenerator(cmState::Snapshot snapshot, + cmLocalGenerator *parent) +{ + if (!snapshot.IsValid()) + { + snapshot = this->CMakeInstance->GetCurrentSnapshot(); + } + + return this->CreateLocalGenerator(parent, snapshot); +} + +cmLocalGenerator* +cmGlobalGenerator::CreateLocalGenerator(cmLocalGenerator* parent, + cmState::Snapshot snapshot) +{ + return new cmLocalGenerator(this, parent, snapshot); +} + +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", + cmState::FILEPATH); + // copy the enabled languages + this->GetCMakeInstance()->GetState()->SetEnabledLanguages( + gen->GetCMakeInstance()->GetState()->GetEnabledLanguages() + ); + 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(); + } +} + +bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, + cmLocalGenerator* gen) const +{ + 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 const& target) const +{ + if(target.GetType() == cmTarget::INTERFACE_LIBRARY + || 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) const +{ + lang = this->CMakeInstance->GetState()->GetEnabledLanguages(); +} + +int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const +{ + std::map<std::string, 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 const& targets = mf->GetTargets(); + for(cmTargets::const_iterator t = targets.begin(); t != targets.end(); ++t) + { + cmTarget const& 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<cmGeneratorTarget const*>& targetSet = + this->LocalGeneratorToTargetMap[clg]; + cmGeneratorTarget* gt = this->GetGeneratorTarget(&target); + targetSet.insert(gt); + + // 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(gt); + 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 std::string& start_dir) const +{ + for(std::vector<cmLocalGenerator*>::const_iterator it = + this->LocalGenerators.begin(); it != this->LocalGenerators.end(); ++it) + { + std::string sd = (*it)->GetMakefile()->GetCurrentSourceDirectory(); + if (sd == start_dir) + { + return *it; + } + } + return 0; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddAlias(const std::string& name, cmTarget *tgt) +{ + this->AliasTargets[name] = tgt; +} + +//---------------------------------------------------------------------------- +bool cmGlobalGenerator::IsAlias(const std::string& name) const +{ + return this->AliasTargets.find(name) != this->AliasTargets.end(); +} + +//---------------------------------------------------------------------------- +cmTarget* +cmGlobalGenerator::FindTarget(const std::string& name, + bool excludeAliases) const +{ + if (!excludeAliases) + { + TargetMap::const_iterator ai = this->AliasTargets.find(name); + if (ai != this->AliasTargets.end()) + { + return ai->second; + } + } + TargetMap::const_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) const +{ + if(cmSystemTools::IsPathToFramework(libname.c_str())) + { + return true; + } + + if(cmTarget* tgt = this->FindTarget(libname)) + { + 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::CreateDefaultGlobalTargets(cmTargets* targets) +{ + cmMakefile* mf = this->LocalGenerators[0]->GetMakefile(); + const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); + + // CPack + std::string workingDir = mf->GetCurrentBinaryDirectory(); + cmCustomCommandLines cpackCommandLines; + std::vector<std::string> depends; + cmCustomCommandLine singleLine; + singleLine.push_back(cmSystemTools::GetCPackCommand()); + if ( cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.' ) + { + singleLine.push_back("-C"); + singleLine.push_back(cmakeCfgIntDir); + } + singleLine.push_back("--config"); + std::string configFile = mf->GetCurrentBinaryDirectory();; + 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(), /*uses_terminal*/true); + } + // 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(cmSystemTools::GetCPackCommand()); + singleLine.push_back("--config"); + configFile = mf->GetCurrentBinaryDirectory();; + 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(), /*uses_terminal*/true); + } + } + + // 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(cmSystemTools::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, + /*uses_terminal*/true); + } + + //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 generator preference for the edit_cache rule if it is defined. + std::string edit_cmd = this->GetEditCacheCommand(); + if (!edit_cmd.empty()) + { + singleLine.push_back(edit_cmd); + 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, /*uses_terminal*/true); + } + else + { + singleLine.push_back(cmSystemTools::GetCMakeCommand()); + singleLine.push_back("-E"); + singleLine.push_back("echo"); + singleLine.push_back("No interactive CMake dialog available."); + cpackCommandLines.push_back(singleLine); + (*targets)[editCacheTargetName] = + this->CreateGlobalTarget( + editCacheTargetName, + "No interactive CMake dialog available...", + &cpackCommandLines, depends, 0, /*uses_terminal*/false); + } + } + + //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(cmSystemTools::GetCMakeCommand()); + 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, /*uses_terminal*/true); + } + + //Install + bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES"); + if(this->InstallTargetEnabled && skipInstallRules) + { + mf->IssueMessage(cmake::WARNING, + "CMAKE_SKIP_INSTALL_RULES was enabled even though " + "installation rules have been specified"); + } + else if(this->InstallTargetEnabled && !skipInstallRules) + { + if(!cmakeCfgIntDir || !*cmakeCfgIntDir || cmakeCfgIntDir[0] == '.') + { + std::set<std::string>* componentsSet = &this->InstallComponents; + cpackCommandLines.erase(cpackCommandLines.begin(), + cpackCommandLines.end()); + depends.erase(depends.begin(), depends.end()); + std::ostringstream ostr; + if (!componentsSet->empty()) + { + ostr << "Available install components are: "; + ostr << cmWrap('"', *componentsSet, '"', " "); + } + else + { + ostr << "Only default component available"; + } + singleLine.push_back(ostr.str()); + (*targets)["list_install_components"] + = this->CreateGlobalTarget("list_install_components", + ostr.str().c_str(), + &cpackCommandLines, depends, 0, /*uses_terminal*/false); + } + std::string cmd = cmSystemTools::GetCMakeCommand(); + 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") && + !mf->IsOn("CMAKE_CROSSCOMPILING")) + { + // 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); + 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, /*uses_terminal*/true); + + // 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, /*uses_terminal*/true); + } + + // 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, /*uses_terminal*/true); + } + } +} + +//---------------------------------------------------------------------------- +const char* cmGlobalGenerator::GetPredefinedTargetsFolder() +{ + const char* prop = this->GetCMakeInstance()->GetState() + ->GetGlobalProperty("PREDEFINED_TARGETS_FOLDER"); + + if (prop) + { + return prop; + } + + return "CMakePredefinedTargets"; +} + +//---------------------------------------------------------------------------- +bool cmGlobalGenerator::UseFolderProperty() +{ + const char* prop = this->GetCMakeInstance()->GetState() + ->GetGlobalProperty("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 until VS11: + // + return false; +} + +//---------------------------------------------------------------------------- +cmTarget cmGlobalGenerator::CreateGlobalTarget( + const std::string& name, const char* message, + const cmCustomCommandLines* commandLines, + std::vector<std::string> depends, + const char* workingDirectory, + bool uses_terminal) +{ + // Package + cmTarget target; + target.SetType(cmTarget::GLOBAL_TARGET, name); + target.SetProperty("EXCLUDE_FROM_ALL","TRUE"); + + std::vector<std::string> no_outputs; + std::vector<std::string> no_byproducts; + std::vector<std::string> no_depends; + // Store the custom command in the target. + cmCustomCommand cc(0, no_outputs, no_byproducts, no_depends, + *commandLines, 0, workingDirectory); + cc.SetUsesTerminal(uses_terminal); + target.AddPostBuildCommand(cc); + target.SetProperty("EchoString", message); + std::vector<std::string>::iterator dit; + for ( dit = depends.begin(); dit != depends.end(); ++ dit ) + { + target.AddUtility(*dit); + } + + // 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) const +{ + std::map<std::string, std::string>::const_iterator it = + this->LanguageToOriginalSharedLibFlags.find(l); + if(it != this->LanguageToOriginalSharedLibFlags.end()) + { + return it->second; + } + return ""; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AppendDirectoryForConfig(const std::string&, + const std::string&, + const std::string&, + 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(cmGeneratorTarget const* target) +{ + return this->TargetDependencies[target]; +} + +void cmGlobalGenerator::AddTarget(cmTarget* t) +{ + if(t->IsImported()) + { + this->ImportedTargets[t->GetName()] = t; + } + else + { + this->TotalTargets[t->GetName()] = t; + } +} + +bool cmGlobalGenerator::IsReservedTarget(std::string const& name) +{ + // The following is a list of targets reserved + // by one or more of the cmake generators. + + // Adding additional targets to this list will require a policy! + const char* reservedTargets[] = + { + "all", "ALL_BUILD", + "help", + "install", "INSTALL", + "preinstall", + "clean", + "edit_cache", + "rebuild_cache", + "test", "RUN_TESTS", + "package", "PACKAGE", + "package_source", + "ZERO_CHECK" + }; + + return std::find(cmArrayBegin(reservedTargets), + cmArrayEnd(reservedTargets), name) + != cmArrayEnd(reservedTargets); +} + +void cmGlobalGenerator::SetExternalMakefileProjectGenerator( + cmExternalMakefileProjectGenerator *extraGenerator) +{ + this->ExtraGenerator = extraGenerator; + if (this->ExtraGenerator!=0) + { + this->ExtraGenerator->SetGlobalGenerator(this); + } +} + +std::string cmGlobalGenerator::GetExtraGeneratorName() const +{ + return this->ExtraGenerator? this->ExtraGenerator->GetName() : std::string(); +} + +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 + cmGeneratorTarget* gt = this->GetGeneratorTarget(target); + originalTargets.insert(gt); + // Get the set of targets that depend on target + this->AddTargetDepends(gt, projectTargets); + } + } +} + +//---------------------------------------------------------------------------- +bool cmGlobalGenerator::IsRootOnlyTarget(cmTarget* target) const +{ + return (target->GetType() == cmTarget::GLOBAL_TARGET || + target->GetName() == this->GetAllTargetName()); +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* 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) + { + this->AddTargetDepends(*i, projectTargets); + } + } +} + + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddToManifest(const std::string& 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); + DirectoryContent& dc = this->DirectoryContentMap[dir]; + dc.Generated.insert(file); + dc.All.insert(file); +} + +//---------------------------------------------------------------------------- +std::set<std::string> const& +cmGlobalGenerator::GetDirectoryContent(std::string const& dir, bool needDisk) +{ + DirectoryContent& dc = this->DirectoryContentMap[dir]; + if(needDisk) + { + long mt = cmSystemTools::ModifiedTime(dir); + if (mt != dc.LastDiskTime) + { + // Reset to non-loaded directory content. + dc.All = dc.Generated; + + // Load the directory content from disk. + cmsys::Directory d; + if(d.Load(dir)) + { + 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.All.insert(f); + } + } + } + dc.LastDiskTime = mt; + } + } + return dc.All; +} + +//---------------------------------------------------------------------------- +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], + 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__) + cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary); +#else + cmsys::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<std::string, 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, home.c_str()); + cmSystemTools::RemoveFile(fname); + } + } + 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, 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); + } + else + { + cmGeneratedFileStream fout(pfile.c_str()); + fout << "# Hashes of file build rules.\n"; + for(std::map<std::string, 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. + for(TargetMap::const_iterator ti = + this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti) + { + if ((ti->second)->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } + 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"; + std::string json_file = dir + "/Labels.json"; + +#ifdef CMAKE_BUILD_WITH_CMAKE + // Check whether labels are enabled for this target. + if(const char* value = target->GetProperty("LABELS")) + { + Json::Value lj_root(Json::objectValue); + Json::Value& lj_target = + lj_root["target"] = Json::objectValue; + lj_target["name"] = target->GetName(); + Json::Value& lj_target_labels = + lj_target["labels"] = Json::arrayValue; + Json::Value& lj_sources = + lj_root["sources"] = Json::arrayValue; + + 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"; + lj_target_labels.append(*li); + } + } + + // List the source files with any per-source labels. + fout << "# Source files and their labels\n"; + std::vector<cmSourceFile*> sources; + std::vector<std::string> configs; + target->GetMakefile()->GetConfigurations(configs); + if (configs.empty()) + { + configs.push_back(""); + } + for(std::vector<std::string>::const_iterator ci = configs.begin(); + ci != configs.end(); ++ci) + { + target->GetSourceFiles(sources, *ci); + } + std::vector<cmSourceFile*>::const_iterator sourcesEnd + = cmRemoveDuplicates(sources); + for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); + si != sourcesEnd; ++si) + { + Json::Value& lj_source = lj_sources.append(Json::objectValue); + cmSourceFile* sf = *si; + std::string const& sfp = sf->GetFullPath(); + fout << sfp << "\n"; + lj_source["file"] = sfp; + if(const char* svalue = sf->GetProperty("LABELS")) + { + labels.clear(); + Json::Value& lj_source_labels = + lj_source["labels"] = Json::arrayValue; + cmSystemTools::ExpandListArgument(svalue, labels); + for(std::vector<std::string>::const_iterator li = labels.begin(); + li != labels.end(); ++li) + { + fout << " " << *li << "\n"; + lj_source_labels.append(*li); + } + } + } + cmGeneratedFileStream json_fout(json_file.c_str()); + json_fout << lj_root; + } + else +#endif + { + cmSystemTools::RemoveFile(file); + cmSystemTools::RemoveFile(json_file); + } +} + +//---------------------------------------------------------------------------- +// 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; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::SetFilenameTargetDepends(cmSourceFile* sf, + std::set<cmTarget const*> tgts) +{ + this->FilenameTargetDepends[sf] = tgts; +} + +//---------------------------------------------------------------------------- +std::set<cmTarget const*> const& +cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const { + return this->FilenameTargetDepends[sf]; +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::CreateEvaluationSourceFiles( + std::string const& config) const +{ + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = this->EvaluationFiles.begin(); + li != this->EvaluationFiles.end(); + ++li) + { + (*li)->CreateOutputFile(config); + } +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddEvaluationFile(const std::string &inputFile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputExpr, + cmMakefile *makefile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, + bool inputIsContent) +{ + this->EvaluationFiles.push_back( + new cmGeneratorExpressionEvaluationFile(inputFile, outputExpr, + makefile, condition, + inputIsContent)); +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::ProcessEvaluationFiles() +{ + std::vector<std::string> generatedFiles; + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = this->EvaluationFiles.begin(); + li != this->EvaluationFiles.end(); + ++li) + { + (*li)->Generate(); + if (cmSystemTools::GetFatalErrorOccured()) + { + return; + } + std::vector<std::string> files = (*li)->GetFiles(); + std::sort(files.begin(), files.end()); + + std::vector<std::string> intersection; + std::set_intersection(files.begin(), files.end(), + generatedFiles.begin(), generatedFiles.end(), + std::back_inserter(intersection)); + if (!intersection.empty()) + { + cmSystemTools::Error("Files to be generated by multiple different " + "commands: ", cmWrap('"', intersection, '"', " ").c_str()); + return; + } + + generatedFiles.insert(generatedFiles.end(), + files.begin(), files.end()); + std::vector<std::string>::iterator newIt = + generatedFiles.end() - files.size(); + std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end()); + } +} + +//---------------------------------------------------------------------------- +std::string cmGlobalGenerator::ExpandCFGIntDir(const std::string& str, + const std::string& /*config*/) const +{ + return str; +} + +//---------------------------------------------------------------------------- +bool cmGlobalGenerator::GenerateCPackPropertiesFile() +{ + cmake::InstalledFilesMap const& installedFiles = + this->CMakeInstance->GetInstalledFiles(); + + cmMakefile* mf = this->LocalGenerators[0]->GetMakefile(); + + std::vector<std::string> configs; + std::string config = mf->GetConfigurations(configs, false); + + std::string path = this->CMakeInstance->GetHomeOutputDirectory(); + path += "/CPackProperties.cmake"; + + if(!cmSystemTools::FileExists(path.c_str()) && installedFiles.empty()) + { + return true; + } + + cmGeneratedFileStream file(path.c_str()); + file << "# CPack properties\n"; + + for(cmake::InstalledFilesMap::const_iterator i = installedFiles.begin(); + i != installedFiles.end(); ++i) + { + cmInstalledFile const& installedFile = i->second; + + cmCPackPropertiesGenerator cpackPropertiesGenerator( + mf, installedFile, configs); + + cpackPropertiesGenerator.Generate(file, config, configs); + } + + return true; +} |