cmake/Source/cmLinkLineDeviceComputer.cxx

217 lines
6.9 KiB
C++
Raw Normal View History

2017-04-14 19:02:05 +02:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLinkLineDeviceComputer.h"
2017-07-20 19:35:53 +02:00
2021-09-14 00:13:48 +02:00
#include <algorithm>
2018-10-28 12:09:07 +01:00
#include <set>
#include <utility>
2017-07-20 19:35:53 +02:00
2020-08-30 11:54:41 +02:00
#include <cmext/algorithm>
2017-04-14 19:02:05 +02:00
#include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h"
2019-11-11 23:01:05 +01:00
#include "cmGlobalGenerator.h"
2020-02-01 23:06:01 +01:00
#include "cmLinkItem.h"
#include "cmListFileCache.h"
2019-11-11 23:01:05 +01:00
#include "cmLocalGenerator.h"
2020-02-01 23:06:01 +01:00
#include "cmMakefile.h"
2020-08-30 11:54:41 +02:00
#include "cmProperty.h"
2019-11-11 23:01:05 +01:00
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
2017-07-20 19:35:53 +02:00
#include "cmStateTypes.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
2017-07-20 19:35:53 +02:00
class cmOutputConverter;
2017-04-14 19:02:05 +02:00
cmLinkLineDeviceComputer::cmLinkLineDeviceComputer(
2017-07-20 19:35:53 +02:00
cmOutputConverter* outputConverter, cmStateDirectory const& stateDir)
2017-04-14 19:02:05 +02:00
: cmLinkLineComputer(outputConverter, stateDir)
{
}
2019-11-11 23:01:05 +01:00
cmLinkLineDeviceComputer::~cmLinkLineDeviceComputer() = default;
2017-04-14 19:02:05 +02:00
2018-10-28 12:09:07 +01:00
static bool cmLinkItemValidForDevice(std::string const& item)
{
// Valid items are:
// * Non-flags (does not start in '-')
// * Specific flags --library, --library-path, -l, -L
// For example:
// * 'cublas_device' => pass-along
// * '--library pthread' => pass-along
// * '-lpthread' => pass-along
// * '-pthread' => drop
// * '-a' => drop
2019-11-11 23:01:05 +01:00
// * '-framework Name' (as one string) => drop
2018-10-28 12:09:07 +01:00
return (!cmHasLiteralPrefix(item, "-") || //
cmHasLiteralPrefix(item, "-l") || //
cmHasLiteralPrefix(item, "-L") || //
cmHasLiteralPrefix(item, "--library"));
}
2019-11-11 23:01:05 +01:00
bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
cmComputeLinkInformation& cli)
{
// Determine if this item might requires device linking.
// For this we only consider targets
2020-02-01 23:06:01 +01:00
using ItemVector = cmComputeLinkInformation::ItemVector;
2019-11-11 23:01:05 +01:00
ItemVector const& items = cli.GetItems();
std::string config = cli.GetConfig();
2021-09-14 00:13:48 +02:00
return std::any_of(
items.begin(), items.end(),
[](cmComputeLinkInformation::Item const& item) -> bool {
return item.Target &&
item.Target->GetType() == cmStateEnums::STATIC_LIBRARY &&
2019-11-11 23:01:05 +01:00
// this dependency requires us to device link it
2021-09-14 00:13:48 +02:00
!item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS") &&
item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION");
});
2019-11-11 23:01:05 +01:00
}
2020-02-01 23:06:01 +01:00
void cmLinkLineDeviceComputer::ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString,
std::vector<BT<std::string>>& linkLibraries)
2017-04-14 19:02:05 +02:00
{
2018-10-28 12:09:07 +01:00
// Generate the unique set of link items when device linking.
// The nvcc device linker is designed so that each static library
// with device symbols only needs to be listed once as it doesn't
// care about link order.
std::set<std::string> emitted;
2020-02-01 23:06:01 +01:00
using ItemVector = cmComputeLinkInformation::ItemVector;
2017-04-14 19:02:05 +02:00
ItemVector const& items = cli.GetItems();
std::string config = cli.GetConfig();
2019-11-11 23:01:05 +01:00
bool skipItemAfterFramework = false;
2020-02-01 23:06:01 +01:00
// Note:
// Any modification of this algorithm should be reflected also in
// cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions
2018-01-26 17:06:56 +01:00
for (auto const& item : items) {
2019-11-11 23:01:05 +01:00
if (skipItemAfterFramework) {
skipItemAfterFramework = false;
continue;
}
2018-08-09 18:06:22 +02:00
if (item.Target) {
bool skip = false;
switch (item.Target->GetType()) {
2020-02-01 23:06:01 +01:00
case cmStateEnums::SHARED_LIBRARY:
2018-08-09 18:06:22 +02:00
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::INTERFACE_LIBRARY:
skip = true;
break;
case cmStateEnums::STATIC_LIBRARY:
skip = item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS");
break;
default:
break;
}
if (skip) {
continue;
}
2017-04-14 19:02:05 +02:00
}
2020-02-01 23:06:01 +01:00
BT<std::string> linkLib;
2021-09-14 00:13:48 +02:00
if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
2018-11-29 20:27:00 +01:00
// nvcc understands absolute paths to libraries ending in '.a' or '.lib'.
// These should be passed to nvlink. Other extensions need to be left
// out because nvlink may not understand or need them. Even though it
// can tolerate '.so' or '.dylib' it cannot tolerate '.so.1'.
2020-08-30 11:54:41 +02:00
if (cmHasLiteralSuffix(item.Value.Value, ".a") ||
cmHasLiteralSuffix(item.Value.Value, ".lib")) {
2020-02-01 23:06:01 +01:00
linkLib.Value += this->ConvertToOutputFormat(
2020-08-30 11:54:41 +02:00
this->ConvertToLinkReference(item.Value.Value));
2018-08-09 18:06:22 +02:00
}
2019-11-11 23:01:05 +01:00
} else if (item.Value == "-framework") {
// This is the first part of '-framework Name' where the framework
// name is specified as a following item. Ignore both.
skipItemAfterFramework = true;
continue;
2020-08-30 11:54:41 +02:00
} else if (cmLinkItemValidForDevice(item.Value.Value)) {
linkLib.Value += item.Value.Value;
2018-10-28 12:09:07 +01:00
}
2020-02-01 23:06:01 +01:00
if (emitted.insert(linkLib.Value).second) {
linkLib.Value += " ";
const cmLinkImplementation* linkImpl =
cli.GetTarget()->GetLinkImplementation(cli.GetConfig());
for (const cmLinkImplItem& iter : linkImpl->Libraries) {
if (iter.Target != nullptr &&
iter.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
std::string libPath = iter.Target->GetLocation(cli.GetConfig());
if (item.Value == libPath) {
linkLib.Backtrace = iter.Backtrace;
break;
}
}
}
linkLibraries.emplace_back(linkLib);
2017-04-14 19:02:05 +02:00
}
}
if (!stdLibString.empty()) {
2020-02-01 23:06:01 +01:00
linkLibraries.emplace_back(cmStrCat(stdLibString, ' '));
2017-04-14 19:02:05 +02:00
}
}
std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*,
std::string const&)
{
return "CUDA";
}
2019-11-11 23:01:05 +01:00
bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
const std::string& config)
2017-04-14 19:02:05 +02:00
{
2019-11-11 23:01:05 +01:00
if (!target.GetGlobalGenerator()->GetLanguageEnabled("CUDA")) {
return false;
}
2017-04-14 19:02:05 +02:00
2019-11-11 23:01:05 +01:00
if (target.GetType() == cmStateEnums::OBJECT_LIBRARY) {
return false;
}
2020-02-01 23:06:01 +01:00
if (!lg.GetMakefile()->IsOn("CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE")) {
return false;
}
2020-08-30 11:54:41 +02:00
if (cmProp resolveDeviceSymbols =
2019-11-11 23:01:05 +01:00
target.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
// If CUDA_RESOLVE_DEVICE_SYMBOLS has been explicitly set we need
// to honor the value no matter what it is.
2020-08-30 11:54:41 +02:00
return cmIsOn(*resolveDeviceSymbols);
2019-11-11 23:01:05 +01:00
}
// Determine if we have any dependencies that require
// us to do a device link step
cmGeneratorTarget::LinkClosure const* closure =
target.GetLinkClosure(config);
2020-08-30 11:54:41 +02:00
if (cm::contains(closure->Languages, "CUDA")) {
2021-09-14 00:13:48 +02:00
if (cmIsOn(target.GetProperty("CUDA_SEPARABLE_COMPILATION"))) {
bool doDeviceLinking = false;
switch (target.GetType()) {
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::EXECUTABLE:
doDeviceLinking = true;
break;
default:
break;
2020-02-01 23:06:01 +01:00
}
2021-09-14 00:13:48 +02:00
return doDeviceLinking;
2020-02-01 23:06:01 +01:00
}
2019-11-11 23:01:05 +01:00
cmComputeLinkInformation* pcli = target.GetLinkInformation(config);
if (pcli) {
cmLinkLineDeviceComputer deviceLinkComputer(
&lg, lg.GetStateSnapshot().GetDirectory());
return deviceLinkComputer.ComputeRequiresDeviceLinking(*pcli);
}
return true;
}
return false;
2017-04-14 19:02:05 +02:00
}