From 83bf980c9601c2e5d6a6247867606539d8a14528 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 8 Feb 2017 16:28:39 -0500 Subject: VS: Find the MSBuild value for VCTargetsPath Run MSBuild on a simple `.vcxproj` file to extract the location of the toolset definitions. This will later be useful for looking at available BuildCustomizations. --- Source/cmGlobalVisualStudio10Generator.cxx | 212 +++++++++++++++++++++++++++++ Source/cmGlobalVisualStudio10Generator.h | 3 + 2 files changed, 215 insertions(+) diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index b1285ac..7f34e93 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -15,10 +15,15 @@ #include "cmVS10MASMFlagTable.h" #include "cmVS10NASMFlagTable.h" #include "cmVS10RCFlagTable.h" +#include "cmVersion.h" #include "cmVisualStudioSlnData.h" #include "cmVisualStudioSlnParser.h" +#include "cmXMLWriter.h" #include "cmake.h" +#include +#include + static const char vs10generatorName[] = "Visual Studio 10 2010"; // Map generator name without year to name with year. @@ -170,6 +175,11 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( if (!this->ParseGeneratorToolset(ts, mf)) { return false; } + + if (!this->FindVCTargetsPath(mf)) { + return false; + } + if (const char* toolset = this->GetPlatformToolset()) { mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset); } @@ -507,6 +517,208 @@ std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand() return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand(); } +bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf) +{ + // Skip this in special cases within our own test suite. + if (this->GetPlatformName() == "Test Platform" || + this->GetPlatformToolsetString() == "Test Toolset") { + return true; + } + + std::string wd; + if (!this->ConfiguredFilesPath.empty()) { + // In a try-compile we are given the outer CMakeFiles directory. + wd = this->ConfiguredFilesPath; + } else { + wd = this->GetCMakeInstance()->GetHomeOutputDirectory(); + wd += cmake::GetCMakeFilesDirectory(); + } + wd += "/"; + wd += cmVersion::GetCMakeVersion(); + + // We record the result persistently in a file. + std::string const txt = wd + "/VCTargetsPath.txt"; + + // If we have a recorded result, use it. + { + cmsys::ifstream fin(txt.c_str()); + if (fin && cmSystemTools::GetLineFromStream(fin, this->VCTargetsPath) && + cmSystemTools::FileIsDirectory(this->VCTargetsPath)) { + cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath); + return true; + } + } + + // Prepare the work directory. + if (!cmSystemTools::MakeDirectory(wd)) { + std::string e = "Failed to make directory:\n " + wd; + mf->IssueMessage(cmake::FATAL_ERROR, e.c_str()); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + // Generate a project file for MSBuild to tell us the VCTargetsPath value. + std::string const vcxproj = "VCTargetsPath.vcxproj"; + { + std::string const vcxprojAbs = wd + "/" + vcxproj; + cmsys::ofstream fout(vcxprojAbs.c_str()); + cmXMLWriter xw(fout); + + /* clang-format off */ + xw.StartDocument(); + xw.StartElement("Project"); + xw.Attribute("DefaultTargets", "Build"); + xw.Attribute("ToolsVersion", "4.0"); + xw.Attribute("xmlns", + "http://schemas.microsoft.com/developer/msbuild/2003"); + if (this->IsNsightTegra()) { + xw.StartElement("PropertyGroup"); + xw.Attribute("Label", "NsightTegraProject"); + xw.StartElement("NsightTegraProjectRevisionNumber"); + xw.Content("6"); + xw.EndElement(); // NsightTegraProjectRevisionNumber + xw.EndElement(); // PropertyGroup + } + xw.StartElement("ItemGroup"); + xw.Attribute("Label", "ProjectConfigurations"); + xw.StartElement("ProjectConfiguration"); + xw.Attribute("Include", "Debug|" + this->GetPlatformName()); + xw.StartElement("Configuration"); + xw.Content("Debug"); + xw.EndElement(); // Configuration + xw.StartElement("Platform"); + xw.Content(this->GetPlatformName()); + xw.EndElement(); // Platform + xw.EndElement(); // ProjectConfiguration + xw.EndElement(); // ItemGroup + xw.StartElement("PropertyGroup"); + xw.Attribute("Label", "Globals"); + xw.StartElement("ProjectGUID"); + xw.Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}"); + xw.EndElement(); // ProjectGUID + xw.StartElement("Keyword"); + xw.Content("Win32Proj"); + xw.EndElement(); // Keyword + xw.StartElement("Platform"); + xw.Content(this->GetPlatformName()); + xw.EndElement(); // Platform + if (this->GetSystemName() == "WindowsPhone") { + xw.StartElement("ApplicationType"); + xw.Content("Windows Phone"); + xw.EndElement(); // ApplicationType + xw.StartElement("ApplicationTypeRevision"); + xw.Content(this->GetSystemVersion()); + xw.EndElement(); // ApplicationTypeRevision + } else if (this->GetSystemName() == "WindowsStore") { + xw.StartElement("ApplicationType"); + xw.Content("Windows Store"); + xw.EndElement(); // ApplicationType + xw.StartElement("ApplicationTypeRevision"); + xw.Content(this->GetSystemVersion()); + xw.EndElement(); // ApplicationTypeRevision + } + if (!this->WindowsTargetPlatformVersion.empty()) { + xw.StartElement("WindowsTargetPlatformVersion"); + xw.Content(this->WindowsTargetPlatformVersion); + xw.EndElement(); // WindowsTargetPlatformVersion + } + if (this->GetPlatformName() == "ARM") { + xw.StartElement("WindowsSDKDesktopARMSupport"); + xw.Content("true"); + xw.EndElement(); // WindowsSDKDesktopARMSupport + } + xw.EndElement(); // PropertyGroup + xw.StartElement("Import"); + xw.Attribute("Project", + "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"); + xw.EndElement(); // Import + if (!this->GeneratorToolsetHostArchitecture.empty()) { + xw.StartElement("PropertyGroup"); + xw.StartElement("PreferredToolArchitecture"); + xw.Content(this->GeneratorToolsetHostArchitecture); + xw.EndElement(); // PreferredToolArchitecture + xw.EndElement(); // PropertyGroup + } + xw.StartElement("PropertyGroup"); + xw.Attribute("Label", "Configuration"); + xw.StartElement("ConfigurationType"); + if (this->IsNsightTegra()) { + // Tegra-Android platform does not understand "Utility". + xw.Content("StaticLibrary"); + } else { + xw.Content("Utility"); + } + xw.EndElement(); // ConfigurationType + xw.StartElement("CharacterSet"); + xw.Content("MultiByte"); + xw.EndElement(); // CharacterSet + if (this->IsNsightTegra()) { + xw.StartElement("NdkToolchainVersion"); + xw.Content(this->GetPlatformToolsetString()); + xw.EndElement(); // NdkToolchainVersion + } else { + xw.StartElement("PlatformToolset"); + xw.Content(this->GetPlatformToolsetString()); + xw.EndElement(); // PlatformToolset + } + xw.EndElement(); // PropertyGroup + xw.StartElement("Import"); + xw.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props"); + xw.EndElement(); // Import + xw.StartElement("ItemDefinitionGroup"); + xw.StartElement("PostBuildEvent"); + xw.StartElement("Command"); + xw.Content("echo VCTargetsPath=$(VCTargetsPath)"); + xw.EndElement(); // Command + xw.EndElement(); // PostBuildEvent + xw.EndElement(); // ItemDefinitionGroup + xw.StartElement("Import"); + xw.Attribute("Project", + "$(VCTargetsPath)\\Microsoft.Cpp.targets"); + xw.EndElement(); // Import + xw.EndElement(); // Project + xw.EndDocument(); + /* clang-format on */ + } + + std::vector cmd; + cmd.push_back(this->GetMSBuildCommand()); + cmd.push_back(vcxproj); + cmd.push_back(std::string("/p:VisualStudioVersion=") + + this->GetIDEVersion()); + std::string out; + int ret = 0; + cmsys::RegularExpression regex("\n *VCTargetsPath=([^%\r\n]+)[\r\n]"); + if (!cmSystemTools::RunSingleCommand(cmd, &out, &out, &ret, wd.c_str(), + cmSystemTools::OUTPUT_NONE) || + ret != 0 || !regex.find(out)) { + cmSystemTools::ReplaceString(out, "\n", "\n "); + std::ostringstream e; + /* clang-format off */ + e << + "Failed to run MSBuild command:\n" + " " << cmd[0] << "\n" + "to get the value of VCTargetsPath:\n" + " " << out << "\n" + ; + /* clang-format on */ + if (ret != 0) { + e << "Exit code: " << ret << "\n"; + } + mf->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + this->VCTargetsPath = regex.match(1); + cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath); + + { + cmsys::ofstream fout(txt.c_str()); + fout << this->VCTargetsPath << "\n"; + } + return true; +} + void cmGlobalVisualStudio10Generator::GenerateBuildCommand( std::vector& makeCommand, const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index c5e4bcd..149dcba 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -160,6 +160,9 @@ private: bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf); + std::string VCTargetsPath; + bool FindVCTargetsPath(cmMakefile* mf); + // We do not use the reload macros for VS >= 10. virtual std::string GetUserMacrosDirectory() { return ""; } }; -- cgit v0.12 From 5164e9a6510137eaac1c7b736a6b24fe02ce17a9 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 8 Feb 2017 16:05:08 -0500 Subject: VS: Provide an option to specify CUDA toolset version The NVIDIA CUDA Toolkit provides MSBuild toolset files for integration with Visual Studio. Multiple versions may be installed so we need a way to tell our VS generators which CUDA toolset to use. Extend the `CMAKE_GENERATOR_TOOLSET` specification to provide a `cuda=...` field specifying the version number. --- Help/manual/cmake-variables.7.rst | 1 + Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst | 10 ++++++++++ Source/cmGlobalVisualStudio10Generator.cxx | 23 ++++++++++++++++++++-- Source/cmGlobalVisualStudio10Generator.h | 5 +++++ Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake | 6 ++++++ .../TestToolsetCudaBoth-stdout.txt | 2 ++ .../GeneratorToolset/TestToolsetCudaBoth.cmake | 2 ++ .../TestToolsetCudaOnly-stdout.txt | 2 ++ .../GeneratorToolset/TestToolsetCudaOnly.cmake | 2 ++ 9 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst create mode 100644 Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth-stdout.txt create mode 100644 Tests/RunCMake/GeneratorToolset/TestToolsetCudaBoth.cmake create mode 100644 Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly-stdout.txt create mode 100644 Tests/RunCMake/GeneratorToolset/TestToolsetCudaOnly.cmake diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 3ec0c19..45829bc 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/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_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 0000000..cc18a20 --- /dev/null +++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst @@ -0,0 +1,10 @@ +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``. CMake provides the selected CUDA toolset version +in this variable. The value may be empty if no version was specified. diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 7f34e93..55babda 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -186,6 +186,9 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( 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; } @@ -261,8 +264,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; } @@ -463,6 +468,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)) { diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 149dcba..581ad11 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -53,6 +53,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; } @@ -118,6 +122,7 @@ protected: std::string GeneratorToolset; std::string GeneratorToolsetHostArchitecture; + std::string GeneratorToolsetCuda; std::string DefaultPlatformToolset; std::string WindowsTargetPlatformVersion; std::string SystemName; diff --git a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake index 44c67a2..f6449f2 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 0000000..90503e2 --- /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 0000000..befa0af --- /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 0000000..94e1e43 --- /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 0000000..befa0af --- /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}'") -- cgit v0.12 From 62b308515abe01fbe03ce0e1c7fee4879ca665b1 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 8 Feb 2017 16:25:03 -0500 Subject: VS: Select highest available CUDA toolset by default If `CMAKE_GENERATOR_TOOLSET` does not have a `cuda=...` field then find available CUDA toolsets and choose the highest version. --- Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst | 6 ++++-- Source/cmGlobalVisualStudio10Generator.cxx | 27 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst index cc18a20..1604a76 100644 --- a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst +++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA.rst @@ -6,5 +6,7 @@ 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``. CMake provides the selected CUDA toolset version -in this variable. The value may be empty if no version was specified. +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/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 55babda..2cea693 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -22,8 +22,11 @@ #include "cmake.h" #include +#include #include +#include + static const char vs10generatorName[] = "Visual Studio 10 2010"; // Map generator name without year to name with year. @@ -160,6 +163,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) { @@ -180,6 +190,23 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( 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); } -- cgit v0.12 From a650dbb280859bdbadb9a7bba5636955190ec18a Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 16 Jan 2017 15:21:23 -0500 Subject: VS: Refactor compiler id detection project file template Make the `ClCompile` element name and `PostBuildEvent/Command` value configurable. Move the current content into default values for the corresponding variables. --- Modules/CMakeDetermineCompilerId.cmake | 2 ++ Modules/CompilerId/VS-10.vcxproj.in | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index ae485bf..7dcd981 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -235,6 +235,8 @@ 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") 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 50be9cb..a900482 100644 --- a/Modules/CompilerId/VS-10.vcxproj.in +++ b/Modules/CompilerId/VS-10.vcxproj.in @@ -49,11 +49,11 @@ Console - for %%i in (@id_cl@) do %40echo CMAKE_@id_lang@_COMPILER=%%~$PATH:i + @id_PostBuildEvent_Command@ - + <@id_compile@ Include="@id_src@" /> -- cgit v0.12 From 895b89046601e61f6fb76bf17c5306ea102b9bf6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 16 Jan 2017 15:24:24 -0500 Subject: VS: Add more placeholders to compiler id detection project file template --- Modules/CMakeDetermineCompilerId.cmake | 4 ++++ Modules/CompilerId/VS-10.vcxproj.in | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index 7dcd981..5d85186 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -237,6 +237,10 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS} 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 "") 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 a900482..6b9b361 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,9 +47,11 @@ + @id_ItemDefinitionGroup_entry@ false Console + @id_Link_AdditionalDependencies@ @id_PostBuildEvent_Command@ @@ -56,4 +61,7 @@ <@id_compile@ Include="@id_src@" /> + + @id_Import_targets@ + -- cgit v0.12 From a05fc93ee6ce563bbc6bb23e4540cd7bc2f4e52a Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 15 Feb 2017 09:40:07 -0500 Subject: VS: Add method to clear flag tables of option parser --- Source/cmVisualStudioGeneratorOptions.cxx | 7 +++++++ Source/cmVisualStudioGeneratorOptions.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index dfe5ce6..3f9ef94 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -81,6 +81,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 diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 8c49470..f6cc7ec 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -43,6 +43,9 @@ 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(); -- cgit v0.12 From f7bb40c92dceedd65965c4c475b5395239e630ea Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 15:10:30 -0500 Subject: VS: Add method to re-parse specific option parser fields This will allow a client to parse flags, replace the flag tables, and then re-parse a field in which flags for a secondary tool were collected. --- Source/cmVisualStudioGeneratorOptions.cxx | 18 +++++++++++++++++- Source/cmVisualStudioGeneratorOptions.h | 6 ++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 3f9ef94..1d20d44 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) @@ -229,6 +233,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. @@ -255,7 +271,7 @@ 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); } void cmVisualStudioGeneratorOptions::SetConfiguration(const char* config) diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index f6cc7ec..700b877 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -52,6 +52,10 @@ public: 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(); @@ -84,6 +88,8 @@ private: bool FortranRuntimeDLL; bool FortranRuntimeMT; + std::string UnknownFlagField; + virtual void StoreUnknownFlag(const char* flag); }; -- cgit v0.12 From 80e982d7ad571ce308708d36a531df7a91ffe0f8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 15:16:17 -0500 Subject: VS: Add method to take a value out of the option parser flag map Remove a flag from the map and return its value. --- Source/cmVisualStudioGeneratorOptions.cxx | 12 ++++++++++++ Source/cmVisualStudioGeneratorOptions.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 1d20d44..3007f14 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -274,6 +274,18 @@ void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag) 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) { this->Configuration = config; diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 700b877..e79c977 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -91,6 +91,8 @@ private: std::string UnknownFlagField; virtual void StoreUnknownFlag(const char* flag); + + FlagValue TakeFlag(std::string const& key); }; #endif -- cgit v0.12 From 82521e359f9afbb1644d1b8eae58f27a51407df3 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 14:32:35 -0500 Subject: VS: Add support for determining CUDA compiler id Teach `CMakeDetermineCompilerId` how to generate a vcxproj file using the `CMAKE_VS_PLATFORM_TOOLSET_CUDA`. --- Modules/CMakeDetermineCUDACompiler.cmake | 51 +++++++++++++++++++------------- Modules/CMakeDetermineCompilerId.cmake | 14 +++++++++ 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake index 375e230..55a6f0c 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) - - # 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}") +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}") + 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 5d85186..6fce8e2 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -241,6 +241,20 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS} 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") -- cgit v0.12 From 13433b135759edaa65bd1cb31c3b124c244866d7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 15:44:43 -0500 Subject: VS: Record in global generator whether CUDA is enabled --- Source/cmGlobalVisualStudio10Generator.cxx | 4 ++++ Source/cmGlobalVisualStudio10Generator.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 2cea693..27bd352 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -103,6 +103,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; @@ -459,6 +460,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); diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 581ad11..fdeb381 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; @@ -168,6 +170,8 @@ private: std::string VCTargetsPath; bool FindVCTargetsPath(cmMakefile* mf); + bool CudaEnabled; + // We do not use the reload macros for VS >= 10. virtual std::string GetUserMacrosDirectory() { return ""; } }; -- cgit v0.12 From 041ebda25bef6c142ac80135b0b59d88acbc0f1f Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 15:47:50 -0500 Subject: VS: Add placeholder CUDA flag tables The CUDA Toolkit's VS integration defines abstractions for both options to `nvcc` and options to pass through `-Xcompiler` to the host MSVC. We need a separate flag table to parse each set of flags into the corresponding abstractions. Add empty placeholders for these tables. --- Source/cmGlobalVisualStudio10Generator.cxx | 15 +++++++++++++++ Source/cmGlobalVisualStudio10Generator.h | 4 ++++ Source/cmVS10CudaFlagTable.h | 1 + Source/cmVS10CudaHostFlagTable.h | 1 + 4 files changed, 21 insertions(+) create mode 100644 Source/cmVS10CudaFlagTable.h create mode 100644 Source/cmVS10CudaHostFlagTable.h diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 27bd352..ca98e6c 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -10,6 +10,8 @@ #include "cmSourceFile.h" #include "cmVS10CLFlagTable.h" #include "cmVS10CSharpFlagTable.h" +#include "cmVS10CudaFlagTable.h" +#include "cmVS10CudaHostFlagTable.h" #include "cmVS10LibFlagTable.h" #include "cmVS10LinkFlagTable.h" #include "cmVS10MASMFlagTable.h" @@ -122,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; @@ -983,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 fdeb381..20f992a 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -100,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; @@ -134,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; diff --git a/Source/cmVS10CudaFlagTable.h b/Source/cmVS10CudaFlagTable.h new file mode 100644 index 0000000..4df474e --- /dev/null +++ b/Source/cmVS10CudaFlagTable.h @@ -0,0 +1 @@ +static cmVS7FlagTable cmVS10CudaFlagTable[] = { { 0, 0, 0, 0, 0 } }; diff --git a/Source/cmVS10CudaHostFlagTable.h b/Source/cmVS10CudaHostFlagTable.h new file mode 100644 index 0000000..5ad05f1 --- /dev/null +++ b/Source/cmVS10CudaHostFlagTable.h @@ -0,0 +1 @@ +static cmVS7FlagTable cmVS10CudaHostFlagTable[] = { { 0, 0, 0, 0, 0 } }; -- cgit v0.12 From b64b4629ea8aa669d652ffb32fe7a7336bd8ea8c Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 15:59:33 -0500 Subject: VS: Add basic infrastructure for CUDA generation Generate the `CudaCompile` elements in `.vcxproj` files. --- Source/cmVisualStudio10TargetGenerator.cxx | 103 +++++++++++++++++++++++++++++ Source/cmVisualStudio10TargetGenerator.h | 5 ++ Source/cmVisualStudioGeneratorOptions.cxx | 3 + Source/cmVisualStudioGeneratorOptions.h | 1 + 4 files changed, 112 insertions(+) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index fbf7447..613c825 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", @@ -1772,6 +1795,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() tool = "ResourceCompile"; } else if (lang == "CSharp") { tool = "Compile"; + } else if (lang == "CUDA" && this->GlobalGenerator->IsCudaEnabled()) { + tool = "CudaCompile"; } if (!tool.empty()) { @@ -2401,6 +2426,83 @@ 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(); + + 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()) { @@ -3142,6 +3244,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 0ebb4e4..52d5550 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 3007f14..125d2c4 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -299,6 +299,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 e79c977..e19d2dd 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -26,6 +26,7 @@ public: { Compiler, ResourceCompiler, + CudaCompiler, MasmCompiler, NasmCompiler, Linker, -- cgit v0.12 From b966f489c1b35cbc897720f1f9b68bd9b69175c7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 16:07:12 -0500 Subject: VS: Do not use absolute paths to CUDA sources The CUDA Toolkit's VS integration does not properly compute the intermediate files directory location when the path to the source file is absolute. --- Source/cmVisualStudio10TargetGenerator.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 613c825..c4bcd41 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1717,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())) { -- cgit v0.12 From 29f07b08671ea8a8cf2b32c6b740a2ecaa58168c Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 16:08:45 -0500 Subject: VS: Do not pass CUDA compile options to C compiler --- Source/cmVisualStudio10TargetGenerator.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index c4bcd41..ec39c8f 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2235,8 +2235,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 = -- cgit v0.12 From 4def02a3852eb211e26951819646f8cd8ee6c00c Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 16:12:27 -0500 Subject: VS: Place CUDA host compiler options in proper project file fields The CUDA Toolkit's VS integration provides abstractions for host compiler options for `nvcc` to pass through `-Xcompiler` to the host MSVC. Populate our secondary flag table and use it to remove flags from the `AdditionalCompilerOptions` in favor of their abstractions. Unfortunately a bug in the CUDA 8.0 VS integration prevents us from passing anything in `AdditionalCompilerOptions` reliably. After taking out the flags that have dedicated abstractions, drop the rest. --- Source/cmVS10CudaFlagTable.h | 10 ++++++++- Source/cmVS10CudaHostFlagTable.h | 36 +++++++++++++++++++++++++++++- Source/cmVisualStudio10TargetGenerator.cxx | 10 +++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Source/cmVS10CudaFlagTable.h b/Source/cmVS10CudaFlagTable.h index 4df474e..0a93de8 100644 --- a/Source/cmVS10CudaFlagTable.h +++ b/Source/cmVS10CudaFlagTable.h @@ -1 +1,9 @@ -static cmVS7FlagTable cmVS10CudaFlagTable[] = { { 0, 0, 0, 0, 0 } }; +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 }, + + { 0, 0, 0, 0, 0 } +}; diff --git a/Source/cmVS10CudaHostFlagTable.h b/Source/cmVS10CudaHostFlagTable.h index 5ad05f1..5b61066 100644 --- a/Source/cmVS10CudaHostFlagTable.h +++ b/Source/cmVS10CudaHostFlagTable.h @@ -1 +1,35 @@ -static cmVS7FlagTable cmVS10CudaHostFlagTable[] = { { 0, 0, 0, 0, 0 } }; +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 ec39c8f..7d66fcb 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2470,6 +2470,16 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( cudaOptions.Parse(defineFlags.c_str()); cudaOptions.ParseFinish(); + // 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"); + std::vector targetDefines; this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName.c_str(), "CUDA"); -- cgit v0.12 From 253594d0aec0cbe34694cac59ef1a8e42a532118 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 16:19:22 -0500 Subject: VS: Select the CUDA runtime library Parse the `-cudart=` option and add a corresponding `CudaRuntime` field to the generated project file. Also add a matching `.lib` to the list of libraries linked. --- Source/cmVS10CudaFlagTable.h | 9 ++++++++ Source/cmVisualStudio10TargetGenerator.cxx | 19 ++++++++++++++-- Source/cmVisualStudioGeneratorOptions.cxx | 36 ++++++++++++++++++++++++++++++ Source/cmVisualStudioGeneratorOptions.h | 8 +++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/Source/cmVS10CudaFlagTable.h b/Source/cmVS10CudaFlagTable.h index 0a93de8..268553d 100644 --- a/Source/cmVS10CudaFlagTable.h +++ b/Source/cmVS10CudaFlagTable.h @@ -5,5 +5,14 @@ static cmVS7FlagTable cmVS10CudaFlagTable[] = { { "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 }, + { 0, 0, 0, 0, 0 } }; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 7d66fcb..8de9fe1 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2855,8 +2855,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: ", @@ -2911,6 +2913,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"; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 125d2c4..c79dc11 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -187,6 +187,27 @@ 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::Parse(const char* flags) { // Parse the input string as a windows command line since the string @@ -220,6 +241,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( diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index e19d2dd..6722503 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -67,6 +67,14 @@ public: bool UsingUnicode() const; bool UsingSBCS() const; + enum CudaRuntime + { + CudaRuntimeStatic, + CudaRuntimeShared, + CudaRuntimeNone + }; + CudaRuntime GetCudaRuntime() const; + bool IsDebug() const; bool IsWinRt() const; bool IsManaged() const; -- cgit v0.12 From 94255511a6d59b14159544e2489905c62dab9fca Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 16:21:29 -0500 Subject: VS: Select CUDA code generation architectures Parse the `-gencode=`, `-arch`, and `-code` flags and generate a `CodeGeneration` field in the project file. --- Source/cmVS10CudaFlagTable.h | 22 +++++++++++++ Source/cmVisualStudio10TargetGenerator.cxx | 2 ++ Source/cmVisualStudioGeneratorOptions.cxx | 51 ++++++++++++++++++++++++++++++ Source/cmVisualStudioGeneratorOptions.h | 2 ++ 4 files changed, 77 insertions(+) diff --git a/Source/cmVS10CudaFlagTable.h b/Source/cmVS10CudaFlagTable.h index 268553d..d8c27d7 100644 --- a/Source/cmVS10CudaFlagTable.h +++ b/Source/cmVS10CudaFlagTable.h @@ -14,5 +14,27 @@ static cmVS7FlagTable cmVS10CudaFlagTable[] = { { "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 }, + { 0, 0, 0, 0, 0 } }; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 8de9fe1..5ffa55c 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2480,6 +2480,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( // did not parse and hope it works. cudaOptions.RemoveFlag("AdditionalCompilerOptions"); + cudaOptions.FixCudaCodeGeneration(); + std::vector targetDefines; this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName.c_str(), "CUDA"); diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index c79dc11..1ca6b9c 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -208,6 +208,57 @@ cmVisualStudioGeneratorOptions::GetCudaRuntime() const 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 diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 6722503..52689e0 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -75,6 +75,8 @@ public: }; CudaRuntime GetCudaRuntime() const; + void FixCudaCodeGeneration(); + bool IsDebug() const; bool IsWinRt() const; bool IsManaged() const; -- cgit v0.12 From 6ca4f2229234ab7543597ca19bda09c51297eee6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 16:23:57 -0500 Subject: VS: Add support for the CUDA_SEPARABLE_COMPILATION property --- Source/cmVisualStudio10TargetGenerator.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 5ffa55c..fc59660 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2470,6 +2470,10 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( 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(); -- cgit v0.12 From 8cae24a1d0277fe3fdd0f2fa9e9a76906ad6c016 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 16:25:09 -0500 Subject: VS: Add more CUDA flag table entries --- Source/cmVS10CudaFlagTable.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Source/cmVS10CudaFlagTable.h b/Source/cmVS10CudaFlagTable.h index d8c27d7..da19d64 100644 --- a/Source/cmVS10CudaFlagTable.h +++ b/Source/cmVS10CudaFlagTable.h @@ -36,5 +36,16 @@ static cmVS7FlagTable cmVS10CudaFlagTable[] = { { "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 } }; -- cgit v0.12 From 65481a60a06b4238d342f64b5fed52e252ee191b Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 7 Mar 2017 14:27:36 -0500 Subject: CUDA: Work around VS limitation in CudaOnly.WithDefs test CUDA 8.0 MSBuild rules do not pass `-x cu` to nvcc and so cannot support a custom file extension. Fix our test for this to use a `.cu` extension instead. --- Tests/CudaOnly/WithDefs/CMakeLists.txt | 11 +++++++++-- Tests/CudaOnly/WithDefs/main_for_vs.cu | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 Tests/CudaOnly/WithDefs/main_for_vs.cu diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt index 2646d29..38f2a44 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 0000000..56078e7 --- /dev/null +++ b/Tests/CudaOnly/WithDefs/main_for_vs.cu @@ -0,0 +1 @@ +#include "main.notcu" -- cgit v0.12