|
|
@@ -102,6 +102,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
|
|
|
, DebugCompileOptionsDone(false)
|
|
|
, DebugCompileFeaturesDone(false)
|
|
|
, DebugCompileDefinitionsDone(false)
|
|
|
+ , DebugLinkOptionsDone(false)
|
|
|
, DebugSourcesDone(false)
|
|
|
, LinkImplementationLanguageIsContextDependent(true)
|
|
|
, UtilityItemsDone(false)
|
|
|
@@ -128,6 +129,10 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
|
|
|
t->GetCompileDefinitionsBacktraces(),
|
|
|
this->CompileDefinitionsEntries);
|
|
|
|
|
|
+ CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
|
|
|
+ t->GetLinkOptionsBacktraces(),
|
|
|
+ this->LinkOptionsEntries);
|
|
|
+
|
|
|
CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
|
|
|
t->GetSourceBacktraces(),
|
|
|
this->SourceEntries, true);
|
|
|
@@ -145,6 +150,7 @@ cmGeneratorTarget::~cmGeneratorTarget()
|
|
|
cmDeleteAll(this->CompileOptionsEntries);
|
|
|
cmDeleteAll(this->CompileFeaturesEntries);
|
|
|
cmDeleteAll(this->CompileDefinitionsEntries);
|
|
|
+ cmDeleteAll(this->LinkOptionsEntries);
|
|
|
cmDeleteAll(this->SourceEntries);
|
|
|
cmDeleteAll(this->LinkInformation);
|
|
|
}
|
|
|
@@ -2633,7 +2639,7 @@ enum class OptionsParse
|
|
|
Shell
|
|
|
};
|
|
|
|
|
|
-static void processCompileOptionsInternal(
|
|
|
+static void processOptionsInternal(
|
|
|
cmGeneratorTarget const* tgt,
|
|
|
const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
|
|
|
std::vector<std::string>& options,
|
|
|
@@ -2665,7 +2671,7 @@ static void processCompileOptionsInternal(
|
|
|
if (!usedOptions.empty()) {
|
|
|
tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
|
|
|
cmake::LOG,
|
|
|
- std::string("Used compile ") + logName + std::string(" for target ") +
|
|
|
+ std::string("Used ") + logName + std::string(" for target ") +
|
|
|
tgt->GetName() + ":\n" + usedOptions,
|
|
|
entry->ge->GetBacktrace());
|
|
|
}
|
|
|
@@ -2680,9 +2686,9 @@ static void processCompileOptions(
|
|
|
cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
|
|
|
bool debugOptions, std::string const& language)
|
|
|
{
|
|
|
- processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
|
|
|
- dagChecker, config, debugOptions, "options",
|
|
|
- language, OptionsParse::Shell);
|
|
|
+ processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
|
|
|
+ config, debugOptions, "compile options", language,
|
|
|
+ OptionsParse::Shell);
|
|
|
}
|
|
|
|
|
|
void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
|
|
|
@@ -2734,9 +2740,9 @@ static void processCompileFeatures(
|
|
|
cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
|
|
|
bool debugOptions)
|
|
|
{
|
|
|
- processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
|
|
|
- dagChecker, config, debugOptions, "features",
|
|
|
- std::string(), OptionsParse::None);
|
|
|
+ processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
|
|
|
+ config, debugOptions, "compile features",
|
|
|
+ std::string(), OptionsParse::None);
|
|
|
}
|
|
|
|
|
|
void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
|
|
|
@@ -2784,9 +2790,9 @@ static void processCompileDefinitions(
|
|
|
cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
|
|
|
bool debugOptions, std::string const& language)
|
|
|
{
|
|
|
- processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
|
|
|
- dagChecker, config, debugOptions,
|
|
|
- "definitions", language, OptionsParse::None);
|
|
|
+ processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
|
|
|
+ config, debugOptions, "compile definitions", language,
|
|
|
+ OptionsParse::None);
|
|
|
}
|
|
|
|
|
|
void cmGeneratorTarget::GetCompileDefinitions(
|
|
|
@@ -2855,6 +2861,153 @@ void cmGeneratorTarget::GetCompileDefinitions(
|
|
|
cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
|
|
|
}
|
|
|
|
|
|
+namespace {
|
|
|
+void processLinkOptions(
|
|
|
+ cmGeneratorTarget const* tgt,
|
|
|
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
|
|
|
+ std::vector<std::string>& options,
|
|
|
+ std::unordered_set<std::string>& uniqueOptions,
|
|
|
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
|
|
|
+ bool debugOptions, std::string const& language)
|
|
|
+{
|
|
|
+ processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
|
|
|
+ config, debugOptions, "link options", language,
|
|
|
+ OptionsParse::Shell);
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
|
|
|
+ const std::string& config,
|
|
|
+ const std::string& language) const
|
|
|
+{
|
|
|
+ std::unordered_set<std::string> uniqueOptions;
|
|
|
+
|
|
|
+ cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), "LINK_OPTIONS",
|
|
|
+ nullptr, nullptr);
|
|
|
+
|
|
|
+ std::vector<std::string> debugProperties;
|
|
|
+ const char* debugProp =
|
|
|
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
|
|
|
+ if (debugProp) {
|
|
|
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool debugOptions = !this->DebugLinkOptionsDone &&
|
|
|
+ std::find(debugProperties.begin(), debugProperties.end(),
|
|
|
+ "LINK_OPTIONS") != debugProperties.end();
|
|
|
+
|
|
|
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
|
|
|
+ this->DebugLinkOptionsDone = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ processLinkOptions(this, this->LinkOptionsEntries, result, uniqueOptions,
|
|
|
+ &dagChecker, config, debugOptions, language);
|
|
|
+
|
|
|
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
|
|
|
+ linkInterfaceLinkOptionsEntries;
|
|
|
+
|
|
|
+ AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS",
|
|
|
+ linkInterfaceLinkOptionsEntries);
|
|
|
+
|
|
|
+ processLinkOptions(this, linkInterfaceLinkOptionsEntries, result,
|
|
|
+ uniqueOptions, &dagChecker, config, debugOptions,
|
|
|
+ language);
|
|
|
+
|
|
|
+ cmDeleteAll(linkInterfaceLinkOptionsEntries);
|
|
|
+
|
|
|
+ // Last step: replace "LINKER:" prefixed elements by
|
|
|
+ // actual linker wrapper
|
|
|
+ const std::string wrapper(this->Makefile->GetSafeDefinition(
|
|
|
+ "CMAKE_" + language + "_LINKER_WRAPPER_FLAG"));
|
|
|
+ std::vector<std::string> wrapperFlag;
|
|
|
+ cmSystemTools::ExpandListArgument(wrapper, wrapperFlag);
|
|
|
+ const std::string wrapperSep(this->Makefile->GetSafeDefinition(
|
|
|
+ "CMAKE_" + language + "_LINKER_WRAPPER_FLAG_SEP"));
|
|
|
+ bool concatFlagAndArgs = true;
|
|
|
+ if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
|
|
|
+ concatFlagAndArgs = false;
|
|
|
+ wrapperFlag.pop_back();
|
|
|
+ }
|
|
|
+
|
|
|
+ const std::string LINKER{ "LINKER:" };
|
|
|
+ const std::string SHELL{ "SHELL:" };
|
|
|
+ const std::string LINKER_SHELL = LINKER + SHELL;
|
|
|
+
|
|
|
+ std::vector<std::string>::iterator entry;
|
|
|
+ while ((entry = std::find_if(result.begin(), result.end(),
|
|
|
+ [&LINKER](const std::string& item) -> bool {
|
|
|
+ return item.compare(0, LINKER.length(),
|
|
|
+ LINKER) == 0;
|
|
|
+ })) != result.end()) {
|
|
|
+ std::vector<std::string> linkerOptions;
|
|
|
+ if (entry->compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
|
|
|
+ cmSystemTools::ParseUnixCommandLine(
|
|
|
+ entry->c_str() + LINKER_SHELL.length(), linkerOptions);
|
|
|
+ } else {
|
|
|
+ linkerOptions =
|
|
|
+ cmSystemTools::tokenize(entry->substr(LINKER.length()), ",");
|
|
|
+ }
|
|
|
+ entry = result.erase(entry);
|
|
|
+
|
|
|
+ if (linkerOptions.empty() ||
|
|
|
+ (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // for now, raise an error if prefix SHELL: is part of arguments
|
|
|
+ if (std::find_if(linkerOptions.begin(), linkerOptions.end(),
|
|
|
+ [&SHELL](const std::string& item) -> bool {
|
|
|
+ return item.find(SHELL) != std::string::npos;
|
|
|
+ }) != linkerOptions.end()) {
|
|
|
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
|
|
|
+ cmake::FATAL_ERROR,
|
|
|
+ "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
|
|
|
+ this->GetBacktrace());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wrapperFlag.empty()) {
|
|
|
+ // nothing specified, insert elements as is
|
|
|
+ result.insert(entry, linkerOptions.begin(), linkerOptions.end());
|
|
|
+ } else {
|
|
|
+ std::vector<std::string> options;
|
|
|
+
|
|
|
+ if (!wrapperSep.empty()) {
|
|
|
+ if (concatFlagAndArgs) {
|
|
|
+ // insert flag elements except last one
|
|
|
+ options.insert(options.end(), wrapperFlag.begin(),
|
|
|
+ wrapperFlag.end() - 1);
|
|
|
+ // concatenate last flag element and all LINKER list values
|
|
|
+ // in one option
|
|
|
+ options.push_back(wrapperFlag.back() +
|
|
|
+ cmJoin(linkerOptions, wrapperSep));
|
|
|
+ } else {
|
|
|
+ options.insert(options.end(), wrapperFlag.begin(),
|
|
|
+ wrapperFlag.end());
|
|
|
+ // concatenate all LINKER list values in one option
|
|
|
+ options.push_back(cmJoin(linkerOptions, wrapperSep));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // prefix each element of LINKER list with wrapper
|
|
|
+ if (concatFlagAndArgs) {
|
|
|
+ std::transform(
|
|
|
+ linkerOptions.begin(), linkerOptions.end(), linkerOptions.begin(),
|
|
|
+ [&wrapperFlag](const std::string& value) -> std::string {
|
|
|
+ return wrapperFlag.back() + value;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ for (const auto& value : linkerOptions) {
|
|
|
+ options.insert(options.end(), wrapperFlag.begin(),
|
|
|
+ concatFlagAndArgs ? wrapperFlag.end() - 1
|
|
|
+ : wrapperFlag.end());
|
|
|
+ options.push_back(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result.insert(entry, options.begin(), options.end());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
|
|
|
{
|
|
|
if (this->IsImported()) {
|