From 83bf980c9601c2e5d6a6247867606539d8a14528 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 8 Feb 2017 16:28:39 -0500 Subject: 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. --- Source/cmGlobalVisualStudio10Generator.cxx | 212 +++++++++++++++++++++++++++++ Source/cmGlobalVisualStudio10Generator.h | 3 + 2 files changed, 215 insertions(+) diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index b1285ac..7f34e93 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -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 +#include + 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 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& makeCommand, const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index c5e4bcd..149dcba 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -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 ""; } }; -- cgit v0.12