diff options
Diffstat (limited to 'Source/cmake.cxx')
-rw-r--r-- | Source/cmake.cxx | 254 |
1 files changed, 154 insertions, 100 deletions
diff --git a/Source/cmake.cxx b/Source/cmake.cxx index f0caf0d..733e0e4 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -12,10 +12,12 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" +#include "cmLinkLineComputer.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessenger.h" #include "cmState.h" +#include "cmStateDirectory.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetLinkLibraryType.h" @@ -24,10 +26,11 @@ #include "cm_auto_ptr.hxx" #if defined(CMAKE_BUILD_WITH_CMAKE) +#include <cm_jsoncpp_writer.h> + #include "cmGraphVizWriter.h" #include "cmVariableWatch.h" - -#include <cm_jsoncpp_writer.h> +#include "cm_unordered_map.hxx" #endif // only build kdevelop generator on non-windows platforms @@ -121,17 +124,13 @@ class cmCommand; namespace { #if defined(CMAKE_BUILD_WITH_CMAKE) -#ifdef CMake_HAVE_CXX_UNORDERED_MAP -typedef std::unordered_map<std::string, Json::Value> JsonValueMapType; -#else -typedef cmsys::hash_map<std::string, Json::Value> JsonValueMapType; -#endif +typedef CM_UNORDERED_MAP<std::string, Json::Value> JsonValueMapType; #endif } // namespace -static bool cmakeCheckStampFile(const char* stampName); -static bool cmakeCheckStampList(const char* stampName); +static bool cmakeCheckStampFile(const char* stampName, bool verbose = true); +static bool cmakeCheckStampList(const char* stampList, bool verbose = true); void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, void* ctx, const char* /*unused*/, @@ -314,7 +313,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) } } std::string var, value; - cmState::CacheEntryType type = cmState::UNINITIALIZED; + cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED; if (cmState::ParseCacheEntry(entry, var, value, type)) { // The value is transformed if it is a filepath for example, so // we can't compare whether the value is already in the cache until @@ -409,8 +408,8 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) std::vector<std::string> cacheKeys = this->State->GetCacheEntryKeys(); for (std::vector<std::string>::const_iterator it = cacheKeys.begin(); it != cacheKeys.end(); ++it) { - cmState::CacheEntryType t = this->State->GetCacheEntryType(*it); - if (t != cmState::STATIC) { + cmStateEnums::CacheEntryType t = this->State->GetCacheEntryType(*it); + if (t != cmStateEnums::STATIC) { if (regex.find(it->c_str())) { entriesToDelete.push_back(*it); } @@ -480,7 +479,7 @@ void cmake::ReadListFile(const std::vector<std::string>& args, std::string homeOutputDir = this->GetHomeOutputDirectory(); this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory()); this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory()); - cmState::Snapshot snapshot = this->GetCurrentSnapshot(); + cmStateSnapshot snapshot = this->GetCurrentSnapshot(); snapshot.GetDirectory().SetCurrentBinary( cmSystemTools::GetCurrentWorkingDirectory()); snapshot.GetDirectory().SetCurrentSource( @@ -516,7 +515,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) cmGlobalGenerator* gg = new cmGlobalGenerator(this); this->SetGlobalGenerator(gg); - cmState::Snapshot snapshot = this->GetCurrentSnapshot(); + cmStateSnapshot snapshot = this->GetCurrentSnapshot(); snapshot.GetDirectory().SetCurrentBinary( cmSystemTools::GetCurrentWorkingDirectory()); snapshot.GetDirectory().SetCurrentSource( @@ -568,7 +567,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) cmSystemTools::ExpandListArgument(libs, libList); for (std::vector<std::string>::const_iterator libIt = libList.begin(); libIt != libList.end(); ++libIt) { - mf->AddLinkLibraryForTarget(targetName, *libIt, GENERAL_LibraryType); + tgt->AddLinkLibrary(*mf, *libIt, GENERAL_LibraryType); } std::string buildType = mf->GetSafeDefinition("CMAKE_BUILD_TYPE"); @@ -582,8 +581,10 @@ bool cmake::FindPackage(const std::vector<std::string>& args) gg->CreateGenerationObjects(); cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName()); cmLocalGenerator* lg = gtgt->GetLocalGenerator(); - lg->GetTargetFlags(buildType, linkLibs, flags, linkFlags, frameworkPath, - linkPath, gtgt, false); + cmLinkLineComputer linkLineComputer(lg, + lg->GetStateSnapshot().GetDirectory()); + lg->GetTargetFlags(&linkLineComputer, buildType, linkLibs, flags, + linkFlags, frameworkPath, linkPath, gtgt); linkLibs = frameworkPath + linkPath + linkLibs; printf("%s\n", linkLibs.c_str()); @@ -856,14 +857,14 @@ int cmake::AddCMakePaths() // Save the value in the cache this->AddCacheEntry("CMAKE_COMMAND", cmSystemTools::GetCMakeCommand().c_str(), - "Path to CMake executable.", cmState::INTERNAL); + "Path to CMake executable.", cmStateEnums::INTERNAL); #ifdef CMAKE_BUILD_WITH_CMAKE - this->AddCacheEntry("CMAKE_CTEST_COMMAND", - cmSystemTools::GetCTestCommand().c_str(), - "Path to ctest program executable.", cmState::INTERNAL); - this->AddCacheEntry("CMAKE_CPACK_COMMAND", - cmSystemTools::GetCPackCommand().c_str(), - "Path to cpack program executable.", cmState::INTERNAL); + this->AddCacheEntry( + "CMAKE_CTEST_COMMAND", cmSystemTools::GetCTestCommand().c_str(), + "Path to ctest program executable.", cmStateEnums::INTERNAL); + this->AddCacheEntry( + "CMAKE_CPACK_COMMAND", cmSystemTools::GetCPackCommand().c_str(), + "Path to cpack program executable.", cmStateEnums::INTERNAL); #endif if (!cmSystemTools::FileExists( (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake").c_str())) { @@ -876,7 +877,7 @@ int cmake::AddCMakePaths() return 0; } this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot().c_str(), - "Path to CMake installation.", cmState::INTERNAL); + "Path to CMake installation.", cmStateEnums::INTERNAL); return 1; } @@ -1144,7 +1145,7 @@ struct SaveCacheEntry std::string key; std::string value; std::string help; - cmState::CacheEntryType type; + cmStateEnums::CacheEntryType type; }; int cmake::HandleDeleteCacheVariables(const std::string& var) @@ -1288,7 +1289,7 @@ int cmake::ActualConfigure() "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory(), "Source directory with the top level CMakeLists.txt file for this " "project", - cmState::INTERNAL); + cmStateEnums::INTERNAL); } // no generator specified on the command line @@ -1310,54 +1311,7 @@ int cmake::ActualConfigure() cmSystemTools::SetForceUnixPaths( this->GlobalGenerator->GetForceUnixPaths()); } else { -#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW) - std::string installedCompiler; - // Try to find the newest VS installed on the computer and - // use that as a default if -G is not specified - const std::string vsregBase = - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"; - std::vector<std::string> vsVerions; - vsVerions.push_back("VisualStudio\\"); - vsVerions.push_back("VCExpress\\"); - vsVerions.push_back("WDExpress\\"); - struct VSRegistryEntryName - { - const char* MSVersion; - const char* GeneratorName; - }; - VSRegistryEntryName version[] = { - /* clang-format needs this comment to break after the opening brace */ - { "7.1", "Visual Studio 7 .NET 2003" }, - { "8.0", "Visual Studio 8 2005" }, - { "9.0", "Visual Studio 9 2008" }, - { "10.0", "Visual Studio 10 2010" }, - { "11.0", "Visual Studio 11 2012" }, - { "12.0", "Visual Studio 12 2013" }, - { "14.0", "Visual Studio 14 2015" }, - { "15.0", "Visual Studio 15 2017" }, - { 0, 0 } - }; - for (int i = 0; version[i].MSVersion != 0; i++) { - for (size_t b = 0; b < vsVerions.size(); b++) { - std::string reg = vsregBase + vsVerions[b] + version[i].MSVersion; - reg += ";InstallDir]"; - cmSystemTools::ExpandRegistryValues(reg, cmSystemTools::KeyWOW64_32); - if (!(reg == "/registry")) { - installedCompiler = version[i].GeneratorName; - break; - } - } - } - cmGlobalGenerator* gen = - this->CreateGlobalGenerator(installedCompiler.c_str()); - if (!gen) { - gen = new cmGlobalNMakeMakefileGenerator(this); - } - this->SetGlobalGenerator(gen); - std::cout << "-- Building for: " << gen->GetName() << "\n"; -#else - this->SetGlobalGenerator(new cmGlobalUnixMakefileGenerator3(this)); -#endif + this->CreateDefaultGlobalGenerator(); } if (!this->GlobalGenerator) { cmSystemTools::Error("Could not create generator"); @@ -1382,11 +1336,11 @@ int cmake::ActualConfigure() if (!this->State->GetInitializedCacheValue("CMAKE_GENERATOR")) { this->AddCacheEntry("CMAKE_GENERATOR", this->GlobalGenerator->GetName().c_str(), - "Name of generator.", cmState::INTERNAL); + "Name of generator.", cmStateEnums::INTERNAL); this->AddCacheEntry("CMAKE_EXTRA_GENERATOR", this->GlobalGenerator->GetExtraGeneratorName().c_str(), "Name of external makefile project generator.", - cmState::INTERNAL); + cmStateEnums::INTERNAL); } if (const char* platformName = @@ -1406,7 +1360,7 @@ int cmake::ActualConfigure() } else { this->AddCacheEntry("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform.c_str(), - "Name of generator platform.", cmState::INTERNAL); + "Name of generator platform.", cmStateEnums::INTERNAL); } if (const char* tsName = @@ -1426,7 +1380,7 @@ int cmake::ActualConfigure() } else { this->AddCacheEntry("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset.c_str(), - "Name of generator toolset.", cmState::INTERNAL); + "Name of generator toolset.", cmStateEnums::INTERNAL); } // reset any system configuration information, except for when we are @@ -1455,13 +1409,14 @@ int cmake::ActualConfigure() if (!this->State->GetInitializedCacheValue("LIBRARY_OUTPUT_PATH")) { this->AddCacheEntry( "LIBRARY_OUTPUT_PATH", "", - "Single output directory for building all libraries.", cmState::PATH); + "Single output directory for building all libraries.", + cmStateEnums::PATH); } if (!this->State->GetInitializedCacheValue("EXECUTABLE_OUTPUT_PATH")) { this->AddCacheEntry( "EXECUTABLE_OUTPUT_PATH", "", "Single output directory for building all executables.", - cmState::PATH); + cmStateEnums::PATH); } } @@ -1485,6 +1440,63 @@ int cmake::ActualConfigure() return 0; } +void cmake::CreateDefaultGlobalGenerator() +{ +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW) + std::string found; + // Try to find the newest VS installed on the computer and + // use that as a default if -G is not specified + const std::string vsregBase = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"; + static const char* const vsVariants[] = { + /* clang-format needs this comment to break after the opening brace */ + "VisualStudio\\", "VCExpress\\", "WDExpress\\" + }; + struct VSVersionedGenerator + { + const char* MSVersion; + const char* GeneratorName; + }; + static VSVersionedGenerator const vsGenerators[] = { + { "15.0", "Visual Studio 15 2017" }, // + { "14.0", "Visual Studio 14 2015" }, // + { "12.0", "Visual Studio 12 2013" }, // + { "11.0", "Visual Studio 11 2012" }, // + { "10.0", "Visual Studio 10 2010" }, // + { "9.0", "Visual Studio 9 2008" }, // + { "8.0", "Visual Studio 8 2005" }, // + { "7.1", "Visual Studio 7 .NET 2003" } + }; + static const char* const vsEntries[] = { + "\\Setup\\VC;ProductDir", // + ";InstallDir" // + }; + for (VSVersionedGenerator const* g = cmArrayBegin(vsGenerators); + found.empty() && g != cmArrayEnd(vsGenerators); ++g) { + for (const char* const* v = cmArrayBegin(vsVariants); + found.empty() && v != cmArrayEnd(vsVariants); ++v) { + for (const char* const* e = cmArrayBegin(vsEntries); + found.empty() && e != cmArrayEnd(vsEntries); ++e) { + std::string const reg = vsregBase + *v + g->MSVersion + *e; + std::string dir; + if (cmSystemTools::ReadRegistryValue(reg, dir, + cmSystemTools::KeyWOW64_32) && + cmSystemTools::PathExists(dir)) { + found = g->GeneratorName; + } + } + } + } + cmGlobalGenerator* gen = this->CreateGlobalGenerator(found); + if (!gen) { + gen = new cmGlobalNMakeMakefileGenerator(this); + } + this->SetGlobalGenerator(gen); + std::cout << "-- Building for: " << gen->GetName() << "\n"; +#else + this->SetGlobalGenerator(new cmGlobalUnixMakefileGenerator3(this)); +#endif +} + void cmake::PreLoadCMakeFiles() { std::vector<std::string> args; @@ -1627,7 +1639,7 @@ void cmake::AddCacheEntry(const std::string& key, const char* value, const char* helpString, int type) { this->State->AddCacheEntry(key, value, helpString, - cmState::CacheEntryType(type)); + cmStateEnums::CacheEntryType(type)); this->UnwatchUnusedCli(key); } @@ -1638,11 +1650,8 @@ const char* cmake::GetCacheDefinition(const std::string& name) const void cmake::AddDefaultCommands() { - std::vector<cmCommand*> commands; - GetBootstrapCommands1(commands); - GetBootstrapCommands2(commands); - GetPredefinedCommands(commands); - for (std::vector<cmCommand*>::iterator i = commands.begin(); + std::vector<cmCommand*> const commands = GetPredefinedCommands(); + for (std::vector<cmCommand*>::const_iterator i = commands.begin(); i != commands.end(); ++i) { this->State->AddCommand(*i); } @@ -1681,7 +1690,8 @@ void cmake::AddDefaultGenerators() } bool cmake::ParseCacheEntry(const std::string& entry, std::string& var, - std::string& value, cmState::CacheEntryType& type) + std::string& value, + cmStateEnums::CacheEntryType& type) { return cmState::ParseCacheEntry(entry, var, value, type); } @@ -2223,7 +2233,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) return 0; } -static bool cmakeCheckStampFile(const char* stampName) +static bool cmakeCheckStampFile(const char* stampName, bool verbose) { // The stamp file does not exist. Use the stamp dependencies to // determine whether it is really out of date. This works in @@ -2277,11 +2287,13 @@ static bool cmakeCheckStampFile(const char* stampName) stamp << "# CMake generation timestamp file for this directory.\n"; } if (cmSystemTools::RenameFile(stampTemp, stampName)) { - // Notify the user why CMake is not re-running. It is safe to - // just print to stdout here because this code is only reachable - // through an undocumented flag used by the VS generator. - std::cout << "CMake does not need to re-run because " << stampName - << " is up-to-date.\n"; + if (verbose) { + // Notify the user why CMake is not re-running. It is safe to + // just print to stdout here because this code is only reachable + // through an undocumented flag used by the VS generator. + std::cout << "CMake does not need to re-run because " << stampName + << " is up-to-date.\n"; + } return true; } cmSystemTools::RemoveFile(stampTemp); @@ -2289,7 +2301,7 @@ static bool cmakeCheckStampFile(const char* stampName) return false; } -static bool cmakeCheckStampList(const char* stampList) +static bool cmakeCheckStampList(const char* stampList, bool verbose) { // If the stamp list does not exist CMake must rerun to generate it. if (!cmSystemTools::FileExists(stampList)) { @@ -2307,7 +2319,7 @@ static bool cmakeCheckStampList(const char* stampList) // Check each stamp. std::string stampName; while (cmSystemTools::GetLineFromStream(fin, stampName)) { - if (!cmakeCheckStampFile(stampName.c_str())) { + if (!cmakeCheckStampFile(stampName.c_str(), verbose)) { return false; } } @@ -2387,6 +2399,48 @@ int cmake::Build(const std::string& dir, const std::string& target, if (cachedVerbose) { verbose = cmSystemTools::IsOn(cachedVerbose); } + +#ifdef CMAKE_HAVE_VS_GENERATORS + // For VS generators, explicitly check if regeneration is necessary before + // actually starting the build. If not done separately from the build + // itself, there is the risk of building an out-of-date solution file due + // to limitations of the underlying build system. + std::string const stampList = cachePath + "/" + + GetCMakeFilesDirectoryPostSlash() + + cmGlobalVisualStudio8Generator::GetGenerateStampList(); + + // Note that the stampList file only exists for VS generators. + if (cmSystemTools::FileExists(stampList.c_str()) && + !cmakeCheckStampList(stampList.c_str(), false)) { + + // Correctly initialize the home (=source) and home output (=binary) + // directories, which is required for running the generation step. + std::string homeOrig = this->GetHomeDirectory(); + std::string homeOutputOrig = this->GetHomeOutputDirectory(); + this->SetDirectoriesFromFile(cachePath.c_str()); + + int ret = this->Configure(); + if (ret) { + cmSystemTools::Message("CMake Configure step failed. " + "Build files cannot be regenerated correctly."); + return ret; + } + ret = this->Generate(); + if (ret) { + cmSystemTools::Message("CMake Generate step failed. " + "Build files cannot be regenerated correctly."); + return ret; + } + std::string message = "Build files have been written to: "; + message += this->GetHomeOutputDirectory(); + this->UpdateProgress(message.c_str(), -1); + + // Restore the previously set directories to their original value. + this->SetHomeDirectory(homeOrig); + this->SetHomeOutputDirectory(homeOutputOrig); + } +#endif + return gen->Build("", dir, projName, target, output, "", config, clean, false, verbose, 0, cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions); @@ -2451,7 +2505,7 @@ void cmake::SetSuppressDevWarnings(bool b) this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", value.c_str(), "Suppress Warnings that are meant for" " the author of the CMakeLists.txt files.", - cmState::INTERNAL); + cmStateEnums::INTERNAL); } bool cmake::GetSuppressDeprecatedWarnings() const @@ -2475,7 +2529,7 @@ void cmake::SetSuppressDeprecatedWarnings(bool b) this->AddCacheEntry("CMAKE_WARN_DEPRECATED", value.c_str(), "Whether to issue warnings for deprecated " "functionality.", - cmState::INTERNAL); + cmStateEnums::INTERNAL); } bool cmake::GetDevWarningsAsErrors() const @@ -2499,7 +2553,7 @@ void cmake::SetDevWarningsAsErrors(bool b) this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_ERRORS", value.c_str(), "Suppress errors that are meant for" " the author of the CMakeLists.txt files.", - cmState::INTERNAL); + cmStateEnums::INTERNAL); } bool cmake::GetDeprecatedWarningsAsErrors() const @@ -2523,5 +2577,5 @@ void cmake::SetDeprecatedWarningsAsErrors(bool b) this->AddCacheEntry("CMAKE_ERROR_DEPRECATED", value.c_str(), "Whether to issue deprecation errors for macros" " and functions.", - cmState::INTERNAL); + cmStateEnums::INTERNAL); } |