diff options
author | Brad King <brad.king@kitware.com> | 2017-10-04 17:01:47 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2017-10-19 14:20:12 (GMT) |
commit | 9ffb35386fb923a5959eec482bfa131aa3feaa18 (patch) | |
tree | a01b2cc99c387db8f4ef234d70ff35de43009b70 | |
parent | 17edfa41983c61574e897eda923c90fd33ba8ac3 (diff) | |
download | CMake-9ffb35386fb923a5959eec482bfa131aa3feaa18.zip CMake-9ffb35386fb923a5959eec482bfa131aa3feaa18.tar.gz CMake-9ffb35386fb923a5959eec482bfa131aa3feaa18.tar.bz2 |
VS: Select and save a VS 2017 instance persistently
Visual Studio 2017 supports multiple instances installed on a single
machine. We use the Visual Studio Installer tool to enumerate instances
and select one. Once we select an instance for a given build tree, save
the result in `CMAKE_GENERATOR_INSTANCE` so we can re-configure the tree
with the same instance on future re-runs of CMake.
Fixes: #17268
16 files changed, 135 insertions, 24 deletions
diff --git a/Help/generator/Visual Studio 15 2017.rst b/Help/generator/Visual Studio 15 2017.rst index 2ac0449..2cf1aa0 100644 --- a/Help/generator/Visual Studio 15 2017.rst +++ b/Help/generator/Visual Studio 15 2017.rst @@ -19,13 +19,17 @@ Instance Selection ^^^^^^^^^^^^^^^^^^ VS 2017 supports multiple installations on the same machine. -CMake queries the Visual Studio Installer to locate VS instances. -If more than one instance is installed we do not define which one -is chosen by default. If the ``VS150COMNTOOLS`` environment variable -is set and points to the ``Common7/Tools`` directory within one of -the instances, that instance will be used. The environment variable -must remain consistently set whenever CMake is re-run within a given -build tree. +The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a +cache entry containing the absolute path to a Visual Studio instance. +If the value is not specified explicitly by the user or a toolchain file, +CMake queries the Visual Studio Installer to locate VS instances, chooses +one, and sets the variable as a cache entry to hold the value persistently. + +When CMake first chooses an instance, if the ``VS150COMNTOOLS`` environment +variable is set and points to the ``Common7/Tools`` directory within +one of the instances, that instance will be used. Otherwise, if more +than one instance is installed we do not define which one is chosen +by default. Toolset Selection ^^^^^^^^^^^^^^^^^ diff --git a/Help/release/dev/generator-instance.rst b/Help/release/dev/generator-instance.rst index 5e92f7d..a3ff658 100644 --- a/Help/release/dev/generator-instance.rst +++ b/Help/release/dev/generator-instance.rst @@ -3,5 +3,6 @@ generator-instance * A :variable:`CMAKE_GENERATOR_INSTANCE` variable was introduced to hold the selected instance of the generator's corresponding - native tools if multiple are available. Currently no generators - actually use this, but the infrastructure is in place. + native tools if multiple are available. This is used by the + :generator:`Visual Studio 15 2017` generator to hold the + selected instance of Visual Studio persistently. diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst index 7c2c280..78c81b1 100644 --- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst +++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst @@ -17,6 +17,8 @@ for this variable, changing the value has undefined behavior. Instance specification is supported only on specific generators: -* None +* For the :generator:`Visual Studio 15 2017` generator (and above) + this specifies the absolute path to the VS installation directory + of the selected VS instance. See native build system documentation for allowed instance values. diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index 5106f52..662dd74 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -8,6 +8,9 @@ #include "cmsys/SystemInformation.hxx" #if defined(_WIN32) +#include "cmAlgorithms.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalVisualStudio15Generator.h" #include "cmSystemTools.h" #include "cmVSSetupHelper.h" #define HAVE_VS_SETUP_HELPER @@ -127,6 +130,17 @@ bool cmCMakeHostSystemInformationCommand::GetValue( value = this->ValueToString(info.GetOSPlatform()); #ifdef HAVE_VS_SETUP_HELPER } else if (key == "VS_15_DIR") { + // If generating for the VS 15 IDE, use the same instance. + cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator(); + if (cmHasLiteralPrefix(gg->GetName(), "Visual Studio 15 ")) { + cmGlobalVisualStudio15Generator* vs15gen = + static_cast<cmGlobalVisualStudio15Generator*>(gg); + if (vs15gen->GetVSInstance(value)) { + return true; + } + } + + // Otherwise, find a VS 15 instance ourselves. cmVSSetupAPIHelper vsSetupAPIHelper; if (vsSetupAPIHelper.GetVSInstanceInfo(value)) { cmSystemTools::ConvertToUnixSlashes(value); diff --git a/Source/cmGlobalVisualStudio15Generator.cxx b/Source/cmGlobalVisualStudio15Generator.cxx index d2bf7cc..014d93d 100644 --- a/Source/cmGlobalVisualStudio15Generator.cxx +++ b/Source/cmGlobalVisualStudio15Generator.cxx @@ -111,6 +111,53 @@ void cmGlobalVisualStudio15Generator::WriteSLNHeader(std::ostream& fout) } } +bool cmGlobalVisualStudio15Generator::SetGeneratorInstance( + std::string const& i, cmMakefile* mf) +{ + if (!i.empty()) { + if (!this->vsSetupAPIHelper.SetVSInstance(i)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "could not find specified instance of Visual Studio:\n" + " " << i; + /* clang-format on */ + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + } + + std::string vsInstance; + if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "could not find any instance of Visual Studio.\n"; + /* clang-format on */ + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + // Save the selected instance persistently. + std::string genInstance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"); + if (vsInstance != genInstance) { + this->CMakeInstance->AddCacheEntry( + "CMAKE_GENERATOR_INSTANCE", vsInstance.c_str(), + "Generator instance identifier.", cmStateEnums::INTERNAL); + } + + return true; +} + +bool cmGlobalVisualStudio15Generator::GetVSInstance(std::string& dir) const +{ + return vsSetupAPIHelper.GetVSInstanceInfo(dir); +} + bool cmGlobalVisualStudio15Generator::InitializeWindows(cmMakefile* mf) { // If the Win 8.1 SDK is installed then we can select a SDK matching diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h index e934882..852a4e7 100644 --- a/Source/cmGlobalVisualStudio15Generator.h +++ b/Source/cmGlobalVisualStudio15Generator.h @@ -27,6 +27,11 @@ public: virtual void WriteSLNHeader(std::ostream& fout); virtual const char* GetToolsVersion() { return "15.0"; } + + bool SetGeneratorInstance(std::string const& i, cmMakefile* mf) override; + + bool GetVSInstance(std::string& dir) const; + protected: bool InitializeWindows(cmMakefile* mf) override; virtual bool SelectWindowsStoreToolset(std::string& toolset) const; diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index 4f5f4e8..c2f8deb 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -273,13 +273,6 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() if (cmSystemTools::GetEnv("VS150COMNTOOLS", envVSCommonToolsDir)) { cmSystemTools::ConvertToUnixSlashes(envVSCommonToolsDir); } - // FIXME: If the environment variable value changes between runs - // of CMake within a given build tree the results are not defined. - // Instead we should save a CMAKE_GENERATOR_INSTANCE value in the cache - // (similar to CMAKE_GENERATOR_TOOLSET) to hold it persistently. - // Unfortunately doing so will require refactoring elsewhere in - // order to make sure the value is available in time to create - // the generator. std::vector<VSInstanceInfo> vecVSInstances; SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL; diff --git a/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake b/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake new file mode 100644 index 0000000..7750c2e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake @@ -0,0 +1,13 @@ +if("x${CMAKE_GENERATOR_INSTANCE}" STREQUAL "x") + message(FATAL_ERROR "CMAKE_GENERATOR_INSTANCE is empty but should have a value.") +elseif("x${CMAKE_GENERATOR_INSTANCE}" MATCHES [[\\]]) + message(FATAL_ERROR + "CMAKE_GENERATOR_INSTANCE is\n" + " ${CMAKE_GENERATOR_INSTANCE}\n" + "which contains a backslash.") +elseif(NOT IS_DIRECTORY "${CMAKE_GENERATOR_INSTANCE}") + message(FATAL_ERROR + "CMAKE_GENERATOR_INSTANCE is\n" + " ${CMAKE_GENERATOR_INSTANCE}\n" + "which is not an existing directory.") +endif() diff --git a/Tests/RunCMake/GeneratorInstance/MissingInstance-result.txt b/Tests/RunCMake/GeneratorInstance/MissingInstance-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/MissingInstance-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/MissingInstance-stderr.txt b/Tests/RunCMake/GeneratorInstance/MissingInstance-stderr.txt new file mode 100644 index 0000000..623bf2e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/MissingInstance-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at CMakeLists.txt:[0-9]+ \(project\): + Generator + + .* + + could not find specified instance of .*: + + .*/Tests/RunCMake/GeneratorInstance/instance_does_not_exist$ diff --git a/Tests/RunCMake/GeneratorInstance/MissingInstance-toolchain.cmake b/Tests/RunCMake/GeneratorInstance/MissingInstance-toolchain.cmake new file mode 100644 index 0000000..f803f14 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/MissingInstance-toolchain.cmake @@ -0,0 +1 @@ +set(CMAKE_GENERATOR_INSTANCE "${CMAKE_CURRENT_LIST_DIR}/instance_does_not_exist") diff --git a/Tests/RunCMake/GeneratorInstance/MissingInstance.cmake b/Tests/RunCMake/GeneratorInstance/MissingInstance.cmake new file mode 100644 index 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/MissingInstance.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-result.txt b/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-stderr.txt b/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-stderr.txt new file mode 100644 index 0000000..623bf2e --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at CMakeLists.txt:[0-9]+ \(project\): + Generator + + .* + + could not find specified instance of .*: + + .*/Tests/RunCMake/GeneratorInstance/instance_does_not_exist$ diff --git a/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain.cmake b/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain.cmake new file mode 100644 index 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/MissingInstanceToolchain.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake index f66da10..e7f9ccb 100644 --- a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake @@ -1,11 +1,22 @@ include(RunCMake) -set(RunCMake_GENERATOR_INSTANCE "") -run_cmake(NoInstance) +if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio 1[56789]") + set(RunCMake_GENERATOR_INSTANCE "") + run_cmake(DefaultInstance) -set(RunCMake_GENERATOR_INSTANCE "Bad Instance") -run_cmake(BadInstance) + set(RunCMake_GENERATOR_INSTANCE "${RunCMake_SOURCE_DIR}/instance_does_not_exist") + run_cmake(MissingInstance) + set(RunCMake_TEST_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/MissingInstance-toolchain.cmake) + run_cmake(MissingInstanceToolchain) + unset(RunCMake_TEST_OPTIONS) +else() + set(RunCMake_GENERATOR_INSTANCE "") + run_cmake(NoInstance) -set(RunCMake_TEST_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/BadInstance-toolchain.cmake) -run_cmake(BadInstanceToolchain) -unset(RunCMake_TEST_OPTIONS) + set(RunCMake_GENERATOR_INSTANCE "Bad Instance") + run_cmake(BadInstance) + + set(RunCMake_TEST_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/BadInstance-toolchain.cmake) + run_cmake(BadInstanceToolchain) + unset(RunCMake_TEST_OPTIONS) +endif() |