VS: Refactor generator toolset parsing

We parse `CMAKE_GENERATOR_TOOLSET` values of the forms:

* `toolset`
* `toolset,host=x64`
* `host=x64`

Generalize the parsing to support the forms:

* `toolset`
* `toolset[,key=value]*`
* `key=value[,key=value]*`

Disallow duplicate keys.  Require all but the first field to
be of `key=value` form.
This commit is contained in:
Brad King 2017-02-08 15:25:23 -05:00
parent d9e2b9a909
commit f773933f26
12 changed files with 112 additions and 28 deletions

View File

@ -182,24 +182,80 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
std::string const& ts, cmMakefile* mf)
{
if (ts.find_first_of(",=") != ts.npos) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"does not recognize the toolset\n"
" " << ts << "\n"
"that was specified.";
/* clang-format on */
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
return false;
std::vector<std::string> const fields = cmSystemTools::tokenize(ts, ",");
std::vector<std::string>::const_iterator fi = fields.begin();
if (fi == fields.end()) {
return true;
}
// The first field may be the VS platform toolset.
if (fi->find('=') == fi->npos) {
this->GeneratorToolset = *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 toolset specification\n"
" " << ts << "\n"
"that contains a field after the first ',' with no '='."
;
/* clang-format on */
mf->IssueMessage(cmake::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 toolset specification\n"
" " << ts << "\n"
"that contains duplicate field key '" << key << "'."
;
/* clang-format on */
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
return false;
}
if (!this->ProcessGeneratorToolsetField(key, value)) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"given toolset specification\n"
" " << ts << "\n"
"that contains invalid field '" << *fi << "'."
;
/* clang-format on */
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
return false;
}
}
this->GeneratorToolset = ts;
return true;
}
bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
std::string const& key, std::string const& value)
{
static_cast<void>(key);
static_cast<void>(value);
return false;
}
bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf)
{
if (this->SystemName == "Windows") {

View File

@ -23,7 +23,6 @@ public:
virtual bool SetSystemName(std::string const& s, cmMakefile* mf);
virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf);
virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf);
virtual bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
virtual void GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
@ -106,6 +105,9 @@ protected:
virtual bool InitializeWindowsPhone(cmMakefile* mf);
virtual bool InitializeWindowsStore(cmMakefile* mf);
virtual bool ProcessGeneratorToolsetField(std::string const& key,
std::string const& value);
virtual std::string SelectWindowsCEToolset() const;
virtual bool SelectWindowsPhoneToolset(std::string& toolset) const;
virtual bool SelectWindowsStoreToolset(std::string& toolset) const;
@ -156,6 +158,8 @@ private:
virtual std::string FindDevEnvCommand();
virtual std::string GetVSMakeProgram() { return this->GetMSBuildCommand(); }
bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
// We do not use the reload macros for VS >= 10.
virtual std::string GetUserMacrosDirectory() { return ""; }
};

View File

@ -109,19 +109,15 @@ bool cmGlobalVisualStudio12Generator::MatchesGeneratorName(
return false;
}
bool cmGlobalVisualStudio12Generator::ParseGeneratorToolset(
std::string const& ts, cmMakefile* mf)
bool cmGlobalVisualStudio12Generator::ProcessGeneratorToolsetField(
std::string const& key, std::string const& value)
{
std::string::size_type ts_end = ts.size();
if (cmHasLiteralSuffix(ts, ",host=x64")) {
if (key == "host" && value == "x64") {
this->GeneratorToolsetHostArchitecture = "x64";
ts_end -= 9;
} else if (ts == "host=x64") {
this->GeneratorToolsetHostArchitecture = "x64";
ts_end = 0;
return true;
}
return this->cmGlobalVisualStudio11Generator::ParseGeneratorToolset(
ts.substr(0, ts_end), mf);
return this->cmGlobalVisualStudio11Generator::ProcessGeneratorToolsetField(
key, value);
}
bool cmGlobalVisualStudio12Generator::InitializeWindowsPhone(cmMakefile* mf)

View File

@ -31,8 +31,8 @@ public:
// version number
virtual const char* GetToolsVersion() { return "12.0"; }
protected:
bool ParseGeneratorToolset(std::string const& ts,
cmMakefile* mf) CM_OVERRIDE;
bool ProcessGeneratorToolsetField(std::string const& key,
std::string const& value) CM_OVERRIDE;
virtual bool InitializeWindowsPhone(cmMakefile* mf);
virtual bool InitializeWindowsStore(cmMakefile* mf);

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,10 @@
CMake Error at CMakeLists.txt:[0-9]+ \(project\):
Generator
.*
given toolset specification
Test Toolset,not_a_key
that contains a field after the first ',' with no '='\.$

View File

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

View File

@ -3,8 +3,8 @@ CMake Error at CMakeLists.txt:[0-9]+ \(project\):
.*
does not recognize the toolset
given toolset specification
Test Toolset,host=x6[45]
that was specified\.$
that contains invalid field 'host=x6[45]'\.$

View File

@ -0,0 +1,10 @@
CMake Error at CMakeLists.txt:[0-9]+ \(project\):
Generator
.*
given toolset specification
Test Toolset,host=x64,host=x64
that contains duplicate field key 'host'\.$

View File

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

View File

@ -17,10 +17,14 @@ if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[01245]")
run_cmake(TestToolsetHostArchNone)
set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x65")
run_cmake(BadToolsetHostArch)
set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64,host=x64")
run_cmake(BadToolsetHostArchTwice)
else()
set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64")
run_cmake(BadToolsetHostArch)
endif()
set(RunCMake_GENERATOR_TOOLSET "Test Toolset,not_a_key")
run_cmake(BadToolsetFormat)
elseif("${RunCMake_GENERATOR}" STREQUAL "Xcode" AND NOT XCODE_BELOW_3)
set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
run_cmake(TestToolset)