From 6377a43814bb6f3087b731644bb61302a3fc3c55 Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Wed, 1 Jun 2022 09:20:08 -0400 Subject: CUDA: Support response files with nvcc --- Modules/Compiler/NVIDIA-CUDA.cmake | 16 ++++--- Source/cmCoreTryCompile.cxx | 9 ++++ Source/cmMakefileExecutableTargetGenerator.cxx | 10 ++-- Source/cmMakefileLibraryTargetGenerator.cxx | 12 +++-- Source/cmMakefileTargetGenerator.cxx | 65 ++++++++++++++------------ Source/cmMakefileTargetGenerator.h | 20 ++++++-- 6 files changed, 83 insertions(+), 49 deletions(-) diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake index 2f12b43..892df90 100644 --- a/Modules/Compiler/NVIDIA-CUDA.cmake +++ b/Modules/Compiler/NVIDIA-CUDA.cmake @@ -127,15 +127,19 @@ else() endif() -# FIXME: investigate use of --options-file. -# Tell Makefile generator that nvcc does not support @ syntax. -set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 0) -set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 0) -set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 0) - if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "9.0") set(CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG "--options-file ") set(CMAKE_CUDA_RESPONSE_FILE_FLAG "--options-file ") endif() +if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0") + set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 1) + set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 1) + set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 1) +else() + set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 0) + set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 0) + set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 0) +endif() + __compiler_check_default_language_standard(CUDA 6.0 03) diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 1e84a0b..27ff708 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -605,6 +605,15 @@ int cmCoreTryCompile::TryCompileCode(std::vector const& argv, // does not include any system headers anyway. fprintf(fout, "set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES \"\")\n"); + + // The link and compile lines for ABI detection step need to not use + // response files so we can extract implicit includes given to + // the underlying host compiler + if (testLangs.find("CUDA") != testLangs.end()) { + fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES OFF)\n"); + fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES OFF)\n"); + fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS OFF)\n"); + } } fprintf(fout, "set(CMAKE_VERBOSE_MAKEFILE 1)\n"); for (std::string const& li : testLangs) { diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 3849c6f..74574f7 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -182,14 +182,16 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( // Collect up flags to link in needed libraries. std::string linkLibs; - this->CreateLinkLibs(linkLineComputer.get(), linkLibs, - useResponseFileForLibs, depends); + this->CreateLinkLibs( + linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends, + cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); // Construct object file lists that may be needed to expand the // rule. std::string buildObjs; - this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects, - buildObjs, depends, false); + this->CreateObjectLists( + useLinkScript, false, useResponseFileForObjects, buildObjs, depends, + false, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); cmRulePlaceholderExpander::RuleVariables vars; std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index f30ec27..3f7d87d 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -322,15 +322,17 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( linkLineComputer->SetForResponse(useResponseFileForLibs); linkLineComputer->SetRelink(relink); - this->CreateLinkLibs(linkLineComputer.get(), linkLibs, - useResponseFileForLibs, depends); + this->CreateLinkLibs( + linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends, + cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); // Construct object file lists that may be needed to expand the // rule. std::string buildObjs; - this->CreateObjectLists(useLinkScript, false, // useArchiveRules - useResponseFileForObjects, buildObjs, depends, - false); + this->CreateObjectLists( + useLinkScript, false, // useArchiveRules + useResponseFileForObjects, buildObjs, depends, false, + cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); objectDir = this->LocalGenerator->ConvertToOutputFormat( diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index aec6577..103d3ac 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -107,7 +107,7 @@ std::unique_ptr cmMakefileTargetGenerator::New( return result; } -std::string cmMakefileTargetGenerator::GetConfigName() +std::string cmMakefileTargetGenerator::GetConfigName() const { auto const& configNames = this->LocalGenerator->GetConfigNames(); assert(configNames.size() == 1); @@ -2080,7 +2080,7 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForLibraries( } std::string cmMakefileTargetGenerator::CreateResponseFile( - const char* name, std::string const& options, + const std::string& name, std::string const& options, std::vector& makefile_depends) { // FIXME: Find a better way to determine the response file encoding, @@ -2126,7 +2126,8 @@ cmMakefileTargetGenerator::CreateLinkLineComputer( void cmMakefileTargetGenerator::CreateLinkLibs( cmLinkLineComputer* linkLineComputer, std::string& linkLibs, - bool useResponseFile, std::vector& makefile_depends) + bool useResponseFile, std::vector& makefile_depends, + ResponseFlagFor responseMode) { std::string frameworkPath; std::string linkPath; @@ -2139,20 +2140,13 @@ void cmMakefileTargetGenerator::CreateLinkLibs( if (useResponseFile && linkLibs.find_first_not_of(' ') != std::string::npos) { // Lookup the response file reference flag. - std::string responseFlagVar = - cmStrCat("CMAKE_", - this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), - "_RESPONSE_FILE_LINK_FLAG"); - std::string responseFlag; - if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) { - responseFlag = *p; - } else { - responseFlag = "@"; - } + std::string responseFlag = this->GetResponseFlag(responseMode); // Create this response file. + std::string responseFileName = + (responseMode == Link) ? "linkLibs.rsp" : "deviceLinkLibs.rsp"; std::string link_rsp = - this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends); + this->CreateResponseFile(responseFileName, linkLibs, makefile_depends); // Reference the response file. linkLibs = cmStrCat(responseFlag, @@ -2164,7 +2158,7 @@ void cmMakefileTargetGenerator::CreateLinkLibs( void cmMakefileTargetGenerator::CreateObjectLists( bool useLinkScript, bool useArchiveRules, bool useResponseFile, std::string& buildObjs, std::vector& makefile_depends, - bool useWatcomQuote) + bool useWatcomQuote, ResponseFlagFor responseMode) { std::string variableName; std::string variableNameExternal; @@ -2179,27 +2173,19 @@ void cmMakefileTargetGenerator::CreateObjectLists( this->WriteObjectsStrings(object_strings, responseFileLimit); // Lookup the response file reference flag. - std::string responseFlagVar = - cmStrCat("CMAKE_", - this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), - "_RESPONSE_FILE_LINK_FLAG"); - std::string responseFlag; - if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) { - responseFlag = *p; - } else { - responseFlag = "@"; - } + std::string responseFlag = this->GetResponseFlag(responseMode); // Write a response file for each string. const char* sep = ""; for (unsigned int i = 0; i < object_strings.size(); ++i) { // Number the response files. - char rsp[32]; - snprintf(rsp, sizeof(rsp), "objects%u.rsp", i + 1); + std::string responseFileName = + (responseMode == Link) ? "objects" : "deviceObjects"; + responseFileName += std::to_string(i + 1); // Create this response file. - std::string objects_rsp = - this->CreateResponseFile(rsp, object_strings[i], makefile_depends); + std::string objects_rsp = this->CreateResponseFile( + responseFileName, object_strings[i], makefile_depends); // Separate from previous response file references. buildObjs += sep; @@ -2251,7 +2237,7 @@ void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, } std::string name = cmStrCat("includes_", lang, ".rsp"); std::string arg = std::move(responseFlag) + - this->CreateResponseFile(name.c_str(), includeFlags, + this->CreateResponseFile(name, includeFlags, this->FlagFileDepends[lang]); this->LocalGenerator->AppendFlags(flags, arg); } else { @@ -2304,3 +2290,22 @@ void cmMakefileTargetGenerator::GenDefFile( fout << src->GetFullPath() << "\n"; } } + +std::string cmMakefileTargetGenerator::GetResponseFlag( + ResponseFlagFor mode) const +{ + std::string responseFlag = "@"; + std::string responseFlagVar; + + auto lang = this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); + if (mode == cmMakefileTargetGenerator::ResponseFlagFor::Link) { + responseFlagVar = cmStrCat("CMAKE_", lang, "_RESPONSE_FILE_LINK_FLAG"); + } else if (mode == cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink) { + responseFlagVar = "CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG"; + } + + if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) { + responseFlag = *p; + } + return responseFlag; +} diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index cb804e0..dafa650 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -56,7 +56,7 @@ public: cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; } - std::string GetConfigName(); + std::string GetConfigName() const; protected: void GetDeviceLinkFlags(std::string& linkFlags, @@ -157,22 +157,31 @@ protected: /** Create a response file with the given set of options. Returns the relative path from the target build working directory to the response file name. */ - std::string CreateResponseFile(const char* name, std::string const& options, + std::string CreateResponseFile(const std::string& name, + std::string const& options, std::vector& makefile_depends); bool CheckUseResponseFileForObjects(std::string const& l) const; bool CheckUseResponseFileForLibraries(std::string const& l) const; + enum ResponseFlagFor + { + Link, + DeviceLink + }; + /** Create list of flags for link libraries. */ void CreateLinkLibs(cmLinkLineComputer* linkLineComputer, std::string& linkLibs, bool useResponseFile, - std::vector& makefile_depends); + std::vector& makefile_depends, + ResponseFlagFor responseMode = ResponseFlagFor::Link); /** Create lists of object files for linking and cleaning. */ void CreateObjectLists(bool useLinkScript, bool useArchiveRules, bool useResponseFile, std::string& buildObjs, std::vector& makefile_depends, - bool useWatcomQuote); + bool useWatcomQuote, + ResponseFlagFor responseMode = ResponseFlagFor::Link); /** Add commands for generate def files */ void GenDefFile(std::vector& real_link_commands); @@ -180,6 +189,9 @@ protected: void AddIncludeFlags(std::string& flags, const std::string& lang, const std::string& config) override; + /** Return the response flag for the given configuration */ + std::string GetResponseFlag(ResponseFlagFor mode) const; + virtual void CloseFileStreams(); cmLocalUnixMakefileGenerator3* LocalGenerator; cmGlobalUnixMakefileGenerator3* GlobalGenerator; -- cgit v0.12