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}'")