diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 2606ba063f..e4ee7255b6 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -84,6 +84,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_CUDA
/variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
/variable/CMAKE_XCODE_PLATFORM_TOOLSET
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst
new file mode 100644
index 0000000000..1604a76675
--- /dev/null
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst
@@ -0,0 +1,12 @@
+CMAKE_VS_PLATFORM_TOOLSET_CUDA
+------------------------------
+
+NVIDIA CUDA Toolkit version whose Visual Studio toolset to use.
+
+The :ref:`Visual Studio Generators` for VS 2010 and above support using
+a CUDA toolset provided by a CUDA Toolkit. The toolset version number
+may be specified by a field in :variable:`CMAKE_GENERATOR_TOOLSET` of
+the form ``cuda=8.0``. If none is specified CMake will choose a default
+version. CMake provides the selected CUDA toolset version in this variable.
+The value may be empty if no CUDA Toolkit with Visual Studio integration
+is installed.
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index 375e2307de..55a6f0ceb5 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -5,36 +5,40 @@ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
include(${CMAKE_ROOT}/Modules//CMakeParseImplicitLinkInfo.cmake)
if( NOT ( ("${CMAKE_GENERATOR}" MATCHES "Make") OR
- ("${CMAKE_GENERATOR}" MATCHES "Ninja") ) )
+ ("${CMAKE_GENERATOR}" MATCHES "Ninja") OR
+ ("${CMAKE_GENERATOR}" MATCHES "Visual Studio (1|[7-9][0-9])") ) )
message(FATAL_ERROR "CUDA language not currently supported by \"${CMAKE_GENERATOR}\" generator")
endif()
-if(NOT CMAKE_CUDA_COMPILER)
- set(CMAKE_CUDA_COMPILER_INIT NOTFOUND)
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+else()
+ if(NOT CMAKE_CUDA_COMPILER)
+ set(CMAKE_CUDA_COMPILER_INIT NOTFOUND)
- # prefer the environment variable CUDACXX
- if(NOT $ENV{CUDACXX} STREQUAL "")
- get_filename_component(CMAKE_CUDA_COMPILER_INIT $ENV{CUDACXX} PROGRAM PROGRAM_ARGS CMAKE_CUDA_FLAGS_ENV_INIT)
- if(CMAKE_CUDA_FLAGS_ENV_INIT)
- set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "First argument to CXX compiler")
- endif()
- if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT})
- message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}")
+ # prefer the environment variable CUDACXX
+ if(NOT $ENV{CUDACXX} STREQUAL "")
+ get_filename_component(CMAKE_CUDA_COMPILER_INIT $ENV{CUDACXX} PROGRAM PROGRAM_ARGS CMAKE_CUDA_FLAGS_ENV_INIT)
+ if(CMAKE_CUDA_FLAGS_ENV_INIT)
+ set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "First argument to CXX compiler")
+ endif()
+ if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT})
+ message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}")
+ endif()
endif()
+
+ # finally list compilers to try
+ if(NOT CMAKE_CUDA_COMPILER_INIT)
+ set(CMAKE_CUDA_COMPILER_LIST nvcc)
endif()
- # finally list compilers to try
- if(NOT CMAKE_CUDA_COMPILER_INIT)
- set(CMAKE_CUDA_COMPILER_LIST nvcc)
+ _cmake_find_compiler(CUDA)
+ else()
+ _cmake_find_compiler_path(CUDA)
endif()
- _cmake_find_compiler(CUDA)
-else()
- _cmake_find_compiler_path(CUDA)
+ mark_as_advanced(CMAKE_CUDA_COMPILER)
endif()
-mark_as_advanced(CMAKE_CUDA_COMPILER)
-
#Allow the user to specify a host compiler
set(CMAKE_CUDA_HOST_COMPILER "" CACHE FILEPATH "Host compiler to be used by nvcc")
if(NOT $ENV{CUDAHOSTCXX} STREQUAL "")
@@ -75,7 +79,12 @@ if(MSVC_CUDA_ARCHITECTURE_ID)
"set(MSVC_CUDA_ARCHITECTURE_ID ${MSVC_CUDA_ARCHITECTURE_ID})")
endif()
-if(CMAKE_CUDA_COMPILER_ID STREQUAL NVIDIA)
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+ set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_LINKER}")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "")
+ set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
+elseif(CMAKE_CUDA_COMPILER_ID STREQUAL NVIDIA)
set(_nvcc_log "")
string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
if(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n")
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index ae485bfbbd..6fce8e2072 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -235,6 +235,26 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
endif()
set(id_dir ${CMAKE_${lang}_COMPILER_ID_DIR})
set(id_src "${src}")
+ set(id_compile "ClCompile")
+ set(id_PostBuildEvent_Command "for %%i in (${id_cl}) do %40echo CMAKE_${lang}_COMPILER=%%~$PATH:i")
+ set(id_Import_props "")
+ set(id_Import_targets "")
+ set(id_ItemDefinitionGroup_entry "")
+ set(id_Link_AdditionalDependencies "")
+ if(lang STREQUAL CUDA)
+ if(NOT CMAKE_VS_PLATFORM_TOOLSET_CUDA)
+ message(FATAL_ERROR "No CUDA toolset found.")
+ endif()
+ set(cuda_tools "CUDA ${CMAKE_VS_PLATFORM_TOOLSET_CUDA}")
+ set(id_compile "CudaCompile")
+ set(id_PostBuildEvent_Command [[echo CMAKE_CUDA_COMPILER=$(CudaToolkitBinDir)\nvcc.exe]])
+ string(CONCAT id_Import_props [[]])
+ string(CONCAT id_Import_targets [[]])
+ if(CMAKE_VS_PLATFORM_NAME STREQUAL x64)
+ set(id_ItemDefinitionGroup_entry "64")
+ endif()
+ set(id_Link_AdditionalDependencies "cudart.lib")
+ endif()
configure_file(${CMAKE_ROOT}/Modules/CompilerId/VS-${v}.${ext}.in
${id_dir}/CompilerId${lang}.${ext} @ONLY)
if(CMAKE_VS_MSBUILD_COMMAND AND NOT lang STREQUAL "Fortran")
diff --git a/Modules/CompilerId/VS-10.vcxproj.in b/Modules/CompilerId/VS-10.vcxproj.in
index 50be9cbccc..6b9b361cc0 100644
--- a/Modules/CompilerId/VS-10.vcxproj.in
+++ b/Modules/CompilerId/VS-10.vcxproj.in
@@ -25,6 +25,9 @@
MultiByte
+
+ @id_Import_props@
+
<_ProjectFileVersion>10.0.30319.1
.\
@@ -44,16 +47,21 @@
+ @id_ItemDefinitionGroup_entry@
false
Console
+ @id_Link_AdditionalDependencies@
- for %%i in (@id_cl@) do %40echo CMAKE_@id_lang@_COMPILER=%%~$PATH:i
+ @id_PostBuildEvent_Command@
-
+ <@id_compile@ Include="@id_src@" />
+
+ @id_Import_targets@
+
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index b1285acc82..ca98e6c920 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -10,15 +10,25 @@
#include "cmSourceFile.h"
#include "cmVS10CLFlagTable.h"
#include "cmVS10CSharpFlagTable.h"
+#include "cmVS10CudaFlagTable.h"
+#include "cmVS10CudaHostFlagTable.h"
#include "cmVS10LibFlagTable.h"
#include "cmVS10LinkFlagTable.h"
#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
+#include
+
+#include
+
static const char vs10generatorName[] = "Visual Studio 10 2010";
// Map generator name without year to name with year.
@@ -95,6 +105,7 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;"
"ProductDir",
vc10Express, cmSystemTools::KeyWOW64_32);
+ this->CudaEnabled = false;
this->SystemIsWindowsCE = false;
this->SystemIsWindowsPhone = false;
this->SystemIsWindowsStore = false;
@@ -113,6 +124,8 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
this->DefaultCSharpFlagTable = cmVS10CSharpFlagTable;
this->DefaultLibFlagTable = cmVS10LibFlagTable;
this->DefaultLinkFlagTable = cmVS10LinkFlagTable;
+ this->DefaultCudaFlagTable = cmVS10CudaFlagTable;
+ this->DefaultCudaHostFlagTable = cmVS10CudaHostFlagTable;
this->DefaultMasmFlagTable = cmVS10MASMFlagTable;
this->DefaultNasmFlagTable = cmVS10NASMFlagTable;
this->DefaultRcFlagTable = cmVS10RCFlagTable;
@@ -155,6 +168,13 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorPlatform(
return true;
}
+static void cmCudaToolVersion(std::string& s)
+{
+ // "CUDA x.y.props" => "x.y"
+ s = s.substr(5);
+ s = s.substr(0, s.size() - 6);
+}
+
bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
std::string const& ts, cmMakefile* mf)
{
@@ -170,12 +190,37 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
if (!this->ParseGeneratorToolset(ts, mf)) {
return false;
}
+
+ if (!this->FindVCTargetsPath(mf)) {
+ return false;
+ }
+
+ if (this->GeneratorToolsetCuda.empty()) {
+ // Find the highest available version of the CUDA tools.
+ std::vector cudaTools;
+ std::string const bcDir = this->VCTargetsPath + "/BuildCustomizations";
+ cmsys::Glob gl;
+ gl.SetRelative(bcDir.c_str());
+ if (gl.FindFiles(bcDir + "/CUDA *.props")) {
+ cudaTools = gl.GetFiles();
+ }
+ if (!cudaTools.empty()) {
+ std::for_each(cudaTools.begin(), cudaTools.end(), cmCudaToolVersion);
+ std::sort(cudaTools.begin(), cudaTools.end(),
+ cmSystemTools::VersionCompareGreater);
+ this->GeneratorToolsetCuda = cudaTools.at(0);
+ }
+ }
+
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);
}
+ if (const char* cuda = this->GetPlatformToolsetCuda()) {
+ mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA", cuda);
+ }
return true;
}
@@ -251,8 +296,10 @@ bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
std::string const& key, std::string const& value)
{
- static_cast(key);
- static_cast(value);
+ if (key == "cuda") {
+ this->GeneratorToolsetCuda = value;
+ return true;
+ }
return false;
}
@@ -417,6 +464,9 @@ void cmGlobalVisualStudio10Generator::EnableLanguage(
if (*it == "ASM_NASM") {
this->NasmEnabled = true;
}
+ if (*it == "CUDA") {
+ this->CudaEnabled = true;
+ }
}
this->AddPlatformDefinitions(mf);
cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
@@ -453,6 +503,20 @@ cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
return CM_NULLPTR;
}
+const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCuda() const
+{
+ if (!this->GeneratorToolsetCuda.empty()) {
+ return this->GeneratorToolsetCuda.c_str();
+ }
+ return CM_NULLPTR;
+}
+
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaString() const
+{
+ return this->GeneratorToolsetCuda;
+}
+
bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
{
if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {
@@ -507,6 +571,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,
@@ -721,6 +987,17 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLinkFlagTable() const
return (table != CM_NULLPTR) ? table : this->DefaultLinkFlagTable;
}
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaFlagTable() const
+{
+ return this->DefaultCudaFlagTable;
+}
+
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
+ const
+{
+ return this->DefaultCudaHostFlagTable;
+}
+
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
{
cmIDEFlagTable const* table = this->ToolsetOptions.GetMasmFlagTable(
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index c5e4bcdc6a..20f992af39 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -42,6 +42,8 @@ public:
cmMakefile*, bool optional);
virtual void WriteSLNHeader(std::ostream& fout);
+ bool IsCudaEnabled() const { return this->CudaEnabled; }
+
/** Generating for Nsight Tegra VS plugin? */
bool IsNsightTegra() const;
std::string GetNsightTegraVersion() const;
@@ -53,6 +55,10 @@ public:
/** The toolset host architecture name (e.g. x64 for 64-bit host tools). */
const char* GetPlatformToolsetHostArchitecture() const;
+ /** The cuda toolset version. */
+ const char* GetPlatformToolsetCuda() const;
+ std::string const& GetPlatformToolsetCudaString() const;
+
/** Return the CMAKE_SYSTEM_NAME. */
std::string const& GetSystemName() const { return this->SystemName; }
@@ -94,6 +100,8 @@ public:
cmIDEFlagTable const* GetRcFlagTable() const;
cmIDEFlagTable const* GetLibFlagTable() const;
cmIDEFlagTable const* GetLinkFlagTable() const;
+ cmIDEFlagTable const* GetCudaFlagTable() const;
+ cmIDEFlagTable const* GetCudaHostFlagTable() const;
cmIDEFlagTable const* GetMasmFlagTable() const;
cmIDEFlagTable const* GetNasmFlagTable() const;
@@ -118,6 +126,7 @@ protected:
std::string GeneratorToolset;
std::string GeneratorToolsetHostArchitecture;
+ std::string GeneratorToolsetCuda;
std::string DefaultPlatformToolset;
std::string WindowsTargetPlatformVersion;
std::string SystemName;
@@ -127,6 +136,8 @@ protected:
cmIDEFlagTable const* DefaultCSharpFlagTable;
cmIDEFlagTable const* DefaultLibFlagTable;
cmIDEFlagTable const* DefaultLinkFlagTable;
+ cmIDEFlagTable const* DefaultCudaFlagTable;
+ cmIDEFlagTable const* DefaultCudaHostFlagTable;
cmIDEFlagTable const* DefaultMasmFlagTable;
cmIDEFlagTable const* DefaultNasmFlagTable;
cmIDEFlagTable const* DefaultRcFlagTable;
@@ -160,6 +171,11 @@ private:
bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
+ std::string VCTargetsPath;
+ bool FindVCTargetsPath(cmMakefile* mf);
+
+ bool CudaEnabled;
+
// We do not use the reload macros for VS >= 10.
virtual std::string GetUserMacrosDirectory() { return ""; }
};
diff --git a/Source/cmVS10CudaFlagTable.h b/Source/cmVS10CudaFlagTable.h
new file mode 100644
index 0000000000..da19d649b3
--- /dev/null
+++ b/Source/cmVS10CudaFlagTable.h
@@ -0,0 +1,51 @@
+static cmVS7FlagTable cmVS10CudaFlagTable[] = {
+ // Collect options meant for the host compiler.
+ { "AdditionalCompilerOptions", "Xcompiler=", "Host compiler options", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SpaceAppendable },
+ { "AdditionalCompilerOptions", "Xcompiler", "Host compiler options", "",
+ cmVS7FlagTable::UserFollowing | cmVS7FlagTable::SpaceAppendable },
+
+ // Select the CUDA runtime library.
+ { "CudaRuntime", "cudart=none", "No CUDA runtime library", "None", 0 },
+ { "CudaRuntime", "cudart=shared", "Shared/dynamic CUDA runtime library",
+ "Shared", 0 },
+ { "CudaRuntime", "cudart=static", "Static CUDA runtime library", "Static",
+ 0 },
+ { "CudaRuntime", "cudart", "CUDA runtime library", "",
+ cmVS7FlagTable::UserFollowing },
+
+ // Capture arch/code arguments into temporaries for post-processing.
+ { "cmake-temp-gencode", "gencode=", "", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "cmake-temp-gencode", "gencode", "", "",
+ cmVS7FlagTable::UserFollowing | cmVS7FlagTable::SemicolonAppendable },
+ { "cmake-temp-gencode", "-generate-code=", "", "",
+ cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable },
+ { "cmake-temp-gencode", "-generate-code", "", "",
+ cmVS7FlagTable::UserFollowing | cmVS7FlagTable::SemicolonAppendable },
+
+ { "cmake-temp-code", "code=", "", "", cmVS7FlagTable::UserValue },
+ { "cmake-temp-code", "code", "", "", cmVS7FlagTable::UserFollowing },
+ { "cmake-temp-code", "-gpu-code=", "", "", cmVS7FlagTable::UserValue },
+ { "cmake-temp-code", "-gpu-code", "", "", cmVS7FlagTable::UserFollowing },
+
+ { "cmake-temp-arch", "arch=", "", "", cmVS7FlagTable::UserValue },
+ { "cmake-temp-arch", "arch", "", "", cmVS7FlagTable::UserFollowing },
+ { "cmake-temp-arch", "-gpu-architecture=", "", "",
+ cmVS7FlagTable::UserValue },
+ { "cmake-temp-arch", "-gpu-architecture", "", "",
+ cmVS7FlagTable::UserFollowing },
+
+ // Other flags.
+
+ { "FastMath", "use_fast_math", "", "true", 0 },
+ { "FastMath", "-use_fast_math", "", "true", 0 },
+
+ { "GPUDebugInfo", "G", "", "true", 0 },
+ { "GPUDebugInfo", "-device-debug", "", "true", 0 },
+
+ { "HostDebugInfo", "g", "", "true", 0 },
+ { "HostDebugInfo", "-debug", "", "true", 0 },
+
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVS10CudaHostFlagTable.h b/Source/cmVS10CudaHostFlagTable.h
new file mode 100644
index 0000000000..5b61066caf
--- /dev/null
+++ b/Source/cmVS10CudaHostFlagTable.h
@@ -0,0 +1,35 @@
+static cmVS7FlagTable cmVS10CudaHostFlagTable[] = {
+ //{"Optimization", "", "", "InheritFromHost", 0},
+ { "Optimization", "Od", "Disabled", "Od", 0 },
+ { "Optimization", "O1", "Minimize Size", "O1", 0 },
+ { "Optimization", "O2", "Maximize Speed", "O2", 0 },
+ { "Optimization", "Ox", "Full Optimization", "O3", 0 },
+
+ //{"Runtime", "", "", "InheritFromHost", 0},
+ { "Runtime", "MT", "Multi-Threaded", "MT", 0 },
+ { "Runtime", "MTd", "Multi-Threaded Debug", "MTd", 0 },
+ { "Runtime", "MD", "Multi-Threaded DLL", "MD", 0 },
+ { "Runtime", "MDd", "Multi-threaded Debug DLL", "MDd", 0 },
+ { "Runtime", "ML", "Single-Threaded", "ML", 0 },
+ { "Runtime", "MLd", "Single-Threaded Debug", "MLd", 0 },
+
+ //{"RuntimeChecks", "", "", "InheritFromHost", 0},
+ //{"RuntimeChecks", "", "Default", "Default", 0},
+ { "RuntimeChecks", "RTCs", "Stack Frames", "RTCs", 0 },
+ { "RuntimeChecks", "RTCu", "Uninitialized Variables", "RTCu", 0 },
+ { "RuntimeChecks", "RTC1", "Both", "RTC1", 0 },
+
+ //{"TypeInfo", "", "", "InheritFromHost", 0},
+ { "TypeInfo", "GR", "Yes", "true", 0 },
+ { "TypeInfo", "GR-", "No", "false", 0 },
+
+ //{"Warning", "", "", "InheritFromHost", 0},
+ { "Warning", "W0", "Off: Turn Off All Warnings", "W0", 0 },
+ { "Warning", "W1", "Level 1", "W1", 0 },
+ { "Warning", "W2", "Level 2", "W2", 0 },
+ { "Warning", "W3", "Level 3", "W3", 0 },
+ { "Warning", "W4", "Level 4", "W4", 0 },
+ { "Warning", "Wall", "Enable All Warnings", "Wall", 0 },
+
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 4aea6f8e65..052cc7fcbc 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -112,6 +112,10 @@ cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
i != this->LinkOptions.end(); ++i) {
delete i->second;
}
+ for (OptionsMap::iterator i = this->CudaOptions.begin();
+ i != this->CudaOptions.end(); ++i) {
+ delete i->second;
+ }
if (!this->BuildFileStream) {
return;
}
@@ -206,6 +210,9 @@ void cmVisualStudio10TargetGenerator::Generate()
if (!this->ComputeRcOptions()) {
return;
}
+ if (!this->ComputeCudaOptions()) {
+ return;
+ }
if (!this->ComputeMasmOptions()) {
return;
}
@@ -454,6 +461,14 @@ void cmVisualStudio10TargetGenerator::Generate()
this->WriteString("\n", 1);
}
this->WriteString("\n", 1);
+ if (this->GlobalGenerator->IsCudaEnabled()) {
+ this->WriteString("BuildFileStream)
+ << cmVS10EscapeXML(this->GlobalGenerator->GetPlatformToolsetCudaString())
+ << ".props\" />\n";
+ }
if (this->GlobalGenerator->IsMasmEnabled()) {
this->WriteString("\n",
@@ -524,6 +539,14 @@ void cmVisualStudio10TargetGenerator::Generate()
this->WriteTargetSpecificReferences();
this->WriteString("\n", 1);
this->WriteTargetsFileReferences();
+ if (this->GlobalGenerator->IsCudaEnabled()) {
+ this->WriteString("BuildFileStream)
+ << cmVS10EscapeXML(this->GlobalGenerator->GetPlatformToolsetCudaString())
+ << ".targets\" />\n";
+ }
if (this->GlobalGenerator->IsMasmEnabled()) {
this->WriteString("\n",
@@ -1694,8 +1717,10 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool,
//
// and fail if this exceeds the maximum allowed path length. Our path
// conversion uses full paths when possible to allow deeper trees.
- bool forceRelative = false;
- std::string sourceFile = this->ConvertPath(sf->GetFullPath(), false);
+ // However, CUDA 8.0 msbuild rules fail on absolute paths so for CUDA
+ // we must use relative paths.
+ bool forceRelative = sf->GetLanguage() == "CUDA";
+ std::string sourceFile = this->ConvertPath(sf->GetFullPath(), forceRelative);
if (this->LocalGenerator->GetVersion() ==
cmGlobalVisualStudioGenerator::VS10 &&
cmSystemTools::FileIsFullPath(sourceFile.c_str())) {
@@ -1772,6 +1797,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources()
tool = "ResourceCompile";
} else if (lang == "CSharp") {
tool = "Compile";
+ } else if (lang == "CUDA" && this->GlobalGenerator->IsCudaEnabled()) {
+ tool = "CudaCompile";
}
if (!tool.empty()) {
@@ -2207,8 +2234,10 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
if (linkLanguage == "CXX") {
clOptions.AddFlag("CompileAs", "CompileAsCpp");
}
- this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
- linkLanguage, configName.c_str());
+ if (linkLanguage != "CUDA") {
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
+ linkLanguage, configName.c_str());
+ }
// Get preprocessor definitions for this directory.
std::string defineFlags =
@@ -2400,6 +2429,99 @@ void cmVisualStudio10TargetGenerator::WriteRCOptions(
this->WriteString("\n", 2);
}
+bool cmVisualStudio10TargetGenerator::ComputeCudaOptions()
+{
+ if (!this->GlobalGenerator->IsCudaEnabled()) {
+ return true;
+ }
+ for (std::vector::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i) {
+ if (!this->ComputeCudaOptions(*i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
+ std::string const& configName)
+{
+ cmGlobalVisualStudio10Generator* gg =
+ static_cast(this->GlobalGenerator);
+ CM_AUTO_PTR pOptions(new Options(
+ this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable()));
+ Options& cudaOptions = *pOptions;
+
+ // Get compile flags for CUDA in this directory.
+ std::string CONFIG = cmSystemTools::UpperCase(configName);
+ std::string configFlagsVar = std::string("CMAKE_CUDA_FLAGS_") + CONFIG;
+ std::string flags =
+ std::string(this->Makefile->GetSafeDefinition("CMAKE_CUDA_FLAGS")) +
+ std::string(" ") +
+ std::string(this->Makefile->GetSafeDefinition(configFlagsVar));
+
+ // Get preprocessor definitions for this directory.
+ std::string defineFlags =
+ this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags();
+
+ cudaOptions.Parse(flags.c_str());
+ cudaOptions.Parse(defineFlags.c_str());
+ cudaOptions.ParseFinish();
+
+ if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
+ cudaOptions.AddFlag("GenerateRelocatableDeviceCode", "true");
+ }
+
+ // Convert the host compiler options to the toolset's abstractions
+ // using a secondary flag table.
+ cudaOptions.ClearTables();
+ cudaOptions.AddTable(gg->GetCudaHostFlagTable());
+ cudaOptions.Reparse("AdditionalCompilerOptions");
+
+ // `CUDA 8.0.targets` places these before nvcc! Just drop whatever
+ // did not parse and hope it works.
+ cudaOptions.RemoveFlag("AdditionalCompilerOptions");
+
+ cudaOptions.FixCudaCodeGeneration();
+
+ std::vector targetDefines;
+ this->GeneratorTarget->GetCompileDefinitions(targetDefines,
+ configName.c_str(), "CUDA");
+ cudaOptions.AddDefines(targetDefines);
+
+ // Add a definition for the configuration name.
+ std::string configDefine = "CMAKE_INTDIR=\"";
+ configDefine += configName;
+ configDefine += "\"";
+ cudaOptions.AddDefine(configDefine);
+ if (const char* exportMacro = this->GeneratorTarget->GetExportMacro()) {
+ cudaOptions.AddDefine(exportMacro);
+ }
+
+ this->CudaOptions[configName] = pOptions.release();
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteCudaOptions(
+ std::string const& configName, std::vector const& includes)
+{
+ if (!this->MSTools || !this->GlobalGenerator->IsCudaEnabled()) {
+ return;
+ }
+ this->WriteString("\n", 2);
+
+ Options& cudaOptions = *(this->CudaOptions[configName]);
+ cudaOptions.AppendFlag("Include", includes);
+ cudaOptions.AppendFlag("Include", "%(Include)");
+ cudaOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
+ "\n", "CUDA");
+ cudaOptions.PrependInheritedString("AdditionalOptions");
+ cudaOptions.OutputFlagMap(*this->BuildFileStream, " ");
+
+ this->WriteString("\n", 2);
+}
+
bool cmVisualStudio10TargetGenerator::ComputeMasmOptions()
{
if (!this->GlobalGenerator->IsMasmEnabled()) {
@@ -2738,8 +2860,10 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
this->LocalGenerator, Options::Linker, gg->GetLinkFlagTable(), 0, this));
Options& linkOptions = *pOptions;
- const std::string& linkLanguage =
- this->GeneratorTarget->GetLinkerLanguage(config.c_str());
+ cmGeneratorTarget::LinkClosure const* linkClosure =
+ this->GeneratorTarget->GetLinkClosure(config);
+
+ const std::string& linkLanguage = linkClosure->LinkerLanguage;
if (linkLanguage.empty()) {
cmSystemTools::Error(
"CMake can not determine linker language for target: ",
@@ -2794,6 +2918,19 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::vector libVec;
std::vector vsTargetVec;
this->AddLibraries(cli, libVec, vsTargetVec);
+ if (std::find(linkClosure->Languages.begin(), linkClosure->Languages.end(),
+ "CUDA") != linkClosure->Languages.end()) {
+ switch (this->CudaOptions[config]->GetCudaRuntime()) {
+ case cmVisualStudioGeneratorOptions::CudaRuntimeStatic:
+ libVec.push_back("cudart_static.lib");
+ break;
+ case cmVisualStudioGeneratorOptions::CudaRuntimeShared:
+ libVec.push_back("cudart.lib");
+ break;
+ case cmVisualStudioGeneratorOptions::CudaRuntimeNone:
+ break;
+ }
+ }
std::string standardLibsVar = "CMAKE_";
standardLibsVar += linkLanguage;
standardLibsVar += "_STANDARD_LIBRARIES";
@@ -3132,6 +3269,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
this->WriteClOptions(*i, includes);
// output rc compile flags
this->WriteRCOptions(*i, includes);
+ this->WriteCudaOptions(*i, includes);
this->WriteMasmOptions(*i, includes);
this->WriteNasmOptions(*i, includes);
}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 0ebb4e494c..52d55501dc 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -98,6 +98,10 @@ private:
bool ComputeRcOptions(std::string const& config);
void WriteRCOptions(std::string const& config,
std::vector const& includes);
+ bool ComputeCudaOptions();
+ bool ComputeCudaOptions(std::string const& config);
+ void WriteCudaOptions(std::string const& config,
+ std::vector const& includes);
bool ComputeMasmOptions();
bool ComputeMasmOptions(std::string const& config);
void WriteMasmOptions(std::string const& config,
@@ -150,6 +154,7 @@ private:
typedef std::map OptionsMap;
OptionsMap ClOptions;
OptionsMap RcOptions;
+ OptionsMap CudaOptions;
OptionsMap MasmOptions;
OptionsMap NasmOptions;
OptionsMap LinkOptions;
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index dfe5ce6f8e..1ca6b9cd10 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -43,6 +43,8 @@ cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
this->FortranRuntimeDebug = false;
this->FortranRuntimeDLL = false;
this->FortranRuntimeMT = false;
+
+ this->UnknownFlagField = "AdditionalOptions";
}
cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
@@ -67,6 +69,8 @@ cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
this->FortranRuntimeDebug = false;
this->FortranRuntimeDLL = false;
this->FortranRuntimeMT = false;
+
+ this->UnknownFlagField = "AdditionalOptions";
}
void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
@@ -81,6 +85,13 @@ void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
}
}
+void cmVisualStudioGeneratorOptions::ClearTables()
+{
+ for (int i = 0; i < FlagTableCount; ++i) {
+ this->FlagTable[i] = CM_NULLPTR;
+ }
+}
+
void cmVisualStudioGeneratorOptions::FixExceptionHandlingDefault()
{
// Exception handling is on by default because the platform file has
@@ -176,6 +187,78 @@ bool cmVisualStudioGeneratorOptions::UsingSBCS() const
return false;
}
+cmVisualStudioGeneratorOptions::CudaRuntime
+cmVisualStudioGeneratorOptions::GetCudaRuntime() const
+{
+ std::map::const_iterator i =
+ this->FlagMap.find("CudaRuntime");
+ if (i != this->FlagMap.end() && i->second.size() == 1) {
+ std::string const& cudaRuntime = i->second[0];
+ if (cudaRuntime == "Static") {
+ return CudaRuntimeStatic;
+ }
+ if (cudaRuntime == "Shared") {
+ return CudaRuntimeShared;
+ }
+ if (cudaRuntime == "None") {
+ return CudaRuntimeNone;
+ }
+ }
+ // nvcc default is static
+ return CudaRuntimeStatic;
+}
+
+void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
+{
+ // Extract temporary values stored by our flag table.
+ FlagValue arch = this->TakeFlag("cmake-temp-arch");
+ FlagValue code = this->TakeFlag("cmake-temp-code");
+ FlagValue gencode = this->TakeFlag("cmake-temp-gencode");
+
+ // No -code allowed without -arch.
+ if (arch.empty()) {
+ code.clear();
+ }
+
+ if (arch.empty() && gencode.empty()) {
+ return;
+ }
+
+ // Create a CodeGeneration field with [arch],[code] syntax in each entry.
+ // CUDA will convert it to `-gencode=arch=[arch],code="[code],[arch]"`.
+ FlagValue& result = this->FlagMap["CodeGeneration"];
+
+ // First entries for the -arch= [-code=,...] pair.
+ if (!arch.empty()) {
+ std::string arch_name = arch[0];
+ std::vector codes;
+ if (!code.empty()) {
+ codes = cmSystemTools::tokenize(code[0], ",");
+ }
+ if (codes.empty()) {
+ codes.push_back(arch_name);
+ // nvcc -arch= has a special case that allows a real
+ // architecture to be specified instead of a virtual arch.
+ // It translates to -arch= -code=.
+ cmSystemTools::ReplaceString(arch_name, "sm_", "compute_");
+ }
+ for (std::vector::iterator ci = codes.begin();
+ ci != codes.end(); ++ci) {
+ std::string entry = arch_name + "," + *ci;
+ result.push_back(entry);
+ }
+ }
+
+ // Now add entries for the -gencode=, pairs.
+ for (std::vector::iterator ei = gencode.begin();
+ ei != gencode.end(); ++ei) {
+ std::string entry = *ei;
+ cmSystemTools::ReplaceString(entry, "arch=", "");
+ cmSystemTools::ReplaceString(entry, "code=", "");
+ result.push_back(entry);
+ }
+}
+
void cmVisualStudioGeneratorOptions::Parse(const char* flags)
{
// Parse the input string as a windows command line since the string
@@ -209,6 +292,21 @@ void cmVisualStudioGeneratorOptions::ParseFinish()
rl += this->FortranRuntimeDLL ? "DLL" : "";
this->FlagMap["RuntimeLibrary"] = rl;
}
+
+ if (this->CurrentTool == CudaCompiler) {
+ std::map::iterator i =
+ this->FlagMap.find("CudaRuntime");
+ if (i != this->FlagMap.end() && i->second.size() == 1) {
+ std::string& cudaRuntime = i->second[0];
+ if (cudaRuntime == "static") {
+ cudaRuntime = "Static";
+ } else if (cudaRuntime == "shared") {
+ cudaRuntime = "Shared";
+ } else if (cudaRuntime == "none") {
+ cudaRuntime = "None";
+ }
+ }
+ }
}
void cmVisualStudioGeneratorOptions::PrependInheritedString(
@@ -222,6 +320,18 @@ void cmVisualStudioGeneratorOptions::PrependInheritedString(
value = "%(" + key + ") " + value;
}
+void cmVisualStudioGeneratorOptions::Reparse(std::string const& key)
+{
+ std::map::iterator i = this->FlagMap.find(key);
+ if (i == this->FlagMap.end() || i->second.size() != 1) {
+ return;
+ }
+ std::string const original = i->second[0];
+ i->second[0] = "";
+ this->UnknownFlagField = key;
+ this->Parse(original.c_str());
+}
+
void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag)
{
// Look for Intel Fortran flags that do not map well in the flag table.
@@ -248,7 +358,19 @@ void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag)
std::string const opts = cmOutputConverter::EscapeWindowsShellArgument(
flag, cmOutputConverter::Shell_Flag_AllowMakeVariables |
cmOutputConverter::Shell_Flag_VSIDE);
- this->AppendFlagString("AdditionalOptions", opts);
+ this->AppendFlagString(this->UnknownFlagField, opts);
+}
+
+cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag(
+ std::string const& key)
+{
+ FlagValue value;
+ std::map::iterator i = this->FlagMap.find(key);
+ if (i != this->FlagMap.end()) {
+ value = i->second;
+ this->FlagMap.erase(i);
+ }
+ return value;
}
void cmVisualStudioGeneratorOptions::SetConfiguration(const char* config)
@@ -264,6 +386,9 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
return;
}
const char* tag = "PreprocessorDefinitions";
+ if (lang == "CUDA") {
+ tag = "Defines";
+ }
if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
// if there are configuration specific flags, then
// use the configuration specific tag for PreprocessorDefinitions
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
index 8c49470067..52689e0a55 100644
--- a/Source/cmVisualStudioGeneratorOptions.h
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -26,6 +26,7 @@ public:
{
Compiler,
ResourceCompiler,
+ CudaCompiler,
MasmCompiler,
NasmCompiler,
Linker,
@@ -43,12 +44,19 @@ public:
// Add a table of flags.
void AddTable(cmVS7FlagTable const* table);
+ // Clear the flag tables.
+ void ClearTables();
+
// Store options from command line flags.
void Parse(const char* flags);
void ParseFinish();
void PrependInheritedString(std::string const& key);
+ // Parse the content of the given flag table entry again to extract
+ // known flags and leave the rest in the original entry.
+ void Reparse(std::string const& key);
+
// Fix the ExceptionHandling option to default to off.
void FixExceptionHandlingDefault();
@@ -59,6 +67,16 @@ public:
bool UsingUnicode() const;
bool UsingSBCS() const;
+ enum CudaRuntime
+ {
+ CudaRuntimeStatic,
+ CudaRuntimeShared,
+ CudaRuntimeNone
+ };
+ CudaRuntime GetCudaRuntime() const;
+
+ void FixCudaCodeGeneration();
+
bool IsDebug() const;
bool IsWinRt() const;
bool IsManaged() const;
@@ -81,7 +99,11 @@ private:
bool FortranRuntimeDLL;
bool FortranRuntimeMT;
+ std::string UnknownFlagField;
+
virtual void StoreUnknownFlag(const char* flag);
+
+ FlagValue TakeFlag(std::string const& key);
};
#endif
diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt
index 2646d29a3f..38f2a44a34 100644
--- a/Tests/CudaOnly/WithDefs/CMakeLists.txt
+++ b/Tests/CudaOnly/WithDefs/CMakeLists.txt
@@ -16,8 +16,15 @@ set(release_compile_defs DEFREL)
#build a executable that needs to be passed a complex define through add_defintions
#this verifies we can pass things such as '_','(' to nvcc
add_definitions("-DPACKED_DEFINE=__attribute__((packed))")
-set_source_files_properties(main.notcu PROPERTIES LANGUAGE CUDA)
-add_executable(CudaOnlyWithDefs main.notcu)
+
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ # CUDA MSBuild rules do not pass '-x cu' to nvcc
+ set(main main_for_vs.cu)
+else()
+ set(main main.notcu)
+ set_source_files_properties(main.notcu PROPERTIES LANGUAGE CUDA)
+endif()
+add_executable(CudaOnlyWithDefs ${main})
target_compile_options(CudaOnlyWithDefs
PRIVATE
diff --git a/Tests/CudaOnly/WithDefs/main_for_vs.cu b/Tests/CudaOnly/WithDefs/main_for_vs.cu
new file mode 100644
index 0000000000..56078e7af2
--- /dev/null
+++ b/Tests/CudaOnly/WithDefs/main_for_vs.cu
@@ -0,0 +1 @@
+#include "main.notcu"
diff --git a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
index 44c67a2689..f6449f205b 100644
--- a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
@@ -6,6 +6,12 @@ run_cmake(NoToolset)
if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[01245]")
set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
run_cmake(TestToolset)
+ set(RunCMake_GENERATOR_TOOLSET "Test Toolset,cuda=Test Cuda")
+ run_cmake(TestToolsetCudaBoth)
+ set(RunCMake_GENERATOR_TOOLSET ",cuda=Test Cuda")
+ run_cmake(TestToolsetCudaOnly)
+ set(RunCMake_GENERATOR_TOOLSET "cuda=Test Cuda")
+ run_cmake(TestToolsetCudaOnly)
if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[245]")
set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64")
run_cmake(TestToolsetHostArchBoth)
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth-stdout.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth-stdout.txt
new file mode 100644
index 0000000000..90503e2ccd
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth-stdout.txt
@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='Test Toolset'
+-- CMAKE_VS_PLATFORM_TOOLSET_CUDA='Test Cuda'
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth.cmake
new file mode 100644
index 0000000000..befa0af9d6
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth.cmake
@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_CUDA='${CMAKE_VS_PLATFORM_TOOLSET_CUDA}'")
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly-stdout.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly-stdout.txt
new file mode 100644
index 0000000000..94e1e43e43
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly-stdout.txt
@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='(v[0-9]+|Windows7.1SDK)'
+-- CMAKE_VS_PLATFORM_TOOLSET_CUDA='Test Cuda'
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly.cmake
new file mode 100644
index 0000000000..befa0af9d6
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly.cmake
@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_CUDA='${CMAKE_VS_PLATFORM_TOOLSET_CUDA}'")