VS: Find the MSBuild value for VCTargetsPath

Run MSBuild on a simple `.vcxproj` file to extract the location of the
toolset definitions.  This will later be useful for looking at available
BuildCustomizations.
This commit is contained in:
Brad King 2017-02-08 16:28:39 -05:00
parent 0a312e2271
commit 83bf980c96
2 changed files with 215 additions and 0 deletions

View File

@ -15,10 +15,15 @@
#include "cmVS10MASMFlagTable.h"
#include "cmVS10NASMFlagTable.h"
#include "cmVS10RCFlagTable.h"
#include "cmVersion.h"
#include "cmVisualStudioSlnData.h"
#include "cmVisualStudioSlnParser.h"
#include "cmXMLWriter.h"
#include "cmake.h"
#include <cmsys/FStream.hxx>
#include <cmsys/RegularExpression.hxx>
static const char vs10generatorName[] = "Visual Studio 10 2010";
// Map generator name without year to name with year.
@ -170,6 +175,11 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
if (!this->ParseGeneratorToolset(ts, mf)) {
return false;
}
if (!this->FindVCTargetsPath(mf)) {
return false;
}
if (const char* toolset = this->GetPlatformToolset()) {
mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
}
@ -507,6 +517,208 @@ std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
}
bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
{
// Skip this in special cases within our own test suite.
if (this->GetPlatformName() == "Test Platform" ||
this->GetPlatformToolsetString() == "Test Toolset") {
return true;
}
std::string wd;
if (!this->ConfiguredFilesPath.empty()) {
// In a try-compile we are given the outer CMakeFiles directory.
wd = this->ConfiguredFilesPath;
} else {
wd = this->GetCMakeInstance()->GetHomeOutputDirectory();
wd += cmake::GetCMakeFilesDirectory();
}
wd += "/";
wd += cmVersion::GetCMakeVersion();
// We record the result persistently in a file.
std::string const txt = wd + "/VCTargetsPath.txt";
// If we have a recorded result, use it.
{
cmsys::ifstream fin(txt.c_str());
if (fin && cmSystemTools::GetLineFromStream(fin, this->VCTargetsPath) &&
cmSystemTools::FileIsDirectory(this->VCTargetsPath)) {
cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
return true;
}
}
// Prepare the work directory.
if (!cmSystemTools::MakeDirectory(wd)) {
std::string e = "Failed to make directory:\n " + wd;
mf->IssueMessage(cmake::FATAL_ERROR, e.c_str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
// Generate a project file for MSBuild to tell us the VCTargetsPath value.
std::string const vcxproj = "VCTargetsPath.vcxproj";
{
std::string const vcxprojAbs = wd + "/" + vcxproj;
cmsys::ofstream fout(vcxprojAbs.c_str());
cmXMLWriter xw(fout);
/* clang-format off */
xw.StartDocument();
xw.StartElement("Project");
xw.Attribute("DefaultTargets", "Build");
xw.Attribute("ToolsVersion", "4.0");
xw.Attribute("xmlns",
"http://schemas.microsoft.com/developer/msbuild/2003");
if (this->IsNsightTegra()) {
xw.StartElement("PropertyGroup");
xw.Attribute("Label", "NsightTegraProject");
xw.StartElement("NsightTegraProjectRevisionNumber");
xw.Content("6");
xw.EndElement(); // NsightTegraProjectRevisionNumber
xw.EndElement(); // PropertyGroup
}
xw.StartElement("ItemGroup");
xw.Attribute("Label", "ProjectConfigurations");
xw.StartElement("ProjectConfiguration");
xw.Attribute("Include", "Debug|" + this->GetPlatformName());
xw.StartElement("Configuration");
xw.Content("Debug");
xw.EndElement(); // Configuration
xw.StartElement("Platform");
xw.Content(this->GetPlatformName());
xw.EndElement(); // Platform
xw.EndElement(); // ProjectConfiguration
xw.EndElement(); // ItemGroup
xw.StartElement("PropertyGroup");
xw.Attribute("Label", "Globals");
xw.StartElement("ProjectGUID");
xw.Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}");
xw.EndElement(); // ProjectGUID
xw.StartElement("Keyword");
xw.Content("Win32Proj");
xw.EndElement(); // Keyword
xw.StartElement("Platform");
xw.Content(this->GetPlatformName());
xw.EndElement(); // Platform
if (this->GetSystemName() == "WindowsPhone") {
xw.StartElement("ApplicationType");
xw.Content("Windows Phone");
xw.EndElement(); // ApplicationType
xw.StartElement("ApplicationTypeRevision");
xw.Content(this->GetSystemVersion());
xw.EndElement(); // ApplicationTypeRevision
} else if (this->GetSystemName() == "WindowsStore") {
xw.StartElement("ApplicationType");
xw.Content("Windows Store");
xw.EndElement(); // ApplicationType
xw.StartElement("ApplicationTypeRevision");
xw.Content(this->GetSystemVersion());
xw.EndElement(); // ApplicationTypeRevision
}
if (!this->WindowsTargetPlatformVersion.empty()) {
xw.StartElement("WindowsTargetPlatformVersion");
xw.Content(this->WindowsTargetPlatformVersion);
xw.EndElement(); // WindowsTargetPlatformVersion
}
if (this->GetPlatformName() == "ARM") {
xw.StartElement("WindowsSDKDesktopARMSupport");
xw.Content("true");
xw.EndElement(); // WindowsSDKDesktopARMSupport
}
xw.EndElement(); // PropertyGroup
xw.StartElement("Import");
xw.Attribute("Project",
"$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
xw.EndElement(); // Import
if (!this->GeneratorToolsetHostArchitecture.empty()) {
xw.StartElement("PropertyGroup");
xw.StartElement("PreferredToolArchitecture");
xw.Content(this->GeneratorToolsetHostArchitecture);
xw.EndElement(); // PreferredToolArchitecture
xw.EndElement(); // PropertyGroup
}
xw.StartElement("PropertyGroup");
xw.Attribute("Label", "Configuration");
xw.StartElement("ConfigurationType");
if (this->IsNsightTegra()) {
// Tegra-Android platform does not understand "Utility".
xw.Content("StaticLibrary");
} else {
xw.Content("Utility");
}
xw.EndElement(); // ConfigurationType
xw.StartElement("CharacterSet");
xw.Content("MultiByte");
xw.EndElement(); // CharacterSet
if (this->IsNsightTegra()) {
xw.StartElement("NdkToolchainVersion");
xw.Content(this->GetPlatformToolsetString());
xw.EndElement(); // NdkToolchainVersion
} else {
xw.StartElement("PlatformToolset");
xw.Content(this->GetPlatformToolsetString());
xw.EndElement(); // PlatformToolset
}
xw.EndElement(); // PropertyGroup
xw.StartElement("Import");
xw.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
xw.EndElement(); // Import
xw.StartElement("ItemDefinitionGroup");
xw.StartElement("PostBuildEvent");
xw.StartElement("Command");
xw.Content("echo VCTargetsPath=$(VCTargetsPath)");
xw.EndElement(); // Command
xw.EndElement(); // PostBuildEvent
xw.EndElement(); // ItemDefinitionGroup
xw.StartElement("Import");
xw.Attribute("Project",
"$(VCTargetsPath)\\Microsoft.Cpp.targets");
xw.EndElement(); // Import
xw.EndElement(); // Project
xw.EndDocument();
/* clang-format on */
}
std::vector<std::string> cmd;
cmd.push_back(this->GetMSBuildCommand());
cmd.push_back(vcxproj);
cmd.push_back(std::string("/p:VisualStudioVersion=") +
this->GetIDEVersion());
std::string out;
int ret = 0;
cmsys::RegularExpression regex("\n *VCTargetsPath=([^%\r\n]+)[\r\n]");
if (!cmSystemTools::RunSingleCommand(cmd, &out, &out, &ret, wd.c_str(),
cmSystemTools::OUTPUT_NONE) ||
ret != 0 || !regex.find(out)) {
cmSystemTools::ReplaceString(out, "\n", "\n ");
std::ostringstream e;
/* clang-format off */
e <<
"Failed to run MSBuild command:\n"
" " << cmd[0] << "\n"
"to get the value of VCTargetsPath:\n"
" " << out << "\n"
;
/* clang-format on */
if (ret != 0) {
e << "Exit code: " << ret << "\n";
}
mf->IssueMessage(cmake::FATAL_ERROR, e.str().c_str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
this->VCTargetsPath = regex.match(1);
cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
{
cmsys::ofstream fout(txt.c_str());
fout << this->VCTargetsPath << "\n";
}
return true;
}
void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& projectDir,

View File

@ -160,6 +160,9 @@ private:
bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
std::string VCTargetsPath;
bool FindVCTargetsPath(cmMakefile* mf);
// We do not use the reload macros for VS >= 10.
virtual std::string GetUserMacrosDirectory() { return ""; }
};