CUDA: Device linking use now link options

properties LINK_OPTIONS and INTERFACE_LINK_OPTIONS are propagated
to the device link step.

To control which options are selected for normal link and device link steps,
the $<DEVICE_LINK> and $<HOST_LINK> generator expressions can be used.

Fixes: #18265
This commit is contained in:
Marc Chevrier
2020-04-06 11:22:37 +02:00
parent ec48e023f6
commit 4248bb452a
33 changed files with 370 additions and 152 deletions

View File

@@ -0,0 +1,10 @@
When a device link step is involved, which is controlled by
:prop_tgt:`CUDA_SEPARABLE_COMPILATION` and
:prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties, the raw options will be
delivered to the host and device link steps (wrapped in ``-Xcompiler`` or
equivalent for device link). Options wrapped with ``$<DEVICE_LINK:...>``
:manual:`generator expression <cmake-generator-expressions(7)>` will be used
only for the device link step. Options wrapped with ``$<HOST_LINK:...>``
:manual:`generator expression <cmake-generator-expressions(7)>` will be used
only for the host link step.

View File

@@ -26,6 +26,8 @@ the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
manual for available expressions. See the :manual:`cmake-buildsystem(7)`
manual for more on defining buildsystem properties.
.. include:: DEVICE_LINK_OPTIONS.txt
.. include:: OPTIONS_SHELL.txt
.. include:: LINK_OPTIONS_LINKER.txt

View File

@@ -43,6 +43,8 @@ with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
manual for available expressions. See the :manual:`cmake-buildsystem(7)`
manual for more on defining buildsystem properties.
.. include:: DEVICE_LINK_OPTIONS.txt
.. include:: OPTIONS_SHELL.txt
.. include:: LINK_OPTIONS_LINKER.txt

View File

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.18
.. toctree::
:maxdepth: 1
CMP0105: Device link step uses the link options. </policy/CMP0105>
CMP0104: CMAKE_CUDA_ARCHITECTURES now detected for NVCC, empty CUDA_ARCHITECTURES not allowed. </policy/CMP0104>
CMP0103: Multiple export() with same FILE without APPEND is not allowed. </policy/CMP0103>

19
Help/policy/CMP0105.rst Normal file
View File

@@ -0,0 +1,19 @@
CMP0105
-------
:prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
properties are now used for the device link step.
In CMake 3.17 and below, link options are not used by the device link step.
The ``OLD`` behavior for this policy is to ignore the link options.
The ``NEW`` behavior of this policy is to use the link options during the
device link step.
This policy was introduced in CMake version 3.17. Use the
:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
Unlike many policies, CMake version |release| does *not* warn
when this policy is not set and simply uses ``OLD`` behavior.
.. include:: DEPRECATED.txt

View File

@@ -2,7 +2,7 @@ LINK_OPTIONS
------------
List of options to use for the link step of shared library, module
and executable targets.
and executable targets as well as the device link step.
This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
given so far to the :command:`add_link_options` command.

View File

@@ -2,12 +2,16 @@ LINK_OPTIONS
------------
List of options to use for the link step of shared library, module
and executable targets. Targets that are static libraries need to use
the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
and executable targets as well as the device link step. Targets that are static
libraries need to use the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
These options are used for both normal linking and device linking
(see policy :policy:`CMP0105`). To control link options for normal and device
link steps, ``$<HOST_LINK>`` and ``$<DEVICE_LINK>``
:manual:`generator expressions <cmake-generator-expressions(7)>` can be used.
This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
specified so far for its target. Use the :command:`target_link_options`
This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of
options specified so far for its target. Use the :command:`target_link_options`
command to append more options.
This property is initialized by the :prop_dir:`LINK_OPTIONS` directory

View File

@@ -0,0 +1,5 @@
device-link-options
-------------------
* the :prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
properties are now used for the device link step. See policy :policy:`CMP0105`.

View File

@@ -192,14 +192,13 @@ unset(__IMPLICT_DLINK_DIRS)
#These are used when linking relocatable (dc) cuda code
if(NOT CMAKE_CUDA_DEVICE_LINK_LIBRARY)
set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
endif()
if(NOT CMAKE_CUDA_DEVICE_LINK_EXECUTABLE)
set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
endif()
unset(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS)
unset(__IMPLICT_DLINK_FLAGS)
set(CMAKE_CUDA_INFORMATION_LOADED 1)

View File

@@ -54,6 +54,11 @@ elseif(CMAKE_CUDA_SIMULATE_ID STREQUAL "Clang")
set(CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP)
endif()
set(CMAKE_CUDA_DEVICE_COMPILER_WRAPPER_FLAG "-Xcompiler=")
set(CMAKE_CUDA_DEVICE_COMPILER_WRAPPER_FLAG_SEP ",")
set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG "-Xlinker=")
set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG_SEP ",")
set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "cudadevrt;cudart_static")
set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_SHARED "cudadevrt;cudart")

View File

@@ -46,9 +46,9 @@ endforeach()
unset(__IMPLICT_DLINK_DIRS)
set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
"<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
unset(__IMPLICT_DLINK_FLAGS)
string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}")

View File

@@ -21,6 +21,8 @@
#include "cmsys/RegularExpression.hxx"
#include "cm_static_string_view.hxx"
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
#include "cmCustomCommand.h"
@@ -3392,22 +3394,38 @@ enum class OptionsParse
};
namespace {
const auto DL_BEGIN = "<DEVICE_LINK>"_s;
const auto DL_END = "</DEVICE_LINK>"_s;
void processOptions(cmGeneratorTarget const* tgt,
std::vector<EvaluatedTargetPropertyEntry> const& entries,
std::vector<BT<std::string>>& options,
std::unordered_set<std::string>& uniqueOptions,
bool debugOptions, const char* logName, OptionsParse parse)
bool debugOptions, const char* logName, OptionsParse parse,
bool processDeviceOptions = false)
{
bool splitOption = !processDeviceOptions;
for (EvaluatedTargetPropertyEntry const& entry : entries) {
std::string usedOptions;
for (std::string const& opt : entry.Values) {
if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) {
options.emplace_back(opt, entry.Backtrace);
splitOption = opt == DL_BEGIN;
continue;
}
if (uniqueOptions.insert(opt).second) {
if (parse == OptionsParse::Shell &&
cmHasLiteralPrefix(opt, "SHELL:")) {
std::vector<std::string> tmp;
cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
for (std::string& o : tmp) {
options.emplace_back(std::move(o), entry.Backtrace);
if (splitOption) {
std::vector<std::string> tmp;
cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
for (std::string& o : tmp) {
options.emplace_back(std::move(o), entry.Backtrace);
}
} else {
options.emplace_back(std::string(opt.c_str() + 6),
entry.Backtrace);
}
} else {
options.emplace_back(opt, entry.Backtrace);
@@ -3426,6 +3444,63 @@ void processOptions(cmGeneratorTarget const* tgt,
}
}
}
std::vector<BT<std::string>> wrapOptions(
std::vector<std::string>& options, const cmListFileBacktrace& bt,
const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep,
bool concatFlagAndArgs)
{
std::vector<BT<std::string>> result;
if (options.empty()) {
return result;
}
if (wrapperFlag.empty() || cmHasLiteralPrefix(options.front(), "LINKER:")) {
// nothing specified or LINKER wrapper, insert elements as is
result.reserve(options.size());
for (std::string& o : options) {
result.emplace_back(std::move(o), bt);
}
} else {
if (!wrapperSep.empty()) {
if (concatFlagAndArgs) {
// insert flag elements except last one
for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
result.emplace_back(*i, bt);
}
// concatenate last flag element and all list values
// in one option
result.emplace_back(wrapperFlag.back() + cmJoin(options, wrapperSep),
bt);
} else {
for (std::string const& i : wrapperFlag) {
result.emplace_back(i, bt);
}
// concatenate all list values in one option
result.emplace_back(cmJoin(options, wrapperSep), bt);
}
} else {
// prefix each element of list with wrapper
if (concatFlagAndArgs) {
std::transform(options.begin(), options.end(), options.begin(),
[&wrapperFlag](std::string const& o) -> std::string {
return wrapperFlag.back() + o;
});
}
for (std::string& o : options) {
for (auto i = wrapperFlag.begin(),
e = concatFlagAndArgs ? wrapperFlag.end() - 1
: wrapperFlag.end();
i != e; ++i) {
result.emplace_back(*i, bt);
}
result.emplace_back(std::move(o), bt);
}
}
}
return result;
}
}
void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
@@ -3958,6 +4033,12 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
const std::string& config,
const std::string& language) const
{
if (this->IsDeviceLink() &&
this->GetPolicyStatusCMP0105() != cmPolicies::NEW) {
// link options are not propagated to the device link step
return;
}
std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language);
result.reserve(tmp.size());
for (BT<std::string>& v : tmp) {
@@ -3997,15 +4078,65 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
processOptions(this, entries, result, uniqueOptions, debugOptions,
"link options", OptionsParse::Shell);
"link options", OptionsParse::Shell, this->IsDeviceLink());
if (this->IsDeviceLink()) {
// wrap host link options
const std::string wrapper(this->Makefile->GetSafeDefinition(
"CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
const std::string wrapperSep(this->Makefile->GetSafeDefinition(
"CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
bool concatFlagAndArgs = true;
if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
concatFlagAndArgs = false;
wrapperFlag.pop_back();
}
auto it = result.begin();
while (it != result.end()) {
if (it->Value == DL_BEGIN) {
// device link options, no treatment
it = result.erase(it);
it = std::find_if(it, result.end(), [](const BT<std::string>& item) {
return item.Value == DL_END;
});
if (it != result.end()) {
it = result.erase(it);
}
} else {
// host link options must be wrapped
std::vector<std::string> options;
cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options);
auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag,
wrapperSep, concatFlagAndArgs);
it = result.erase(it);
// some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect
// C++11 standard: 'std::vector::insert()' do not returns an iterator,
// so need to recompute the iterator after insertion.
if (it == result.end()) {
cm::append(result, hostOptions);
it = result.end();
} else {
auto index = it - result.begin();
result.insert(it, hostOptions.begin(), hostOptions.end());
it = result.begin() + index + hostOptions.size();
}
}
}
}
// Last step: replace "LINKER:" prefixed elements by
// actual linker wrapper
const std::string wrapper(this->Makefile->GetSafeDefinition(
"CMAKE_" + language + "_LINKER_WRAPPER_FLAG"));
"CMAKE_" + language +
(this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
: "_LINKER_WRAPPER_FLAG")));
std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
const std::string wrapperSep(this->Makefile->GetSafeDefinition(
"CMAKE_" + language + "_LINKER_WRAPPER_FLAG_SEP"));
"CMAKE_" + language +
(this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
: "_LINKER_WRAPPER_FLAG_SEP")));
bool concatFlagAndArgs = true;
if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
concatFlagAndArgs = false;
@@ -4051,51 +4182,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
return result;
}
std::vector<BT<std::string>> options;
if (wrapperFlag.empty()) {
// nothing specified, insert elements as is
options.reserve(linkerOptions.size());
for (std::string& o : linkerOptions) {
options.emplace_back(std::move(o), bt);
}
} else {
if (!wrapperSep.empty()) {
if (concatFlagAndArgs) {
// insert flag elements except last one
for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
options.emplace_back(*i, bt);
}
// concatenate last flag element and all LINKER list values
// in one option
options.emplace_back(
wrapperFlag.back() + cmJoin(linkerOptions, wrapperSep), bt);
} else {
for (std::string const& i : wrapperFlag) {
options.emplace_back(i, bt);
}
// concatenate all LINKER list values in one option
options.emplace_back(cmJoin(linkerOptions, wrapperSep), bt);
}
} else {
// prefix each element of LINKER list with wrapper
if (concatFlagAndArgs) {
std::transform(linkerOptions.begin(), linkerOptions.end(),
linkerOptions.begin(),
[&wrapperFlag](std::string const& o) -> std::string {
return wrapperFlag.back() + o;
});
}
for (std::string& o : linkerOptions) {
for (auto i = wrapperFlag.begin(),
e = concatFlagAndArgs ? wrapperFlag.end() - 1
: wrapperFlag.end();
i != e; ++i) {
options.emplace_back(*i, bt);
}
options.emplace_back(std::move(o), bt);
}
}
}
std::vector<BT<std::string>> options = wrapOptions(
linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs);
result.insert(entry, options.begin(), options.end());
}
return result;
@@ -4651,9 +4739,9 @@ void cmGeneratorTarget::GetFullNameInternal(
outBase += this->GetOutputName(config, artifact);
// Append the per-configuration postfix.
// When using Xcode, the postfix should be part of the suffix rather than the
// base, because the suffix ends up being used in Xcode's EXECUTABLE_SUFFIX
// attribute.
// When using Xcode, the postfix should be part of the suffix rather than
// the base, because the suffix ends up being used in Xcode's
// EXECUTABLE_SUFFIX attribute.
if (this->IsFrameworkOnApple() &&
GetGlobalGenerator()->GetName() == "Xcode") {
targetSuffix = configPostfix.c_str();
@@ -5150,7 +5238,8 @@ void cmGeneratorTarget::CheckPropertyCompatibility(
std::ostringstream e;
e << "Property \"" << prop << "\" appears in both the " << propsString
<< " property in the dependencies of target \"" << this->GetName()
<< "\". This is not allowed. A property may only require compatibility "
<< "\". This is not allowed. A property may only require "
"compatibility "
"in a boolean interpretation, a numeric minimum, a numeric maximum "
"or a "
"string interpretation, but not a mixture.";
@@ -5800,8 +5889,9 @@ void cmGeneratorTarget::ExpandLinkItems(
// Keep this logic in sync with ComputeLinkImplementationLibraries.
cmGeneratorExpression ge;
cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
// The $<LINK_ONLY> expression may be in a link interface to specify private
// link dependencies that are otherwise excluded from usage requirements.
// The $<LINK_ONLY> expression may be in a link interface to specify
// private link dependencies that are otherwise excluded from usage
// requirements.
if (usage_requirements_only) {
dagChecker.SetTransitivePropertiesOnly();
}
@@ -5899,9 +5989,9 @@ void cmGeneratorTarget::ComputeLinkInterface(
}
} else {
// TODO: Recognize shared library file names. Perhaps this
// should be moved to cmComputeLinkInformation, but that creates
// a chicken-and-egg problem since this list is needed for its
// construction.
// should be moved to cmComputeLinkInformation, but that
// creates a chicken-and-egg problem since this list is needed
// for its construction.
}
}
}

View File

@@ -34,7 +34,6 @@
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmLinkLineComputer.h"
#include "cmLinkLineDeviceComputer.h"
#include "cmMakefile.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
@@ -1423,6 +1422,30 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags(
return flags;
}
void cmLocalGenerator::GetDeviceLinkFlags(
cmLinkLineComputer* linkLineComputer, const std::string& config,
std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath,
std::string& linkPath, cmGeneratorTarget* target)
{
cmGeneratorTarget::DeviceLinkSetter setter(*target);
cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
const std::string linkLanguage =
linkLineComputer->GetLinkerLanguage(target, config);
if (pcli) {
// Compute the required cuda device link libraries when
// resolving cuda device symbols
this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath,
linkPath);
}
std::vector<std::string> linkOpts;
target->GetLinkOptions(linkOpts, config, linkLanguage);
// LINK_OPTIONS are escaped.
this->AppendCompileOptions(linkFlags, linkOpts);
}
void cmLocalGenerator::GetTargetFlags(
cmLinkLineComputer* linkLineComputer, const std::string& config,
std::string& linkLibs, std::string& flags, std::string& linkFlags,
@@ -1455,12 +1478,6 @@ void cmLocalGenerator::GetTargetFlags(
switch (target->GetType()) {
case cmStateEnums::STATIC_LIBRARY:
linkFlags = this->GetStaticLibraryFlags(config, linkLanguage, target);
if (pcli && dynamic_cast<cmLinkLineDeviceComputer*>(linkLineComputer)) {
// Compute the required cuda device link libraries when
// resolving cuda device symbols
this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
frameworkPath, linkPath);
}
break;
case cmStateEnums::MODULE_LIBRARY:
libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
@@ -1827,10 +1844,10 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065(
"CMAKE_POLICY_WARNING_CMP0065")) {
std::ostringstream w;
/* clang-format off */
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n"
"For compatibility with older versions of CMake, "
"additional flags may be added to export symbols on all "
"executables regardless of their ENABLE_EXPORTS property.";
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n"
"For compatibility with older versions of CMake, "
"additional flags may be added to export symbols on all "
"executables regardless of their ENABLE_EXPORTS property.";
/* clang-format on */
this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
}
@@ -2033,7 +2050,6 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName,
if (name.empty()) {
return false;
}
if (cmSystemTools::GetFilenameLastExtension(name) == ".exe") {
name = cmSystemTools::GetFilenameWithoutLastExtension(name);
}

View File

@@ -421,6 +421,11 @@ public:
/** Fill out these strings for the given target. Libraries to link,
* flags, and linkflags. */
void GetDeviceLinkFlags(cmLinkLineComputer* linkLineComputer,
const std::string& config, std::string& linkLibs,
std::string& linkFlags, std::string& frameworkPath,
std::string& linkPath, cmGeneratorTarget* target);
void GetTargetFlags(cmLinkLineComputer* linkLineComputer,
const std::string& config, std::string& linkLibs,
std::string& flags, std::string& linkFlags,

View File

@@ -122,31 +122,15 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
}
// Build a list of compiler flags and linker flags.
std::string flags;
std::string langFlags;
std::string linkFlags;
// Add flags to create an executable.
// Add symbol export flags if necessary.
if (this->GeneratorTarget->IsExecutableWithExports()) {
std::string export_flag_var =
cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG");
this->LocalGenerator->AppendFlags(
linkFlags, this->Makefile->GetSafeDefinition(export_flag_var));
}
this->LocalGenerator->AppendFlags(linkFlags,
this->LocalGenerator->GetLinkLibsCMP0065(
linkLanguage, *this->GeneratorTarget));
// Add language feature flags.
this->LocalGenerator->AddLanguageFlagsForLinking(
flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
this->LocalGenerator->AddArchitectureFlags(
flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
// Add target-specific linker flags.
this->GetTargetLinkFlags(linkFlags, linkLanguage);
// Add device-specific linker flags.
this->GetDeviceLinkFlags(linkFlags, linkLanguage);
// Construct a list of files associated with this executable that
// may need to be cleaned.
@@ -226,7 +210,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
vars.ObjectDir = objectDir.c_str();
vars.Target = target.c_str();
vars.LinkLibraries = linkLibs.c_str();
vars.Flags = flags.c_str();
vars.LanguageCompileFlags = langFlags.c_str();
vars.LinkFlags = linkFlags.c_str();
vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();

View File

@@ -249,9 +249,14 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
std::vector<std::string> depends;
this->AppendLinkDepends(depends, linkLanguage);
// Add language-specific flags.
std::string langFlags;
this->LocalGenerator->AddLanguageFlagsForLinking(
langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
// Create set of linking flags.
std::string linkFlags;
this->GetTargetLinkFlags(linkFlags, linkLanguage);
this->GetDeviceLinkFlags(linkFlags, linkLanguage);
// Get the name of the device object to generate.
std::string const targetOutputReal =
@@ -344,16 +349,10 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
vars.Target = target.c_str();
vars.LinkLibraries = linkLibs.c_str();
vars.ObjectsQuoted = buildObjs.c_str();
vars.LanguageCompileFlags = langFlags.c_str();
vars.LinkFlags = linkFlags.c_str();
vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
// Add language-specific flags.
std::string langFlags;
this->LocalGenerator->AddLanguageFlagsForLinking(
langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
vars.LanguageCompileFlags = langFlags.c_str();
std::string launcher;
const char* val = this->LocalGenerator->GetRuleLauncher(
this->GeneratorTarget, "RULE_LAUNCH_LINK");

View File

@@ -87,6 +87,18 @@ std::string cmMakefileTargetGenerator::GetConfigName()
return configNames.front();
}
void cmMakefileTargetGenerator::GetDeviceLinkFlags(
std::string& linkFlags, const std::string& linkLanguage)
{
cmGeneratorTarget::DeviceLinkSetter setter(*this->GetGeneratorTarget());
std::vector<std::string> linkOpts;
this->GeneratorTarget->GetLinkOptions(linkOpts, this->GetConfigName(),
linkLanguage);
// LINK_OPTIONS are escaped.
this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
}
void cmMakefileTargetGenerator::GetTargetLinkFlags(
std::string& flags, const std::string& linkLanguage)
{

View File

@@ -60,6 +60,8 @@ public:
std::string GetConfigName();
protected:
void GetDeviceLinkFlags(std::string& linkFlags,
const std::string& linkLanguage);
void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage);
// create the file and directory etc

View File

@@ -233,11 +233,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(
vars.LinkFlags = "$LINK_FLAGS";
vars.Manifests = "$MANIFESTS";
std::string langFlags;
if (this->GetGeneratorTarget()->GetType() != cmStateEnums::EXECUTABLE) {
langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
vars.LanguageCompileFlags = langFlags.c_str();
}
vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS";
std::string launcher;
const char* val = this->GetLocalGenerator()->GetRuleLauncher(
@@ -590,8 +586,6 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
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";
@@ -677,9 +671,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig());
localGen.GetTargetFlags(
linkLineComputer.get(), config, vars["LINK_LIBRARIES"], vars["FLAGS"],
vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget);
localGen.GetDeviceLinkFlags(linkLineComputer.get(), config,
vars["LINK_LIBRARIES"], vars["LINK_FLAGS"],
frameworkPath, linkPath, genTarget);
this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
@@ -689,22 +683,12 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
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, config);
vars["FLAGS"] = t;
} else {
std::string t = vars["ARCH_FLAGS"];
localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config);
vars["ARCH_FLAGS"] = t;
t.clear();
localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage,
config);
vars["LANGUAGE_COMPILE_FLAGS"] = t;
}
// Compute language specific link flags.
std::string langFlags;
localGen.AddLanguageFlagsForLinking(langFlags, genTarget, cudaLinkLanguage,
config);
vars["LANGUAGE_COMPILE_FLAGS"] = langFlags;
auto const tgtNames = this->TargetNames(config);
if (genTarget->HasSOName(config)) {
vars["SONAME_FLAG"] =

View File

@@ -307,12 +307,14 @@ class cmMakefile;
"mark_as_advanced() does nothing if a cache entry does not exist.", \
3, 17, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0103, \
"multiple export() with same FILE without APPEND is not allowed.", \
"Multiple export() with same FILE without APPEND is not allowed.", \
3, 18, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0104, \
"CMAKE_CUDA_ARCHITECTURES now detected for NVCC, empty " \
"CUDA_ARCHITECTURES not allowed.", \
3, 18, 0, cmPolicies::WARN)
3, 18, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0105, "Device link step uses the link options.", 3, 18, \
0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -343,7 +345,8 @@ class cmMakefile;
F(CMP0083) \
F(CMP0095) \
F(CMP0099) \
F(CMP0104)
F(CMP0104) \
F(CMP0105)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies

View File

@@ -3184,6 +3184,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable());
Options& cudaLinkOptions = *pOptions;
cmGeneratorTarget::DeviceLinkSetter setter(*this->GeneratorTarget);
// Determine if we need to do a device link
const bool doDeviceLinking = requireDeviceLinking(
*this->GeneratorTarget, *this->LocalGenerator, configName);
@@ -3191,12 +3193,20 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
cudaLinkOptions.AddFlag("PerformDeviceLink",
doDeviceLinking ? "true" : "false");
// Suppress deprecation warnings for default GPU targets during device link.
if (cmSystemTools::VersionCompareGreaterEq(
this->GlobalGenerator->GetPlatformToolsetCudaString(), "8.0")) {
cudaLinkOptions.AppendFlagString("AdditionalOptions",
"-Wno-deprecated-gpu-targets");
}
// Add extra flags for device linking
cudaLinkOptions.AppendFlagString(
"AdditionalOptions",
this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_FLAGS"));
cudaLinkOptions.AppendFlagString(
"AdditionalOptions",
this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS"));
std::vector<std::string> linkOpts;
std::string linkFlags;
this->GeneratorTarget->GetLinkOptions(linkOpts, configName, "CUDA");
// LINK_OPTIONS are escaped.
this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
cudaLinkOptions.AppendFlagString("AdditionalOptions", linkFlags);
// For static libraries that have device linking enabled compute
// the libraries

View File

@@ -471,7 +471,8 @@ add_RunCMake_test(ExportWithoutLanguage)
add_RunCMake_test(target_link_directories)
add_RunCMake_test(target_link_libraries)
add_RunCMake_test(add_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMake_TEST_CUDA=${CMake_TEST_CUDA})
add_RunCMake_test(target_compile_definitions)
add_RunCMake_test(target_compile_features)

View File

@@ -30,6 +30,7 @@
\* CMP0095
\* CMP0099
\* CMP0104
\* CMP0105
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@@ -1,5 +1,5 @@
CMake Warning \(dev\) at Repeat.cmake:[0-9]+ \(export\):
Policy CMP0103 is not set: multiple export\(\) with same FILE without APPEND
Policy CMP0103 is not set: Multiple export\(\) with same FILE without APPEND
is not allowed. Run "cmake --help-policy CMP0103" for policy details. Use
the cmake_policy command to set the policy and suppress this warning.
@@ -14,7 +14,7 @@ Call Stack \(most recent call first\):
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning \(dev\) at Repeat/CMakeLists.txt:[0-9]+ \(export\):
Policy CMP0103 is not set: multiple export\(\) with same FILE without APPEND
Policy CMP0103 is not set: Multiple export\(\) with same FILE without APPEND
is not allowed. Run "cmake --help-policy CMP0103" for policy details. Use
the cmake_policy command to set the policy and suppress this warning.

View File

@@ -0,0 +1,14 @@
#include <cuda.h>
#ifdef _WIN32
__declspec(dllexport)
#endif
int simplelib()
{
return 0;
}
int main(void)
{
return simplelib();
}

View File

@@ -13,8 +13,9 @@ endmacro()
if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
# Intel compiler does not reject bad flags or objects!
set(RunCMake_TEST_OUTPUT_MERGE TRUE)
set(RunCMake_TEST_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
endif()
run_cmake(LINK_OPTIONS)
@@ -48,6 +49,13 @@ if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
run_cmake_target(genex_DEVICE_LINK interface LinkOptions_shared_interface --config Release)
run_cmake_target(genex_DEVICE_LINK private LinkOptions_private --config Release)
if (CMake_TEST_CUDA)
run_cmake_target(genex_DEVICE_LINK CMP0105_UNSET LinkOptions_CMP0105_UNSET --config Release)
run_cmake_target(genex_DEVICE_LINK CMP0105_OLD LinkOptions_CMP0105_OLD --config Release)
run_cmake_target(genex_DEVICE_LINK CMP0105_NEW LinkOptions_CMP0105_NEW --config Release)
run_cmake_target(genex_DEVICE_LINK device LinkOptions_device --config Release)
run_cmake_target(genex_DEVICE_LINK no_device LinkOptions_no_device --config Release)
endif()
unset(RunCMake_TEST_OPTIONS)
unset(RunCMake_TEST_OUTPUT_MERGE)

View File

@@ -0,0 +1,4 @@
if (NOT actual_stdout MATCHES "BADFLAG_DEVICE_LINK")
set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_DEVICE_LINK'.")
endif()

View File

@@ -0,0 +1,3 @@
set (DEVICE_LINK TRUE)
include ("${CMAKE_CURRENT_LIST_DIR}/genex_DEVICE_LINK-validation.cmake")

View File

@@ -0,0 +1,3 @@
set (DEVICE_LINK FALSE)
include ("${CMAKE_CURRENT_LIST_DIR}/genex_DEVICE_LINK-validation.cmake")

View File

@@ -17,3 +17,32 @@ target_link_libraries (LinkOptions_shared_interface PRIVATE LinkOptions_interfac
add_library(LinkOptions_private SHARED LinkOptionsLib.c)
target_link_options (LinkOptions_private PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>
$<HOST_LINK:${pre}BADFLAG_NORMAL_LINK${obj}>)
if (CMake_TEST_CUDA)
enable_language(CUDA)
add_executable(LinkOptions_CMP0105_UNSET LinkOptionsDevice.cu)
set_property(TARGET LinkOptions_CMP0105_UNSET PROPERTY CUDA_SEPARABLE_COMPILATION ON)
target_link_options(LinkOptions_CMP0105_UNSET PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>)
cmake_policy(SET CMP0105 OLD)
add_executable(LinkOptions_CMP0105_OLD LinkOptionsDevice.cu)
set_property(TARGET LinkOptions_CMP0105_OLD PROPERTY CUDA_SEPARABLE_COMPILATION ON)
target_link_options(LinkOptions_CMP0105_OLD PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>)
cmake_policy(SET CMP0105 NEW)
add_executable(LinkOptions_CMP0105_NEW LinkOptionsDevice.cu)
set_property(TARGET LinkOptions_CMP0105_NEW PROPERTY CUDA_SEPARABLE_COMPILATION ON)
target_link_options(LinkOptions_CMP0105_NEW PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>)
add_executable(LinkOptions_device LinkOptionsDevice.cu)
set_property(TARGET LinkOptions_device PROPERTY CUDA_SEPARABLE_COMPILATION ON)
target_link_options(LinkOptions_device PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>
$<HOST_LINK:${pre}BADFLAG_NORMAL_LINK${obj}>)
add_executable(LinkOptions_no_device LinkOptionsDevice.cu)
target_link_options(LinkOptions_no_device PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>
$<HOST_LINK:${pre}BADFLAG_NORMAL_LINK${obj}>)
endif()