summaryrefslogtreecommitdiffstats
path: root/Source/cmake.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmake.cxx')
-rw-r--r--Source/cmake.cxx254
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);
}