diff options
author | Brad King <brad.king@kitware.com> | 2016-11-29 13:59:03 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2016-11-29 13:59:03 (GMT) |
commit | 4838ca14dfe9ee17b2c788b91227d8f7bf733f06 (patch) | |
tree | e6d2925f18c2946d3047efc45a11a48bc733220e /Source | |
parent | a0af10e42371b17daa51646a3123ec5d8a6d0291 (diff) | |
parent | 4cc601f2c5c0fe76fa76f7e4a47d112df7a1c032 (diff) | |
download | CMake-4838ca14dfe9ee17b2c788b91227d8f7bf733f06.zip CMake-4838ca14dfe9ee17b2c788b91227d8f7bf733f06.tar.gz CMake-4838ca14dfe9ee17b2c788b91227d8f7bf733f06.tar.bz2 |
Merge topic 'initial_cuda_language_support'
4cc601f2 Help: Add release note for CUDA support
7b9131da CUDA: Add tests to verify CUDA compiler works properly.
9cf5b98d CUDA: Prefer environment variables CUDACXX and CUDAHOSTCXX.
a5e806b3 CUDA: Add support for CMAKE_CUDA_COMPILE_OPTIONS_VISIBILITY
d038559e CUDA: Add separable compilation support to the makefile generator.
43ce4414 CUDA: Add separable compilation support to the ninja generator.
4b316097 CUDA: Add support for the CUDA_SEPARABLE_COMPILATION target property
ae05fcc6 CUDA: Add LinkLineComputer that computes cuda dlink lines.
115269a8 CUDA: Refactor cmLinkLineComputer to allow for better derived children.
5dec4031 CUDA: Refactor CMakeCUDAInformation to prepare for separable compilation.
5b20d0ab CUDA: C++ compile features now enable cuda c++11 support.
489c52ce CUDA: Use the host compiler for linking CUDA executables and shared libs.
bbaf2434 CUDA: add support for specifying an explicit host compiler.
a92f8d96 CUDA: Enable header dependency scanning.
ec6ce623 CUDA: State that cuda has preprocessor output and can generate assembly.
4f5155f6 CUDA: We now properly perform CUDA compiler identification.
...
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Source/cmComputeLinkInformation.h | 1 | ||||
-rw-r--r-- | Source/cmLinkLineComputer.h | 6 | ||||
-rw-r--r-- | Source/cmLinkLineDeviceComputer.cxx | 74 | ||||
-rw-r--r-- | Source/cmLinkLineDeviceComputer.h | 36 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 5 | ||||
-rw-r--r-- | Source/cmLocalUnixMakefileGenerator3.cxx | 7 | ||||
-rw-r--r-- | Source/cmMakefile.cxx | 3 | ||||
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.cxx | 227 | ||||
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.h | 4 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 222 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.h | 6 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 27 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 358 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.h | 10 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 18 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 4 |
17 files changed, 992 insertions, 18 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index fcda6f9..f7e0944 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -298,6 +298,8 @@ set(SRCS cmLinkItem.h cmLinkLineComputer.cxx cmLinkLineComputer.h + cmLinkLineDeviceComputer.cxx + cmLinkLineDeviceComputer.h cmListFileCache.cxx cmListFileCache.h cmListFileLexer.c diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 1d29c26..3d26ea7 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -70,6 +70,7 @@ public: std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; } std::string GetRPathLinkString(); + std::string GetConfig() const { return this->Config; } private: void AddItem(std::string const& item, const cmGeneratorTarget* tgt); void AddSharedDepItem(std::string const& item, cmGeneratorTarget const* tgt); diff --git a/Source/cmLinkLineComputer.h b/Source/cmLinkLineComputer.h index 97a5d1b..bb13717 100644 --- a/Source/cmLinkLineComputer.h +++ b/Source/cmLinkLineComputer.h @@ -33,10 +33,10 @@ public: std::string ComputeFrameworkPath(cmComputeLinkInformation& cli, std::string const& fwSearchFlag); - std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, - std::string const& stdLibString); + virtual std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, + std::string const& stdLibString); -private: +protected: std::string ComputeLinkLibs(cmComputeLinkInformation& cli); std::string ComputeRPath(cmComputeLinkInformation& cli); diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx new file mode 100644 index 0000000..75e5ef5 --- /dev/null +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -0,0 +1,74 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmLinkLineDeviceComputer.h" +#include "cmComputeLinkInformation.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalNinjaGenerator.h" +#include "cmOutputConverter.h" + +cmLinkLineDeviceComputer::cmLinkLineDeviceComputer( + cmOutputConverter* outputConverter, cmStateDirectory stateDir) + : cmLinkLineComputer(outputConverter, stateDir) +{ +} + +cmLinkLineDeviceComputer::~cmLinkLineDeviceComputer() +{ +} + +std::string cmLinkLineDeviceComputer::ComputeLinkLibraries( + cmComputeLinkInformation& cli, std::string const& stdLibString) +{ + // Write the library flags to the build rule. + std::ostringstream fout; + typedef cmComputeLinkInformation::ItemVector ItemVector; + ItemVector const& items = cli.GetItems(); + std::string config = cli.GetConfig(); + for (ItemVector::const_iterator li = items.begin(); li != items.end(); + ++li) { + if (!li->Target) { + continue; + } + + if (li->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY || + li->Target->GetType() == cmStateEnums::SHARED_LIBRARY || + li->Target->GetType() == cmStateEnums::MODULE_LIBRARY) { + continue; + } + + std::set<std::string> langs; + li->Target->GetLanguages(langs, config); + if (langs.count("CUDA") == 0) { + continue; + } + + if (li->IsPath) { + fout << this->ConvertToOutputFormat( + this->ConvertToLinkReference(li->Value)); + } else { + fout << li->Value; + } + fout << " "; + } + + if (!stdLibString.empty()) { + fout << stdLibString << " "; + } + + return fout.str(); +} + +cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer( + cmOutputConverter* outputConverter, cmStateDirectory stateDir, + cmGlobalNinjaGenerator const* gg) + : cmLinkLineDeviceComputer(outputConverter, stateDir) + , GG(gg) +{ +} + +std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference( + std::string const& lib) const +{ + return GG->ConvertToNinjaPath(lib); +} diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h new file mode 100644 index 0000000..d1079d7 --- /dev/null +++ b/Source/cmLinkLineDeviceComputer.h @@ -0,0 +1,36 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#ifndef cmLinkLineDeviceComputer_h +#define cmLinkLineDeviceComputer_h + +#include "cmLinkLineComputer.h" +class cmGlobalNinjaGenerator; + +class cmLinkLineDeviceComputer : public cmLinkLineComputer +{ +public: + cmLinkLineDeviceComputer(cmOutputConverter* outputConverter, + cmStateDirectory stateDir); + ~cmLinkLineDeviceComputer() CM_OVERRIDE; + + std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, + std::string const& stdLibString) + CM_OVERRIDE; +}; + +class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer +{ +public: + cmNinjaLinkLineDeviceComputer(cmOutputConverter* outputConverter, + cmStateDirectory stateDir, + cmGlobalNinjaGenerator const* gg); + + std::string ConvertToLinkReference(std::string const& input) const + CM_OVERRIDE; + +private: + cmGlobalNinjaGenerator const* GG; +}; + +#endif diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 1fda4e9..46e49dc 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -63,6 +63,8 @@ static const char* ruleReplaceVars[] = { "CMAKE_CURRENT_BINARY_DIR", "CMAKE_RANLIB", "CMAKE_LINKER", + "CMAKE_CUDA_HOST_COMPILER", + "CMAKE_CUDA_HOST_LINK_LAUNCHER", "CMAKE_CL_SHOWINCLUDES_PREFIX" }; @@ -1475,6 +1477,9 @@ void cmLocalGenerator::AddCompilerRequirementFlag( langStdMap["C"].push_back("11"); langStdMap["C"].push_back("99"); langStdMap["C"].push_back("90"); + + langStdMap["CUDA"].push_back("11"); + langStdMap["CUDA"].push_back("98"); } std::string standard(standardProp); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 8bb084a..ba17f81 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -285,8 +285,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefile() for (std::vector<LocalObjectEntry>::const_iterator ei = lo->second.begin(); ei != lo->second.end(); ++ei) { if (ei->Language == "C" || ei->Language == "CXX" || - ei->Language == "Fortran") { - // Right now, C, C++ and Fortran have both a preprocessor and the + ei->Language == "CUDA" || ei->Language == "Fortran") { + // Right now, C, C++, Fortran and CUDA have both a preprocessor and the // ability to generate assembly code lang_has_preprocessor = true; lang_has_assembly = true; @@ -1458,7 +1458,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies( // Create the scanner for this language cmDepends* scanner = CM_NULLPTR; - if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM") { + if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" || + lang == "CUDA") { // TODO: Handle RC (resource files) dependencies correctly. scanner = new cmDependsC(this, targetDir, lang, &validDeps); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 90182f9..fecc983 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -4413,10 +4413,13 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, if (setCxx14) { target->SetProperty("CXX_STANDARD", "14"); + target->SetProperty("CUDA_STANDARD", "14"); } else if (setCxx11) { target->SetProperty("CXX_STANDARD", "11"); + target->SetProperty("CUDA_STANDARD", "11"); } else if (setCxx98) { target->SetProperty("CXX_STANDARD", "98"); + target->SetProperty("CUDA_STANDARD", "98"); } return true; } diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 358804e..069011d 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -10,6 +10,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" +#include "cmLinkLineDeviceComputer.h" #include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" @@ -56,6 +57,9 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() // write in rules for object files and custom commands this->WriteTargetBuildRules(); + // write the device link rules + this->WriteDeviceExecutableRule(false); + // write the link rules this->WriteExecutableRule(false); if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) { @@ -77,6 +81,218 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() this->CloseFileStreams(); } +void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( + bool relink) +{ +#ifdef CMAKE_BUILD_WITH_CMAKE + const std::string cuda_lang("CUDA"); + cmGeneratorTarget::LinkClosure const* closure = + this->GeneratorTarget->GetLinkClosure(this->ConfigName); + + const bool hasCUDA = + (std::find(closure->Languages.begin(), closure->Languages.end(), + cuda_lang) != closure->Languages.end()); + if (!hasCUDA) { + return; + } + + std::vector<std::string> commands; + + // Build list of dependencies. + std::vector<std::string> depends; + this->AppendLinkDepends(depends); + + // Get the language to use for linking this library. + std::string linkLanguage = "CUDA"; + + // Get the name of the device object to generate. + std::string const targetOutputReal = + this->GeneratorTarget->ObjectDirectory + "cmake_device_link.o"; + this->DeviceLinkObject = targetOutputReal; + + this->NumberOfProgressActions++; + if (!this->NoRuleMessages) { + cmLocalUnixMakefileGenerator3::EchoProgress progress; + this->MakeEchoProgress(progress); + // Add the link message. + std::string buildEcho = "Linking "; + buildEcho += linkLanguage; + buildEcho += " device code "; + buildEcho += targetOutputReal; + this->LocalGenerator->AppendEcho( + commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress); + } + + // Build a list of compiler flags and linker flags. + std::string flags; + std::string linkFlags; + + // Add flags to create an executable. + // Add symbol export flags if necessary. + if (this->GeneratorTarget->IsExecutableWithExports()) { + std::string export_flag_var = "CMAKE_EXE_EXPORTS_"; + export_flag_var += linkLanguage; + export_flag_var += "_FLAG"; + this->LocalGenerator->AppendFlags( + linkFlags, this->Makefile->GetDefinition(export_flag_var)); + } + + this->LocalGenerator->AppendFlags(linkFlags, + this->LocalGenerator->GetLinkLibsCMP0065( + linkLanguage, *this->GeneratorTarget)); + + // Add language feature flags. + this->AddFeatureFlags(flags, linkLanguage); + + this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget, + linkLanguage, this->ConfigName); + + // Add target-specific linker flags. + this->LocalGenerator->AppendFlags( + linkFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS")); + std::string linkFlagsConfig = "LINK_FLAGS_"; + linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName); + this->LocalGenerator->AppendFlags( + linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig)); + + { + CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer( + this->CreateLinkLineComputer( + this->LocalGenerator, + this->LocalGenerator->GetStateSnapshot().GetDirectory())); + + this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags); + } + + // Construct a list of files associated with this executable that + // may need to be cleaned. + std::vector<std::string> exeCleanFiles; + exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal)); + + // Determine whether a link script will be used. + bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); + + // Construct the main link rule. + std::vector<std::string> real_link_commands; + const std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE"; + const std::string linkRule = this->GetLinkRule(linkRuleVar); + std::vector<std::string> commands1; + cmSystemTools::ExpandListArgument(linkRule, real_link_commands); + + bool useResponseFileForObjects = + this->CheckUseResponseFileForObjects(linkLanguage); + bool const useResponseFileForLibs = + this->CheckUseResponseFileForLibraries(linkLanguage); + + // Expand the rule variables. + { + bool useWatcomQuote = + this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); + + // Set path conversion for link script shells. + this->LocalGenerator->SetLinkScriptShell(useLinkScript); + + CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer( + new cmLinkLineDeviceComputer( + this->LocalGenerator, + this->LocalGenerator->GetStateSnapshot().GetDirectory())); + linkLineComputer->SetForResponse(useResponseFileForLibs); + linkLineComputer->SetUseWatcomQuote(useWatcomQuote); + linkLineComputer->SetRelink(relink); + + // Collect up flags to link in needed libraries. + std::string linkLibs; + this->CreateLinkLibs(linkLineComputer.get(), linkLibs, + useResponseFileForLibs, depends); + + // Construct object file lists that may be needed to expand the + // rule. + std::string buildObjs; + this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects, + buildObjs, depends, useWatcomQuote); + + cmRulePlaceholderExpander::RuleVariables vars; + std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); + + objectDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir), + cmOutputConverter::SHELL); + + cmOutputConverter::OutputFormat output = (useWatcomQuote) + ? cmOutputConverter::WATCOMQUOTE + : cmOutputConverter::SHELL; + std::string target = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), + output); + + vars.Language = linkLanguage.c_str(); + vars.Objects = buildObjs.c_str(); + vars.ObjectDir = objectDir.c_str(); + vars.Target = target.c_str(); + vars.LinkLibraries = linkLibs.c_str(); + vars.Flags = flags.c_str(); + vars.LinkFlags = linkFlags.c_str(); + + std::string launcher; + + const char* val = this->LocalGenerator->GetRuleLauncher( + this->GeneratorTarget, "RULE_LAUNCH_LINK"); + if (val && *val) { + launcher = val; + launcher += " "; + } + + CM_AUTO_PTR<cmRulePlaceholderExpander> rulePlaceholderExpander( + this->LocalGenerator->CreateRulePlaceholderExpander()); + + // Expand placeholders in the commands. + rulePlaceholderExpander->SetTargetImpLib(targetOutputReal); + for (std::vector<std::string>::iterator i = real_link_commands.begin(); + i != real_link_commands.end(); ++i) { + *i = launcher + *i; + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, *i, + vars); + } + + // Restore path conversion to normal shells. + this->LocalGenerator->SetLinkScriptShell(false); + } + + // Optionally convert the build rule to use a script to avoid long + // command lines in the make shell. + if (useLinkScript) { + // Use a link script. + const char* name = (relink ? "drelink.txt" : "dlink.txt"); + this->CreateLinkScript(name, real_link_commands, commands1, depends); + } else { + // No link script. Just use the link rule directly. + commands1 = real_link_commands; + } + this->LocalGenerator->CreateCDCommand( + commands1, this->Makefile->GetCurrentBinaryDirectory(), + this->LocalGenerator->GetBinaryDirectory()); + commands.insert(commands.end(), commands1.begin(), commands1.end()); + commands1.clear(); + + // Write the build rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + targetOutputReal, depends, commands, + false); + + // Write the main driver rule to build everything in this target. + this->WriteTargetDriverRule(targetOutputReal, relink); + + // Clean all the possible executable names and symlinks. + this->CleanFiles.insert(this->CleanFiles.end(), exeCleanFiles.begin(), + exeCleanFiles.end()); +#else + static_cast<void>(relink); +#endif +} + void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) { std::vector<std::string> commands; @@ -84,6 +300,9 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Build list of dependencies. std::vector<std::string> depends; this->AppendLinkDepends(depends); + if (!this->DeviceLinkObject.empty()) { + depends.push_back(this->DeviceLinkObject); + } // Get the name of the executable to generate. std::string targetName; @@ -327,6 +546,14 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string buildObjs; this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects, buildObjs, depends, useWatcomQuote); + if (!this->DeviceLinkObject.empty()) { + buildObjs += " " + + this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), + this->DeviceLinkObject), + cmOutputConverter::SHELL); + } // maybe create .def file from list of objects if (this->GeneratorTarget->IsExecutableWithExports() && diff --git a/Source/cmMakefileExecutableTargetGenerator.h b/Source/cmMakefileExecutableTargetGenerator.h index 36cfe40..642182b 100644 --- a/Source/cmMakefileExecutableTargetGenerator.h +++ b/Source/cmMakefileExecutableTargetGenerator.h @@ -21,6 +21,10 @@ public: protected: virtual void WriteExecutableRule(bool relink); + virtual void WriteDeviceExecutableRule(bool relink); + +private: + std::string DeviceLinkObject; }; #endif diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index c591bb3..2b0e1b1 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -11,6 +11,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" +#include "cmLinkLineDeviceComputer.h" #include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" @@ -151,6 +152,24 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) this->WriteFrameworkRules(relink); return; } + + if (!relink) { + const std::string cuda_lang("CUDA"); + cmGeneratorTarget::LinkClosure const* closure = + this->GeneratorTarget->GetLinkClosure(this->ConfigName); + + const bool hasCUDA = + (std::find(closure->Languages.begin(), closure->Languages.end(), + cuda_lang) != closure->Languages.end()); + if (hasCUDA) { + std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; + std::string extraFlags; + this->LocalGenerator->AppendFlags( + extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS")); + this->WriteDeviceLibraryRules(linkRuleVar, extraFlags, relink); + } + } + std::string linkLanguage = this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); std::string linkRuleVar = "CMAKE_"; @@ -183,6 +202,24 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) { + + if (!relink) { + const std::string cuda_lang("CUDA"); + cmGeneratorTarget::LinkClosure const* closure = + this->GeneratorTarget->GetLinkClosure(this->ConfigName); + + const bool hasCUDA = + (std::find(closure->Languages.begin(), closure->Languages.end(), + cuda_lang) != closure->Languages.end()); + if (hasCUDA) { + std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; + std::string extraFlags; + this->LocalGenerator->AppendFlags( + extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS")); + this->WriteDeviceLibraryRules(linkRuleVar, extraFlags, relink); + } + } + std::string linkLanguage = this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); std::string linkRuleVar = "CMAKE_"; @@ -230,6 +267,180 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) this->WriteLibraryRules(linkRuleVar, extraFlags, relink); } +void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( + const std::string& linkRuleVar, const std::string& extraFlags, bool relink) +{ +#ifdef CMAKE_BUILD_WITH_CMAKE + // TODO: Merge the methods that call this method to avoid + // code duplication. + std::vector<std::string> commands; + + // Build list of dependencies. + std::vector<std::string> depends; + this->AppendLinkDepends(depends); + + // Get the language to use for linking this library. + std::string linkLanguage = "CUDA"; + + // Create set of linking flags. + std::string linkFlags; + this->LocalGenerator->AppendFlags(linkFlags, extraFlags); + + // Get the name of the device object to generate. + std::string const targetOutputReal = + this->GeneratorTarget->ObjectDirectory + "cmake_device_link.o"; + this->DeviceLinkObject = targetOutputReal; + + this->NumberOfProgressActions++; + if (!this->NoRuleMessages) { + cmLocalUnixMakefileGenerator3::EchoProgress progress; + this->MakeEchoProgress(progress); + // Add the link message. + std::string buildEcho = "Linking " + linkLanguage + " device code"; + buildEcho += targetOutputReal; + this->LocalGenerator->AppendEcho( + commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress); + } + // Clean files associated with this library. + std::vector<std::string> libCleanFiles; + libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal)); + + // Determine whether a link script will be used. + bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); + + bool useResponseFileForObjects = + this->CheckUseResponseFileForObjects(linkLanguage); + bool const useResponseFileForLibs = + this->CheckUseResponseFileForLibraries(linkLanguage); + + cmRulePlaceholderExpander::RuleVariables vars; + vars.Language = linkLanguage.c_str(); + + // Expand the rule variables. + std::vector<std::string> real_link_commands; + { + bool useWatcomQuote = + this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); + + // Set path conversion for link script shells. + this->LocalGenerator->SetLinkScriptShell(useLinkScript); + + // Collect up flags to link in needed libraries. + std::string linkLibs; + if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) { + + CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer( + new cmLinkLineDeviceComputer( + this->LocalGenerator, + this->LocalGenerator->GetStateSnapshot().GetDirectory())); + linkLineComputer->SetForResponse(useResponseFileForLibs); + linkLineComputer->SetUseWatcomQuote(useWatcomQuote); + linkLineComputer->SetRelink(relink); + + this->CreateLinkLibs(linkLineComputer.get(), linkLibs, + useResponseFileForLibs, depends); + } + + // Construct object file lists that may be needed to expand the + // rule. + std::string buildObjs; + this->CreateObjectLists(useLinkScript, false, // useArchiveRules + useResponseFileForObjects, buildObjs, depends, + useWatcomQuote); + + cmOutputConverter::OutputFormat output = (useWatcomQuote) + ? cmOutputConverter::WATCOMQUOTE + : cmOutputConverter::SHELL; + + std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); + objectDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir), + cmOutputConverter::SHELL); + + std::string target = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), + output); + + vars.Objects = buildObjs.c_str(); + vars.ObjectDir = objectDir.c_str(); + vars.Target = target.c_str(); + vars.LinkLibraries = linkLibs.c_str(); + vars.ObjectsQuoted = buildObjs.c_str(); + vars.LinkFlags = linkFlags.c_str(); + + // Add language feature flags. + std::string langFlags; + this->AddFeatureFlags(langFlags, linkLanguage); + + vars.LanguageCompileFlags = langFlags.c_str(); + + std::string launcher; + const char* val = this->LocalGenerator->GetRuleLauncher( + this->GeneratorTarget, "RULE_LAUNCH_LINK"); + if (val && *val) { + launcher = val; + launcher += " "; + } + + CM_AUTO_PTR<cmRulePlaceholderExpander> rulePlaceholderExpander( + this->LocalGenerator->CreateRulePlaceholderExpander()); + + // Construct the main link rule and expand placeholders. + rulePlaceholderExpander->SetTargetImpLib(targetOutputReal); + std::string linkRule = this->GetLinkRule(linkRuleVar); + cmSystemTools::ExpandListArgument(linkRule, real_link_commands); + + // Expand placeholders. + for (std::vector<std::string>::iterator i = real_link_commands.begin(); + i != real_link_commands.end(); ++i) { + *i = launcher + *i; + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, *i, + vars); + } + // Restore path conversion to normal shells. + this->LocalGenerator->SetLinkScriptShell(false); + + // Clean all the possible library names and symlinks. + this->CleanFiles.insert(this->CleanFiles.end(), libCleanFiles.begin(), + libCleanFiles.end()); + } + + std::vector<std::string> commands1; + // Optionally convert the build rule to use a script to avoid long + // command lines in the make shell. + if (useLinkScript) { + // Use a link script. + const char* name = (relink ? "drelink.txt" : "dlink.txt"); + this->CreateLinkScript(name, real_link_commands, commands1, depends); + } else { + // No link script. Just use the link rule directly. + commands1 = real_link_commands; + } + this->LocalGenerator->CreateCDCommand( + commands1, this->Makefile->GetCurrentBinaryDirectory(), + this->LocalGenerator->GetBinaryDirectory()); + commands.insert(commands.end(), commands1.begin(), commands1.end()); + commands1.clear(); + + // Compute the list of outputs. + std::vector<std::string> outputs(1, targetOutputReal); + + // Write the build rule. + this->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, outputs, depends, + commands, false); + + // Write the main driver rule to build everything in this target. + this->WriteTargetDriverRule(targetOutputReal, relink); +#else + static_cast<void>(linkRuleVar); + static_cast<void>(extraFlags); + static_cast<void>(relink); +#endif +} + void cmMakefileLibraryTargetGenerator::WriteLibraryRules( const std::string& linkRuleVar, const std::string& extraFlags, bool relink) { @@ -240,6 +451,9 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Build list of dependencies. std::vector<std::string> depends; this->AppendLinkDepends(depends); + if (!this->DeviceLinkObject.empty()) { + depends.push_back(this->DeviceLinkObject); + } // Get the language to use for linking this library. std::string linkLanguage = @@ -518,6 +732,14 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( this->CreateObjectLists(useLinkScript, useArchiveRules, useResponseFileForObjects, buildObjs, depends, useWatcomQuote); + if (!this->DeviceLinkObject.empty()) { + buildObjs += " " + + this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), + this->DeviceLinkObject), + cmOutputConverter::SHELL); + } // maybe create .def file from list of objects if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY && diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h index dda41b8..93ce902 100644 --- a/Source/cmMakefileLibraryTargetGenerator.h +++ b/Source/cmMakefileLibraryTargetGenerator.h @@ -26,6 +26,9 @@ protected: void WriteStaticLibraryRules(); void WriteSharedLibraryRules(bool relink); void WriteModuleLibraryRules(bool relink); + + void WriteDeviceLibraryRules(const std::string& linkRule, + const std::string& extraFlags, bool relink); void WriteLibraryRules(const std::string& linkRule, const std::string& extraFlags, bool relink); // MacOSX Framework support methods @@ -33,6 +36,9 @@ protected: // Store the computd framework version for OS X Frameworks. std::string FrameworkVersion; + +private: + std::string DeviceLinkObject; }; #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5bec2bb..2e5173d 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -583,11 +583,11 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::string const includesString = "$(" + lang + "_INCLUDES)"; vars.Includes = includesString.c_str(); - // At the moment, it is assumed that C, C++, and Fortran have both + // At the moment, it is assumed that C, C++, Fortran, and CUDA have both // assembly and preprocessor capabilities. The same is true for the // ability to export compile commands - bool lang_has_preprocessor = - ((lang == "C") || (lang == "CXX") || (lang == "Fortran")); + bool lang_has_preprocessor = ((lang == "C") || (lang == "CXX") || + (lang == "Fortran") || (lang == "CUDA")); bool const lang_has_assembly = lang_has_preprocessor; bool const lang_can_export_cmds = lang_has_preprocessor; @@ -596,13 +596,22 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Construct the compile rules. { - std::string compileRuleVar = "CMAKE_"; - compileRuleVar += lang; - compileRuleVar += "_COMPILE_OBJECT"; - std::string compileRule = - this->Makefile->GetRequiredDefinition(compileRuleVar); std::vector<std::string> compileCommands; - cmSystemTools::ExpandListArgument(compileRule, compileCommands); + if (lang == "CUDA") { + std::string cmdVar; + if (this->GeneratorTarget->GetProperty("CUDA_SEPARABLE_COMPILATION")) { + cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION"); + } else { + cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION"); + } + std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar); + cmSystemTools::ExpandListArgument(compileRule, compileCommands); + } else { + const std::string cmdVar = + std::string("CMAKE_") + lang + "_COMPILE_OBJECT"; + std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar); + cmSystemTools::ExpandListArgument(compileRule, compileCommands); + } if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") && lang_can_export_cmds && compileCommands.size() == 1) { diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 3598914..6c5b2b2 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -18,6 +18,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" #include "cmLinkLineComputer.h" +#include "cmLinkLineDeviceComputer.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -47,6 +48,7 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator( , TargetNameImport() , TargetNamePDB() , TargetLinkLanguage("") + , DeviceLinkObject() { this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName()); if (target->GetType() == cmStateEnums::EXECUTABLE) { @@ -94,6 +96,9 @@ void cmNinjaNormalTargetGenerator::Generate() if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) { this->WriteObjectLibStatement(); } else { + // If this target has cuda language link inputs, and we need to do + // device linking + this->WriteDeviceLinkStatement(); this->WriteLinkStatement(); } } @@ -155,6 +160,14 @@ std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule() const this->GetGeneratorTarget()->GetName()); } +std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule() const +{ + return this->TargetLinkLanguage + "_" + + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) + + "_DEVICE_LINKER__" + cmGlobalNinjaGenerator::EncodeRuleName( + this->GetGeneratorTarget()->GetName()); +} + struct cmNinjaRemoveNoOpCommands { bool operator()(std::string const& cmd) @@ -163,6 +176,115 @@ struct cmNinjaRemoveNoOpCommands } }; +void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile) +{ + cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType(); + std::string ruleName = this->LanguageLinkerDeviceRule(); + // Select whether to use a response file for objects. + std::string rspfile; + std::string rspcontent; + + if (!this->GetGlobalGenerator()->HasRule(ruleName)) { + cmRulePlaceholderExpander::RuleVariables vars; + vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); + vars.CMTargetType = + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()); + + vars.Language = "CUDA"; + + std::string responseFlag; + if (!useResponseFile) { + vars.Objects = "$in"; + vars.LinkLibraries = "$LINK_LIBRARIES"; + } else { + std::string cmakeVarLang = "CMAKE_"; + cmakeVarLang += this->TargetLinkLanguage; + + // build response file name + std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG"; + const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar); + if (flag) { + responseFlag = flag; + } else { + responseFlag = "@"; + } + rspfile = "$RSP_FILE"; + responseFlag += rspfile; + + // build response file content + if (this->GetGlobalGenerator()->IsGCCOnWindows()) { + rspcontent = "$in"; + } else { + rspcontent = "$in_newline"; + } + rspcontent += " $LINK_LIBRARIES"; + vars.Objects = responseFlag.c_str(); + vars.LinkLibraries = ""; + } + + vars.ObjectDir = "$OBJECT_DIR"; + + vars.Target = "$TARGET_FILE"; + + vars.SONameFlag = "$SONAME_FLAG"; + vars.TargetSOName = "$SONAME"; + vars.TargetPDB = "$TARGET_PDB"; + + vars.Flags = "$FLAGS"; + vars.LinkFlags = "$LINK_FLAGS"; + vars.Manifests = "$MANIFESTS"; + + std::string langFlags; + if (targetType != cmStateEnums::EXECUTABLE) { + langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS"; + vars.LanguageCompileFlags = langFlags.c_str(); + } + + std::string launcher; + const char* val = this->GetLocalGenerator()->GetRuleLauncher( + this->GetGeneratorTarget(), "RULE_LAUNCH_LINK"); + if (val && *val) { + launcher = val; + launcher += " "; + } + + CM_AUTO_PTR<cmRulePlaceholderExpander> rulePlaceholderExpander( + this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + + // Rule for linking library/executable. + std::vector<std::string> linkCmds = this->ComputeDeviceLinkCmd(); + for (std::vector<std::string>::iterator i = linkCmds.begin(); + i != linkCmds.end(); ++i) { + *i = launcher + *i; + rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), + *i, vars); + } + { + // If there is no ranlib the command will be ":". Skip it. + std::vector<std::string>::iterator newEnd = std::remove_if( + linkCmds.begin(), linkCmds.end(), cmNinjaRemoveNoOpCommands()); + linkCmds.erase(newEnd, linkCmds.end()); + } + + std::string linkCmd = + this->GetLocalGenerator()->BuildCommandLine(linkCmds); + + // Write the linker rule with response file if needed. + std::ostringstream comment; + comment << "Rule for linking " << this->TargetLinkLanguage << " " + << this->GetVisibleTypeName() << "."; + std::ostringstream description; + description << "Linking " << this->TargetLinkLanguage << " " + << this->GetVisibleTypeName() << " $TARGET_FILE"; + this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(), + comment.str(), + /*depfile*/ "", + /*deptype*/ "", rspfile, rspcontent, + /*restat*/ "$RESTAT", + /*generator*/ false); + } +} + void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile) { cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType(); @@ -327,6 +449,32 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile) } } +std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd() +{ + std::vector<std::string> linkCmds; + + // this target requires separable cuda compilation + // now build the correct command depending on if the target is + // an executable or a dynamic library. + std::string linkCmd; + switch (this->GetGeneratorTarget()->GetType()) { + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: { + const std::string cudaLinkCmd( + this->GetMakefile()->GetDefinition("CMAKE_CUDA_DEVICE_LINK_LIBRARY")); + cmSystemTools::ExpandListArgument(cudaLinkCmd, linkCmds); + } break; + case cmStateEnums::EXECUTABLE: { + const std::string cudaLinkCmd(this->GetMakefile()->GetDefinition( + "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE")); + cmSystemTools::ExpandListArgument(cudaLinkCmd, linkCmds); + } break; + default: + break; + } + return linkCmds; +} + std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() { std::vector<std::string> linkCmds; @@ -421,6 +569,211 @@ static int calculateCommandLineLengthLimit(int linkRuleLength) return sz - linkRuleLength; } +void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() +{ + cmGeneratorTarget& genTarget = *this->GetGeneratorTarget(); + + // determine if we need to do any device linking for this target + const std::string cuda_lang("CUDA"); + cmGeneratorTarget::LinkClosure const* closure = + genTarget.GetLinkClosure(this->GetConfigName()); + + const bool hasCUDA = + (std::find(closure->Languages.begin(), closure->Languages.end(), + cuda_lang) != closure->Languages.end()); + + bool shouldHaveDeviceLinking = false; + switch (genTarget.GetType()) { + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + case cmStateEnums::EXECUTABLE: + shouldHaveDeviceLinking = true; + break; + default: + break; + } + + if (!shouldHaveDeviceLinking || !hasCUDA) { + return; + } + + // Now we can do device linking + + // First and very important step is to make sure while inside this + // step our link language is set to CUDA + std::string cudaLinkLanguage = "CUDA"; + + std::string const cfgName = this->GetConfigName(); + std::string const targetOutputReal = + ConvertToNinjaPath(genTarget.ObjectDirectory + "cmake_device_link.o"); + + std::string const targetOutputImplib = + ConvertToNinjaPath(genTarget.GetFullPath(cfgName, + /*implib=*/true)); + + this->DeviceLinkObject = targetOutputReal; + + // Write comments. + cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); + const cmStateEnums::TargetType targetType = genTarget.GetType(); + this->GetBuildFileStream() << "# Device Link build statements for " + << cmState::GetTargetTypeName(targetType) + << " target " << this->GetTargetName() << "\n\n"; + + // Compute the comment. + std::ostringstream comment; + comment << "Link the " << this->GetVisibleTypeName() << " " + << targetOutputReal; + + cmNinjaDeps emptyDeps; + cmNinjaVars vars; + + // Compute outputs. + cmNinjaDeps outputs; + outputs.push_back(targetOutputReal); + // Compute specific libraries to link with. + cmNinjaDeps explicitDeps = this->GetObjects(); + cmNinjaDeps implicitDeps = this->ComputeLinkDeps(); + + std::string frameworkPath; + std::string linkPath; + + std::string createRule = genTarget.GetCreateRuleVariable( + this->TargetLinkLanguage, this->GetConfigName()); + const bool useWatcomQuote = + this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE"); + cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator(); + + vars["TARGET_FILE"] = + localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL); + + CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer( + new cmNinjaLinkLineDeviceComputer( + this->GetLocalGenerator(), + this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(), + this->GetGlobalGenerator())); + linkLineComputer->SetUseWatcomQuote(useWatcomQuote); + + localGen.GetTargetFlags( + linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"], + vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget); + + this->addPoolNinjaVariable("JOB_POOL_LINK", &genTarget, vars); + + this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]); + vars["LINK_FLAGS"] = + cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]); + + vars["MANIFESTS"] = this->GetManifests(); + + vars["LINK_PATH"] = frameworkPath + linkPath; + + // Compute architecture specific link flags. Yes, these go into a different + // variable for executables, probably due to a mistake made when duplicating + // code between the Makefile executable and library generators. + if (targetType == cmStateEnums::EXECUTABLE) { + std::string t = vars["FLAGS"]; + localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName); + vars["FLAGS"] = t; + } else { + std::string t = vars["ARCH_FLAGS"]; + localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName); + vars["ARCH_FLAGS"] = t; + t = ""; + localGen.AddLanguageFlags(t, cudaLinkLanguage, cfgName); + vars["LANGUAGE_COMPILE_FLAGS"] = t; + } + if (this->GetGeneratorTarget()->HasSOName(cfgName)) { + vars["SONAME_FLAG"] = + this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage); + vars["SONAME"] = this->TargetNameSO; + if (targetType == cmStateEnums::SHARED_LIBRARY) { + std::string install_dir = + this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); + if (!install_dir.empty()) { + vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( + install_dir, cmOutputConverter::SHELL); + } + } + } + + cmNinjaDeps byproducts; + + if (!this->TargetNameImport.empty()) { + const std::string impLibPath = localGen.ConvertToOutputFormat( + targetOutputImplib, cmOutputConverter::SHELL); + vars["TARGET_IMPLIB"] = impLibPath; + EnsureParentDirectoryExists(impLibPath); + if (genTarget.HasImportLibrary()) { + byproducts.push_back(targetOutputImplib); + } + } + + const std::string objPath = GetGeneratorTarget()->GetSupportDirectory(); + vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( + this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); + EnsureDirectoryExists(objPath); + + if (this->GetGlobalGenerator()->IsGCCOnWindows()) { + // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) + std::string& linkLibraries = vars["LINK_LIBRARIES"]; + std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); + std::string& link_path = vars["LINK_PATH"]; + std::replace(link_path.begin(), link_path.end(), '\\', '/'); + } + + const std::vector<cmCustomCommand>* cmdLists[3] = { + &genTarget.GetPreBuildCommands(), &genTarget.GetPreLinkCommands(), + &genTarget.GetPostBuildCommands() + }; + + std::vector<std::string> preLinkCmdLines, postBuildCmdLines; + vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines); + vars["POST_BUILD"] = localGen.BuildCommandLine(postBuildCmdLines); + + std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines, + &preLinkCmdLines, + &postBuildCmdLines }; + + for (unsigned i = 0; i != 3; ++i) { + for (std::vector<cmCustomCommand>::const_iterator ci = + cmdLists[i]->begin(); + ci != cmdLists[i]->end(); ++ci) { + cmCustomCommandGenerator ccg(*ci, cfgName, this->GetLocalGenerator()); + localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]); + std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); + std::transform(ccByproducts.begin(), ccByproducts.end(), + std::back_inserter(byproducts), MapToNinjaPath()); + } + } + + cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator(); + + int commandLineLengthLimit = -1; + if (!this->ForceResponseFile()) { + commandLineLengthLimit = calculateCommandLineLengthLimit( + globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule())); + } + + const std::string rspfile = + std::string(cmake::GetCMakeFilesDirectoryPostSlash()) + + genTarget.GetName() + ".rsp"; + + // Gather order-only dependencies. + cmNinjaDeps orderOnlyDeps; + this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(), + orderOnlyDeps); + + // Write the build statement for this target. + bool usedResponseFile = false; + globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(), + this->LanguageLinkerDeviceRule(), outputs, + /*implicitOuts=*/cmNinjaDeps(), explicitDeps, + implicitDeps, orderOnlyDeps, vars, rspfile, + commandLineLengthLimit, &usedResponseFile); + this->WriteDeviceLinkRule(usedResponseFile); +} + void cmNinjaNormalTargetGenerator::WriteLinkStatement() { cmGeneratorTarget& gt = *this->GetGeneratorTarget(); @@ -481,6 +834,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() cmNinjaDeps explicitDeps = this->GetObjects(); cmNinjaDeps implicitDeps = this->ComputeLinkDeps(); + if (!this->DeviceLinkObject.empty()) { + explicitDeps.push_back(this->DeviceLinkObject); + } + cmMakefile* mf = this->GetMakefile(); std::string frameworkPath; @@ -504,6 +861,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() localGen.GetTargetFlags( linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"], vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget); + if (this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") && (gt.GetType() == cmStateEnums::SHARED_LIBRARY || gt.IsExecutableWithExports())) { diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h index 5bd906f..e5595ea 100644 --- a/Source/cmNinjaNormalTargetGenerator.h +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -22,12 +22,21 @@ public: private: std::string LanguageLinkerRule() const; + std::string LanguageLinkerDeviceRule() const; + const char* GetVisibleTypeName() const; void WriteLanguagesRules(); + void WriteLinkRule(bool useResponseFile); + void WriteDeviceLinkRule(bool useResponseFile); + void WriteLinkStatement(); + void WriteDeviceLinkStatement(); + void WriteObjectLibStatement(); + std::vector<std::string> ComputeLinkCmd(); + std::vector<std::string> ComputeDeviceLinkCmd(); private: // Target name info. @@ -37,6 +46,7 @@ private: std::string TargetNameImport; std::string TargetNamePDB; std::string TargetLinkLanguage; + std::string DeviceLinkObject; }; #endif // ! cmNinjaNormalTargetGenerator_h diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index a220cd8..e47de97 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -583,10 +583,22 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) } // Rule for compiling object file. - const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT"; - std::string compileCmd = mf->GetRequiredDefinition(cmdVar); std::vector<std::string> compileCmds; - cmSystemTools::ExpandListArgument(compileCmd, compileCmds); + if (lang == "CUDA") { + std::string cmdVar; + if (this->GeneratorTarget->GetProperty("CUDA_SEPARABLE_COMPILATION")) { + cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION"); + } else { + cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION"); + } + std::string compileCmd = mf->GetRequiredDefinition(cmdVar); + cmSystemTools::ExpandListArgument(compileCmd, compileCmds); + } else { + const std::string cmdVar = + std::string("CMAKE_") + lang + "_COMPILE_OBJECT"; + std::string compileCmd = mf->GetRequiredDefinition(cmdVar); + cmSystemTools::ExpandListArgument(compileCmd, compileCmds); + } // Maybe insert an include-what-you-use runner. if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index f5d9e61..ee4ff39 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -266,6 +266,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("CXX_STANDARD", CM_NULLPTR); this->SetPropertyDefault("CXX_STANDARD_REQUIRED", CM_NULLPTR); this->SetPropertyDefault("CXX_EXTENSIONS", CM_NULLPTR); + this->SetPropertyDefault("CUDA_STANDARD", CM_NULLPTR); + this->SetPropertyDefault("CUDA_STANDARD_REQUIRED", CM_NULLPTR); + this->SetPropertyDefault("CUDA_EXTENSIONS", CM_NULLPTR); this->SetPropertyDefault("LINK_SEARCH_START_STATIC", CM_NULLPTR); this->SetPropertyDefault("LINK_SEARCH_END_STATIC", CM_NULLPTR); } @@ -360,6 +363,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->GetType() != cmStateEnums::UTILITY) { this->SetPropertyDefault("C_VISIBILITY_PRESET", CM_NULLPTR); this->SetPropertyDefault("CXX_VISIBILITY_PRESET", CM_NULLPTR); + this->SetPropertyDefault("CUDA_VISIBILITY_PRESET", CM_NULLPTR); this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", CM_NULLPTR); } |