Merge topic 'linker-user-selection'

96a953b1ed Add options to specify linker tool

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !8861
This commit is contained in:
Brad King
2023-10-16 14:39:38 +00:00
committed by Kitware Robot
59 changed files with 623 additions and 16 deletions
+16
View File
@@ -14,6 +14,7 @@
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
#include "cmArgumentParser.h"
#include "cmConfigureLog.h"
@@ -83,6 +84,7 @@ std::string const kCMAKE_HIP_PLATFORM = "CMAKE_HIP_PLATFORM";
std::string const kCMAKE_HIP_RUNTIME_LIBRARY = "CMAKE_HIP_RUNTIME_LIBRARY";
std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS";
std::string const kCMAKE_ISPC_HEADER_SUFFIX = "CMAKE_ISPC_HEADER_SUFFIX";
std::string const kCMAKE_LINKER_TYPE = "CMAKE_LINKER_TYPE";
std::string const kCMAKE_LINK_SEARCH_END_STATIC =
"CMAKE_LINK_SEARCH_END_STATIC";
std::string const kCMAKE_LINK_SEARCH_START_STATIC =
@@ -1114,6 +1116,20 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
vars.insert(varList.begin(), varList.end());
}
if (this->Makefile->GetDefinition(kCMAKE_LINKER_TYPE)) {
// propagate various variables to support linker selection
vars.insert(kCMAKE_LINKER_TYPE);
auto defs = this->Makefile->GetDefinitions();
cmsys::RegularExpression linkerTypeDef{
"^CMAKE_[A-Za-z]+_USING_LINKER_"
};
for (auto const& def : defs) {
if (linkerTypeDef.find(def)) {
vars.insert(def);
}
}
}
if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0083) ==
cmPolicies::NEW) {
// To ensure full support of PIE, propagate cache variables
+3 -2
View File
@@ -175,14 +175,15 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
cm::string_view property(this->Top()->Property);
return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s ||
property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s;
property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s ||
property == "LINKER_TYPE"_s;
}
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
{
cm::string_view property(this->Top()->Property);
return property == "LINK_OPTIONS"_s;
return property == "LINK_OPTIONS"_s || property == "LINKER_TYPE"_s;
}
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const
+69
View File
@@ -868,6 +868,31 @@ cmValue cmGeneratorTarget::GetFeature(const std::string& feature,
return this->LocalGenerator->GetFeature(feature, config);
}
std::string cmGeneratorTarget::GetLinkerTypeProperty(
std::string const& lang, std::string const& config) const
{
std::string propName{ "LINKER_TYPE" };
auto linkerType = this->GetProperty(propName);
if (!linkerType.IsEmpty()) {
cmGeneratorExpressionDAGChecker dagChecker(this, propName, nullptr,
nullptr);
auto ltype =
cmGeneratorExpression::Evaluate(*linkerType, this->GetLocalGenerator(),
config, this, &dagChecker, this, lang);
if (this->IsDeviceLink()) {
cmList list{ ltype };
const auto DL_BEGIN = "<DEVICE_LINK>"_s;
const auto DL_END = "</DEVICE_LINK>"_s;
cm::erase_if(list, [&](const std::string& item) {
return item == DL_BEGIN || item == DL_END;
});
return list.to_string();
}
return ltype;
}
return std::string{};
}
const char* cmGeneratorTarget::GetLinkPIEProperty(
const std::string& config) const
{
@@ -5515,6 +5540,50 @@ std::string cmGeneratorTarget::GetLinkerLanguage(
return this->GetLinkClosure(config)->LinkerLanguage;
}
std::string cmGeneratorTarget::GetLinkerTool(const std::string& config) const
{
return this->GetLinkerTool(this->GetLinkerLanguage(config), config);
}
std::string cmGeneratorTarget::GetLinkerTool(const std::string& lang,
const std::string& config) const
{
auto usingLinker =
cmStrCat("CMAKE_", lang, "_USING_", this->IsDeviceLink() ? "DEVICE_" : "",
"LINKER_");
auto format = this->Makefile->GetDefinition(cmStrCat(usingLinker, "MODE"));
if (!format || format != "TOOL"_s) {
return this->Makefile->GetDefinition("CMAKE_LINKER");
}
auto linkerType = this->GetLinkerTypeProperty(lang, config);
if (linkerType.empty()) {
linkerType = "DEFAULT";
}
usingLinker = cmStrCat(usingLinker, linkerType);
auto linkerTool = this->Makefile->GetDefinition(usingLinker);
if (!linkerTool) {
if (this->GetGlobalGenerator()->IsVisualStudio() &&
linkerType == "DEFAULT"_s) {
return std::string{};
}
// fall-back to generic definition
linkerTool = this->Makefile->GetDefinition("CMAKE_LINKER");
if (linkerType != "DEFAULT"_s) {
this->LocalGenerator->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("LINKER_TYPE '", linkerType,
"' is unknown. Did you forgot to define '", usingLinker,
"' variable?"));
}
}
return linkerTool;
}
std::string cmGeneratorTarget::GetPDBOutputName(
const std::string& config) const
{
+7
View File
@@ -205,6 +205,9 @@ public:
cmValue GetFeature(const std::string& feature,
const std::string& config) const;
std::string GetLinkerTypeProperty(std::string const& lang,
std::string const& config) const;
const char* GetLinkPIEProperty(const std::string& config) const;
bool IsIPOEnabled(std::string const& lang, std::string const& config) const;
@@ -788,6 +791,10 @@ public:
//! Return the preferred linker language for this target
std::string GetLinkerLanguage(const std::string& config) const;
//! Return the preferred linker tool for this target
std::string GetLinkerTool(const std::string& config) const;
std::string GetLinkerTool(const std::string& lang,
const std::string& config) const;
/** Does this target have a GNU implib to convert to MS format? */
bool HasImplibGNUtoMS(std::string const& config) const;
+13
View File
@@ -116,6 +116,19 @@ void cmGhsMultiTargetGenerator::Generate()
void cmGhsMultiTargetGenerator::GenerateTarget()
{
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE &&
!this->GeneratorTarget
->GetLinkerTypeProperty(
this->GeneratorTarget->GetLinkerLanguage(this->ConfigName),
this->ConfigName)
.empty()) {
// Green Hill MULTI does not support this feature.
cmSystemTools::Message(
cmStrCat("'LINKER_TYPE' property, specified on target '",
this->GeneratorTarget->GetName(),
"', is not supported by this generator."));
}
// Open the target file in copy-if-different mode.
std::string fproj =
cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+3
View File
@@ -2500,6 +2500,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
this->CurrentLocalGenerator->GetStaticLibraryFlags(
extraLinkOptions, configName, llang, gtgt);
} else {
this->CurrentLocalGenerator->AppendLinkerTypeFlags(extraLinkOptions, gtgt,
configName, llang);
cmValue targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
if (targetLinkFlags) {
this->CurrentLocalGenerator->AppendFlags(extraLinkOptions,
+44 -1
View File
@@ -82,7 +82,6 @@ static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
"CMAKE_CURRENT_SOURCE_DIR",
"CMAKE_CURRENT_BINARY_DIR",
"CMAKE_RANLIB",
"CMAKE_LINKER",
"CMAKE_MT",
"CMAKE_TAPI",
"CMAKE_CUDA_HOST_COMPILER",
@@ -1604,6 +1603,7 @@ void cmLocalGenerator::GetTargetFlags(
}
std::string extraLinkFlags;
this->AppendLinkerTypeFlags(extraLinkFlags, target, config, linkLanguage);
this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config,
linkLanguage);
this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage);
@@ -3200,6 +3200,49 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
}
}
void cmLocalGenerator::AppendLinkerTypeFlags(std::string& flags,
cmGeneratorTarget* target,
const std::string& config,
const std::string& linkLanguage)
{
switch (target->GetType()) {
case cmStateEnums::EXECUTABLE:
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
break;
default:
return;
}
auto usingLinker =
cmStrCat("CMAKE_", linkLanguage, "_USING_",
target->IsDeviceLink() ? "DEVICE_" : "", "LINKER_");
auto format = this->Makefile->GetDefinition(cmStrCat(usingLinker, "MODE"));
if (format && format != "FLAG"_s) {
return;
}
auto linkerType = target->GetLinkerTypeProperty(linkLanguage, config);
if (linkerType.empty()) {
linkerType = "DEFAULT";
}
usingLinker = cmStrCat(usingLinker, linkerType);
auto linkerTypeFlags = this->Makefile->GetDefinition(usingLinker);
if (linkerTypeFlags) {
if (!linkerTypeFlags.IsEmpty()) {
auto linkerFlags = cmExpandListWithBacktrace(linkerTypeFlags);
target->ResolveLinkerWrapper(linkerFlags, linkLanguage);
this->AppendFlags(flags, linkerFlags);
}
} else if (linkerType != "DEFAULT"_s) {
this->IssueMessage(MessageType::FATAL_ERROR,
cmStrCat("LINKER_TYPE '", linkerType,
"' is unknown. Did you forgot to define '",
usingLinker, "' variable?"));
}
}
void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
cmGeneratorTarget* target,
const std::string& config,
+3
View File
@@ -177,6 +177,9 @@ public:
void AddPchDependencies(cmGeneratorTarget* target);
void AddUnityBuild(cmGeneratorTarget* target);
virtual void AddXCConfigSources(cmGeneratorTarget* /* target */) {}
void AppendLinkerTypeFlags(std::string& flags, cmGeneratorTarget* target,
const std::string& config,
const std::string& linkLanguage);
void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,
const std::string& config,
const std::string& lang);
+21
View File
@@ -32,6 +32,7 @@
#include "cmList.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
#include "cmSourceFile.h"
@@ -1085,6 +1086,16 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
cmComputeLinkInformation& cli = *pcli;
std::string linkLanguage = cli.GetLinkLanguage();
if (!target->GetLinkerTypeProperty(linkLanguage, configName).empty()) {
// Visual Studio 10 or upper is required for this feature
this->GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("'LINKER_TYPE' property, specified on target '",
target->GetName(),
"', is not supported by this generator."),
target->GetBacktrace());
}
// Compute the variable name to lookup standard libraries for this
// language.
std::string standardLibsVar =
@@ -1161,6 +1172,16 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
cmComputeLinkInformation& cli = *pcli;
std::string linkLanguage = cli.GetLinkLanguage();
if (!target->GetLinkerTypeProperty(linkLanguage, configName).empty()) {
// Visual Studio 10 or upper is required for this feature
this->GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("'LINKER_TYPE' property, specified on target '",
target->GetName(),
"', is not supported by this generator."),
target->GetBacktrace());
}
bool isWin32Executable = target->IsWin32Executable(configName);
// Compute the variable name to lookup standard libraries for this
@@ -344,6 +344,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
return;
}
auto linker = this->GeneratorTarget->GetLinkerTool(this->GetConfigName());
// Build list of dependencies.
std::vector<std::string> depends;
this->AppendLinkDepends(depends, linkLanguage);
@@ -533,6 +535,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
vars.CMTargetType =
cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
vars.Language = linkLanguage.c_str();
vars.Linker = linker.c_str();
vars.AIXExports = aixExports.c_str();
vars.Objects = buildObjs.c_str();
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
@@ -441,6 +441,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
return;
}
auto linker = this->GeneratorTarget->GetLinkerTool(this->GetConfigName());
// Build list of dependencies.
std::vector<std::string> depends;
this->AppendLinkDepends(depends, linkLanguage);
@@ -766,6 +768,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
vars.CMTargetType =
cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
vars.Language = linkLanguage.c_str();
vars.Linker = linker.c_str();
vars.AIXExports = aixExports.c_str();
vars.Objects = buildObjs.c_str();
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
+2
View File
@@ -153,6 +153,8 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags(
this->LocalGenerator->AppendCompileOptions(flags, opts);
this->LocalGenerator->SetLinkScriptShell(false);
this->LocalGenerator->AppendLinkerTypeFlags(
flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
this->LocalGenerator->AppendPositionIndependentLinkerFlags(
flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
this->LocalGenerator->AppendDependencyInfoLinkerFlags(
+8
View File
@@ -294,6 +294,9 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule(
.c_str();
vars.Language = "CUDA";
std::string linker =
this->GetGeneratorTarget()->GetLinkerTool("CUDA", config);
vars.Linker = linker.c_str();
// build response file name
std::string responseFlag = this->GetMakefile()->GetSafeDefinition(
@@ -400,6 +403,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules(
vars.Fatbinary = "$FATBIN";
vars.RegisterFile = "$REGISTER";
vars.LinkFlags = "$LINK_FLAGS";
std::string linker =
this->GetGeneratorTarget()->GetLinkerTool("CUDA", config);
vars.Linker = linker.c_str();
std::string flags = this->GetFlags("CUDA", config);
vars.Flags = flags.c_str();
@@ -441,6 +447,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
std::string linker = this->GetGeneratorTarget()->GetLinkerTool(config);
vars.Linker = linker.c_str();
std::string lang = this->TargetLinkLanguage(config);
vars.Language = lang.c_str();
vars.AIXExports = "$AIX_EXPORTS";
+14 -11
View File
@@ -27,6 +27,19 @@ std::string cmRulePlaceholderExpander::ExpandVariable(
return this->ReplaceValues->LinkFlags;
}
}
if (this->ReplaceValues->Linker) {
if (variable == "CMAKE_LINKER") {
auto result = this->OutputConverter->ConvertToOutputForExisting(
this->ReplaceValues->Linker);
if (this->ReplaceValues->Launcher) {
// Add launcher as part of expansion so that it always appears
// immediately before the command itself, regardless of whether the
// overall rule template contains other content at the front.
result = cmStrCat(this->ReplaceValues->Launcher, " ", result);
}
return result;
}
}
if (this->ReplaceValues->Manifests) {
if (variable == "MANIFESTS") {
return this->ReplaceValues->Manifests;
@@ -325,17 +338,7 @@ std::string cmRulePlaceholderExpander::ExpandVariable(
auto mapIt = this->VariableMappings.find(variable);
if (mapIt != this->VariableMappings.end()) {
if (variable.find("_FLAG") == std::string::npos) {
std::string ret =
this->OutputConverter->ConvertToOutputForExisting(mapIt->second);
if (this->ReplaceValues->Launcher && variable == "CMAKE_LINKER") {
// Add launcher as part of expansion so that it always appears
// immediately before the command itself, regardless of whether the
// overall rule template contains other content at the front.
ret = cmStrCat(this->ReplaceValues->Launcher, " ", ret);
}
return ret;
return this->OutputConverter->ConvertToOutputForExisting(mapIt->second);
}
return mapIt->second;
}
+1
View File
@@ -53,6 +53,7 @@ public:
const char* SONameFlag = nullptr;
const char* TargetSOName = nullptr;
const char* TargetInstallNameDir = nullptr;
const char* Linker = nullptr;
const char* LinkFlags = nullptr;
const char* Manifests = nullptr;
const char* LanguageCompileFlags = nullptr;
+1
View File
@@ -456,6 +456,7 @@ TargetProperty const StaticTargetProperties[] = {
{ "AUTORCC_EXECUTABLE"_s, IC::CanCompileSources },
// Linking properties
{ "LINKER_TYPE"_s, IC::CanCompileSources },
{ "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports },
{ "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget },
{ "LINK_SEARCH_START_STATIC"_s, IC::CanCompileSources },
@@ -2987,6 +2987,16 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
e1.WritePlatformConfigTag(
"IntDir", cond, R"($(Platform)\$(Configuration)\$(ProjectName)\)");
} else {
if (ttype == cmStateEnums::SHARED_LIBRARY ||
ttype == cmStateEnums::MODULE_LIBRARY ||
ttype == cmStateEnums::EXECUTABLE) {
auto linker = this->GeneratorTarget->GetLinkerTool(config);
if (!linker.empty()) {
ConvertToWindowsSlash(linker);
e1.WritePlatformConfigTag("LinkToolExe", cond, linker);
}
}
std::string intermediateDir = cmStrCat(
this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/',
config, '/');