From 8e6d930e8c3fb951e3c4388cc6a9a96dedcb412b Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 26 Oct 2021 15:13:53 -0400 Subject: VS: Parse comma-separated fields from CMAKE_GENERATOR_INSTANCE --- Help/variable/CMAKE_GENERATOR_INSTANCE.rst | 13 +++- Source/cmGlobalVisualStudioVersionedGenerator.cxx | 87 +++++++++++++++++++++- Source/cmGlobalVisualStudioVersionedGenerator.h | 7 ++ .../GeneratorInstance/BadFieldNoComma-result.txt | 1 + .../GeneratorInstance/BadFieldNoComma-stderr.txt | 11 +++ .../GeneratorInstance/BadFieldNoComma.cmake | 1 + .../GeneratorInstance/BadFieldUnknown-result.txt | 1 + .../GeneratorInstance/BadFieldUnknown-stderr.txt | 11 +++ .../GeneratorInstance/BadFieldUnknown.cmake | 1 + .../RunCMake/GeneratorInstance/RunCMakeTest.cmake | 5 ++ 10 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt create mode 100644 Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst index 5a76f09..57dba53 100644 --- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst +++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst @@ -26,7 +26,18 @@ Visual Studio Instance Selection :ref:`Visual Studio Generators` support instance specification for Visual Studio 2017 and above. The ``CMAKE_GENERATOR_INSTANCE`` variable may be set as a cache entry selecting an instance of Visual Studio -via the absolute path to the top-level directory of the VS installation. +via one of the following forms: + +* ``location`` +* ``location[,key=value]*`` +* ``key=value[,key=value]*`` + +The ``location`` specifies the absolute path to the top-level directory +of the VS installation. + +The ``key=value`` pairs form a comma-separated list of options to +specify details of the instance selection. +There are no supported pairs: this syntax is reserved for future use. If the value of ``CMAKE_GENERATOR_INSTANCE`` is not specified explicitly by the user or a toolchain file, CMake queries the Visual Studio Installer diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index f27b2c4..78bebac 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -441,8 +441,12 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( return true; } - if (!i.empty()) { - if (!this->vsSetupAPIHelper.SetVSInstance(i)) { + if (!this->ParseGeneratorInstance(i, mf)) { + return false; + } + + if (!this->GeneratorInstance.empty()) { + if (!this->vsSetupAPIHelper.SetVSInstance(this->GeneratorInstance)) { std::ostringstream e; /* clang-format off */ e << @@ -485,6 +489,85 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( return true; } +bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance( + std::string const& is, cmMakefile* mf) +{ + this->GeneratorInstance.clear(); + + std::vector const fields = cmTokenize(is, ","); + std::vector::const_iterator fi = fields.begin(); + if (fi == fields.end()) { + return true; + } + + // The first field may be the VS instance. + if (fi->find('=') == fi->npos) { + this->GeneratorInstance = *fi; + ++fi; + } + + std::set handled; + + // The rest of the fields must be key=value pairs. + for (; fi != fields.end(); ++fi) { + std::string::size_type pos = fi->find('='); + if (pos == fi->npos) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "given instance specification\n" + " " << is << "\n" + "that contains a field after the first ',' with no '='." + ; + /* clang-format on */ + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + std::string const key = fi->substr(0, pos); + std::string const value = fi->substr(pos + 1); + if (!handled.insert(key).second) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "given instance specification\n" + " " << is << "\n" + "that contains duplicate field key '" << key << "'." + ; + /* clang-format on */ + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + if (!this->ProcessGeneratorInstanceField(key, value)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "given instance specification\n" + " " << is << "\n" + "that contains invalid field '" << *fi << "'." + ; + /* clang-format on */ + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + } + + return true; +} + +bool cmGlobalVisualStudioVersionedGenerator::ProcessGeneratorInstanceField( + std::string const& key, std::string const& value) +{ + static_cast(key); + static_cast(value); + return false; +} + bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance( std::string& dir) const { diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index 2aed65b..a19e506 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -65,6 +65,9 @@ protected: std::string GetWindows10SDKMaxVersionDefault(cmMakefile*) const override; + virtual bool ProcessGeneratorInstanceField(std::string const& key, + std::string const& value); + std::string FindMSBuildCommand() override; std::string FindDevEnvCommand() override; @@ -76,5 +79,9 @@ private: class Factory17; friend class Factory17; mutable cmVSSetupAPIHelper vsSetupAPIHelper; + + bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf); + + std::string GeneratorInstance; cm::optional LastGeneratorInstanceString; }; diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt new file mode 100644 index 0000000..d6c73c8 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma-stderr.txt @@ -0,0 +1,11 @@ +^CMake Error at CMakeLists.txt:[0-9]+ \(project\): + Generator + + Visual Studio [^ +]+ + + given instance specification + + Test Instance,nocomma + + that contains a field after the first ',' with no '='\.$ diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake new file mode 100644 index 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldNoComma.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR "This should not be reached!") diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt new file mode 100644 index 0000000..ecfe229 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown-stderr.txt @@ -0,0 +1,11 @@ +^CMake Error at CMakeLists.txt:[0-9]+ \(project\): + Generator + + Visual Studio [^ +]+ + + given instance specification + + Test Instance,unknown= + + that contains invalid field 'unknown='\.$ diff --git a/Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown.cmake new file mode 100644 index 0000000..2fc38e5 --- /dev/null +++ b/Tests/RunCMake/GeneratorInstance/BadFieldUnknown.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 e7f9ccb..5eeac8e 100644 --- a/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorInstance/RunCMakeTest.cmake @@ -9,6 +9,11 @@ if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio 1[56789]") set(RunCMake_TEST_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/MissingInstance-toolchain.cmake) run_cmake(MissingInstanceToolchain) unset(RunCMake_TEST_OPTIONS) + + set(RunCMake_GENERATOR_INSTANCE "Test Instance,nocomma") + run_cmake(BadFieldNoComma) + set(RunCMake_GENERATOR_INSTANCE "Test Instance,unknown=") + run_cmake(BadFieldUnknown) else() set(RunCMake_GENERATOR_INSTANCE "") run_cmake(NoInstance) -- cgit v0.12