VS: Parse comma-separated fields from CMAKE_GENERATOR_INSTANCE

This commit is contained in:
Brad King
2021-10-26 15:13:53 -04:00
parent 5d1f377737
commit 8e6d930e8c
10 changed files with 135 additions and 3 deletions

View File

@@ -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

View File

@@ -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<std::string> const fields = cmTokenize(is, ",");
std::vector<std::string>::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<std::string> 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<void>(key);
static_cast<void>(value);
return false;
}
bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance(
std::string& dir) const
{

View File

@@ -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<std::string> LastGeneratorInstanceString;
};

View File

@@ -0,0 +1 @@
1

View File

@@ -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 '='\.$

View File

@@ -0,0 +1 @@
message(FATAL_ERROR "This should not be reached!")

View File

@@ -0,0 +1 @@
1

View File

@@ -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='\.$

View File

@@ -0,0 +1 @@
message(FATAL_ERROR "This should not be reached!")

View File

@@ -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)