Browse Source

VS: Provide an option to use x64 host tools

Visual Studio provides toolchains that are themselves built for 32-bit
or 64-bit host architectures.  By default it uses the 32-bit tools, but
it can be told to prefer the 64-bit tools on 64-bit hosts.  Extend the
`CMAKE_GENERATOR_TOOLSET` specification to provide a way to request
use of the 64-bit host tools.

Closes: #15622
Brad King 9 years ago
parent
commit
d079e71c29

+ 10 - 0
Help/generator/VS_TOOLSET_HOST_ARCH.txt

@@ -0,0 +1,10 @@
+For each toolset that comes with this version of Visual Studio, there are
+variants that are themselves compiled for 32-bit (x86) and 64-bit (x64) hosts
+(independent of the architecture they target).  By default Visual Studio
+chooses the 32-bit variant even on a 64-bit host.  One may request use of the
+64-bit host tools by adding ``host=x64`` to the toolset specification:
+
+``host=x64``
+  Select the 64-bit variant of the default toolset.
+``<toolset>,host=x64``
+  Select the 64-bit variant of the ``<toolset>`` toolset.

+ 2 - 0
Help/generator/Visual Studio 12 2013.rst

@@ -24,3 +24,5 @@ Toolset Selection
 The ``v120`` toolset that comes with Visual Studio 12 2013 is selected by
 default.  The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
 via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. include:: VS_TOOLSET_HOST_ARCH.txt

+ 2 - 0
Help/generator/Visual Studio 14 2015.rst

@@ -21,3 +21,5 @@ Toolset Selection
 The ``v140`` toolset that comes with Visual Studio 14 2015 is selected by
 default.  The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
 via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. include:: VS_TOOLSET_HOST_ARCH.txt

+ 2 - 0
Help/generator/Visual Studio 15.rst

@@ -21,3 +21,5 @@ Toolset Selection
 The ``v141`` toolset that comes with Visual Studio 15 is selected by
 default.  The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
 via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
+
+.. include:: VS_TOOLSET_HOST_ARCH.txt

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -82,6 +82,7 @@ Variables that Provide Information
    /variable/CMAKE_VS_NsightTegra_VERSION
    /variable/CMAKE_VS_PLATFORM_NAME
    /variable/CMAKE_VS_PLATFORM_TOOLSET
+   /variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
    /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
    /variable/CMAKE_XCODE_PLATFORM_TOOLSET
    /variable/PROJECT_BINARY_DIR

+ 7 - 0
Help/release/dev/vs-host-x64-tools.rst

@@ -0,0 +1,7 @@
+vs-host-x64-tools
+-----------------
+
+* The :ref:`Visual Studio Generators` for VS 2013 and above learned to
+  support a ``host=x64`` option in the :variable:`CMAKE_GENERATOR_TOOLSET`
+  value (e.g.  via the :manual:`cmake(1)` ``-T`` option) to request use
+  of a VS 64-bit toolchain on 64-bit hosts.

+ 10 - 0
Help/variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE.rst

@@ -0,0 +1,10 @@
+CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
+-------------------------------------------
+
+Visual Studio preferred tool architecture.
+
+The :ref:`Visual Studio Generators` for VS 2013 and above support optional
+selection of a 64-bit toolchain on 64-bit hosts by specifying a ``host=64``
+value in the :variable:`CMAKE_GENERATOR_TOOLSET` option.  CMake provides
+the selected toolchain architecture preference in this variable (either
+``x64`` or empty).

+ 5 - 0
Modules/CMakeDetermineCompilerId.cmake

@@ -182,6 +182,11 @@ Id flags: ${testflags}
     else()
       set(id_toolset "")
     endif()
+    if(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE)
+      set(id_PreferredToolArchitecture "<PreferredToolArchitecture>${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}</PreferredToolArchitecture>")
+    else()
+      set(id_PreferredToolArchitecture "")
+    endif()
     if(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone")
       set(id_system "<ApplicationType>Windows Phone</ApplicationType>")
     elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")

+ 3 - 0
Modules/CompilerId/VS-10.vcxproj.in

@@ -16,6 +16,9 @@
     @id_WindowsSDKDesktopARMSupport@
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup>
+    @id_PreferredToolArchitecture@
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@id_platform@'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     @id_toolset@

+ 36 - 1
Source/cmGlobalVisualStudio10Generator.cxx

@@ -145,10 +145,36 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
     return false;
   }
 
-  this->GeneratorToolset = ts;
+  if (!this->ParseGeneratorToolset(ts, mf)) {
+    return false;
+  }
   if (const char* toolset = this->GetPlatformToolset()) {
     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
   }
+  if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
+    mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE", hostArch);
+  }
+  return true;
+}
+
+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;
+  }
+
+  this->GeneratorToolset = ts;
   return true;
 }
 
@@ -322,6 +348,15 @@ const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
   return 0;
 }
 
+const char*
+cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
+{
+  if (!this->GeneratorToolsetHostArchitecture.empty()) {
+    return this->GeneratorToolsetHostArchitecture.c_str();
+  }
+  return CM_NULLPTR;
+}
+
 void cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
 {
   this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf);

+ 5 - 0
Source/cmGlobalVisualStudio10Generator.h

@@ -22,6 +22,7 @@ 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,
@@ -48,6 +49,9 @@ public:
   /** The toolset name for the target platform.  */
   const char* GetPlatformToolset() const;
 
+  /** The toolset host architecture name (e.g. x64 for 64-bit host tools).  */
+  const char* GetPlatformToolsetHostArchitecture() const;
+
   /** Return the CMAKE_SYSTEM_NAME.  */
   std::string const& GetSystemName() const { return this->SystemName; }
 
@@ -101,6 +105,7 @@ protected:
   std::string const& GetMSBuildCommand();
 
   std::string GeneratorToolset;
+  std::string GeneratorToolsetHostArchitecture;
   std::string DefaultPlatformToolset;
   std::string WindowsTargetPlatformVersion;
   std::string SystemName;

+ 15 - 0
Source/cmGlobalVisualStudio12Generator.cxx

@@ -96,6 +96,21 @@ bool cmGlobalVisualStudio12Generator::MatchesGeneratorName(
   return false;
 }
 
+bool cmGlobalVisualStudio12Generator::ParseGeneratorToolset(
+  std::string const& ts, cmMakefile* mf)
+{
+  std::string::size_type ts_end = ts.size();
+  if (cmHasLiteralSuffix(ts, ",host=x64")) {
+    this->GeneratorToolsetHostArchitecture = "x64";
+    ts_end -= 9;
+  } else if (ts == "host=x64") {
+    this->GeneratorToolsetHostArchitecture = "x64";
+    ts_end = 0;
+  }
+  return this->cmGlobalVisualStudio11Generator::ParseGeneratorToolset(
+    ts.substr(0, ts_end), mf);
+}
+
 bool cmGlobalVisualStudio12Generator::InitializeWindowsPhone(cmMakefile* mf)
 {
   if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) {

+ 3 - 0
Source/cmGlobalVisualStudio12Generator.h

@@ -22,6 +22,9 @@ public:
   // version number
   virtual const char* GetToolsVersion() { return "12.0"; }
 protected:
+  bool ParseGeneratorToolset(std::string const& ts,
+                             cmMakefile* mf) CM_OVERRIDE;
+
   virtual bool InitializeWindowsPhone(cmMakefile* mf);
   virtual bool InitializeWindowsStore(cmMakefile* mf);
   virtual bool SelectWindowsPhoneToolset(std::string& toolset) const;

+ 13 - 0
Source/cmGlobalXCodeGenerator.cxx

@@ -220,6 +220,19 @@ bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
                                                  cmMakefile* mf)
 {
   if (this->XcodeVersion >= 30) {
+    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;
+    }
     this->GeneratorToolset = ts;
     if (!this->GeneratorToolset.empty()) {
       mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET",

+ 9 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -322,6 +322,15 @@ void cmVisualStudio10TargetGenerator::Generate()
     this->WriteString("</PropertyGroup>\n", 1);
   }
 
+  if (const char* hostArch =
+        this->GlobalGenerator->GetPlatformToolsetHostArchitecture()) {
+    this->WriteString("<PropertyGroup>\n", 1);
+    this->WriteString("<PreferredToolArchitecture>", 2);
+    (*this->BuildFileStream) << cmVS10EscapeXML(hostArch)
+                             << "</PreferredToolArchitecture>\n";
+    this->WriteString("</PropertyGroup>\n", 1);
+  }
+
   this->WriteProjectConfigurations();
   this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1);
   this->WriteString("<ProjectGUID>", 2);

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetHostArch-result.txt

@@ -0,0 +1 @@
+1

+ 10 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetHostArch-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    .*
+
+  does not recognize the toolset
+
+    Test Toolset,host=x6[45]
+
+  that was specified\.$

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetHostArch.cmake

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

+ 15 - 0
Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake

@@ -6,6 +6,21 @@ run_cmake(NoToolset)
 if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[01245]|Xcode" AND NOT XCODE_BELOW_3)
   set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
   run_cmake(TestToolset)
+  if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[245]")
+    set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64")
+    run_cmake(TestToolsetHostArchBoth)
+    set(RunCMake_GENERATOR_TOOLSET ",host=x64")
+    run_cmake(TestToolsetHostArchOnly)
+    set(RunCMake_GENERATOR_TOOLSET "host=x64")
+    run_cmake(TestToolsetHostArchOnly)
+    set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
+    run_cmake(TestToolsetHostArchNone)
+    set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x65")
+    run_cmake(BadToolsetHostArch)
+  else()
+    set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64")
+    run_cmake(BadToolsetHostArch)
+  endif()
 else()
   set(RunCMake_GENERATOR_TOOLSET "Bad Toolset")
   run_cmake(BadToolset)

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetHostArchBoth-stdout.txt

@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='Test Toolset'
+-- CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE='x64'

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetHostArchBoth.cmake

@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE='${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}'")

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetHostArchNone-stdout.txt

@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='Test Toolset'
+-- CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE=''

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetHostArchNone.cmake

@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE='${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}'")

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetHostArchOnly-stdout.txt

@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='v[0-9]+'
+-- CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE='x64'

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetHostArchOnly.cmake

@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE='${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}'")