Browse Source

CUDA: Add separable compilation support to the makefile generator.

pull/162/merge
Robert Maynard 9 years ago
committed by Brad King
parent
commit
d038559e49
  1. 227
      Source/cmMakefileExecutableTargetGenerator.cxx
  2. 4
      Source/cmMakefileExecutableTargetGenerator.h
  3. 222
      Source/cmMakefileLibraryTargetGenerator.cxx
  4. 6
      Source/cmMakefileLibraryTargetGenerator.h

227
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() &&

4
Source/cmMakefileExecutableTargetGenerator.h

@ -21,6 +21,10 @@ public:
protected:
virtual void WriteExecutableRule(bool relink);
virtual void WriteDeviceExecutableRule(bool relink);
private:
std::string DeviceLinkObject;
};
#endif

222
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 &&

6
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
Loading…
Cancel
Save