diff options
author | Marc Chevrier <marc.chevrier@gmail.com> | 2018-04-24 15:01:01 (GMT) |
---|---|---|
committer | Marc Chevrier <marc.chevrier@gmail.com> | 2018-06-06 15:22:39 (GMT) |
commit | c1f5a44b28047cde74e2fb10e8d68e314272f699 (patch) | |
tree | 6124b73331c13c92480b5352045686758d3df86f /Source | |
parent | 8e28d2630a60475dad715162a1802d301ada35bd (diff) | |
download | CMake-c1f5a44b28047cde74e2fb10e8d68e314272f699.zip CMake-c1f5a44b28047cde74e2fb10e8d68e314272f699.tar.gz CMake-c1f5a44b28047cde74e2fb10e8d68e314272f699.tar.bz2 |
LINK_OPTIONS: Add new family of properties
This family enable to manage link flags
Three new properties:
* directory property: LINK_OPTIONS
* target properties: LINK_OPTIONS and INTERFACE_LINK_OPTIONS
Two new commands
* add_link_options(): to populate directory property
* target_link_options(): to populate target properties
Fixes: #16543
Diffstat (limited to 'Source')
29 files changed, 437 insertions, 26 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 30bef74..6623ba4 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -379,6 +379,8 @@ set(SRCS cmAddCompileDefinitionsCommand.h cmAddCompileOptionsCommand.cxx cmAddCompileOptionsCommand.h + cmAddLinkOptionsCommand.cxx + cmAddLinkOptionsCommand.h cmAddCustomCommandCommand.cxx cmAddCustomCommandCommand.h cmAddCustomTargetCommand.cxx @@ -574,6 +576,8 @@ set(SRCS cmTargetCompileOptionsCommand.h cmTargetIncludeDirectoriesCommand.cxx cmTargetIncludeDirectoriesCommand.h + cmTargetLinkOptionsCommand.cxx + cmTargetLinkOptionsCommand.h cmTargetLinkLibrariesCommand.cxx cmTargetLinkLibrariesCommand.h cmTargetPropCommandBase.cxx diff --git a/Source/cmAddLinkOptionsCommand.cxx b/Source/cmAddLinkOptionsCommand.cxx new file mode 100644 index 0000000..10ebd12 --- /dev/null +++ b/Source/cmAddLinkOptionsCommand.cxx @@ -0,0 +1,20 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmAddLinkOptionsCommand.h" + +#include "cmMakefile.h" + +class cmExecutionStatus; + +bool cmAddLinkOptionsCommand::InitialPass(std::vector<std::string> const& args, + cmExecutionStatus&) +{ + if (args.empty()) { + return true; + } + + for (std::string const& i : args) { + this->Makefile->AddLinkOption(i); + } + return true; +} diff --git a/Source/cmAddLinkOptionsCommand.h b/Source/cmAddLinkOptionsCommand.h new file mode 100644 index 0000000..30fff00 --- /dev/null +++ b/Source/cmAddLinkOptionsCommand.h @@ -0,0 +1,31 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmAddLinkOptionsCommand_h +#define cmAddLinkOptionsCommand_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> +#include <vector> + +#include "cmCommand.h" + +class cmExecutionStatus; + +class cmAddLinkOptionsCommand : public cmCommand +{ +public: + /** + * This is a virtual constructor for the command. + */ + cmCommand* Clone() override { return new cmAddLinkOptionsCommand; } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus& status) override; +}; + +#endif diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index dc9318e..15fbd40 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -82,6 +82,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) # include "cmAddCompileOptionsCommand.h" +# include "cmAddLinkOptionsCommand.h" # include "cmAuxSourceDirectoryCommand.h" # include "cmBuildNameCommand.h" # include "cmCMakeHostSystemInformationCommand.h" @@ -100,6 +101,7 @@ # include "cmRemoveDefinitionsCommand.h" # include "cmSourceGroupCommand.h" # include "cmSubdirDependsCommand.h" +# include "cmTargetLinkOptionsCommand.h" # include "cmUseMangledMesaCommand.h" # include "cmUtilitySourceCommand.h" # include "cmVariableRequiresCommand.h" @@ -272,7 +274,10 @@ void GetProjectCommands(cmState* state) state->AddBuiltinCommand("include_external_msproject", new cmIncludeExternalMSProjectCommand); state->AddBuiltinCommand("install_programs", new cmInstallProgramsCommand); + state->AddBuiltinCommand("add_link_options", new cmAddLinkOptionsCommand); state->AddBuiltinCommand("link_libraries", new cmLinkLibrariesCommand); + state->AddBuiltinCommand("target_link_options", + new cmTargetLinkOptionsCommand); state->AddBuiltinCommand("load_cache", new cmLoadCacheCommand); state->AddBuiltinCommand("qt_wrap_cpp", new cmQTWrapCPPCommand); state->AddBuiltinCommand("qt_wrap_ui", new cmQTWrapUICommand); diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 0ceac85..bb370c4 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -7,6 +7,7 @@ #include <sstream> #include <utility> +#include "cmAlgorithms.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" @@ -169,6 +170,11 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( end = "\\\n"; } os << "\n"; + } else if (property.first == "INTERFACE_LINK_OPTIONS") { + os << "LOCAL_EXPORT_LDFLAGS := "; + std::vector<std::string> linkFlagsList; + cmSystemTools::ExpandListArgument(property.second, linkFlagsList); + os << cmJoin(linkFlagsList, " ") << "\n"; } else { os << "# " << property.first << " " << (property.second) << "\n"; } diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 47636cd..9f2e01d 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -95,6 +95,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, properties); diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 02686f3..1db76ac 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -103,6 +103,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); std::string errorMessage; if (!this->PopulateExportProperties(gt, properties, errorMessage)) { diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index a3a8f69..cfe31f1 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -25,7 +25,8 @@ struct cmGeneratorExpressionContext; SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \ SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \ SELECT(F, EvaluatingSources, SOURCES) \ - SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) + SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \ + SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) #define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index b223c5e..f5418a5 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -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,59 @@ void cmGeneratorTarget::GetCompileDefinitions( cmDeleteAll(linkInterfaceCompileDefinitionsEntries); } +static 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); +} + void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const { if (this->IsImported()) { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 2132b15..aa36823 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -418,6 +418,10 @@ public: const std::string& config, const std::string& language) const; + void GetLinkOptions(std::vector<std::string>& result, + const std::string& config, + const std::string& language) const; + bool IsSystemIncludeDirectory(const std::string& dir, const std::string& config, const std::string& language) const; @@ -803,6 +807,7 @@ private: std::vector<TargetPropertyEntry*> CompileOptionsEntries; std::vector<TargetPropertyEntry*> CompileFeaturesEntries; std::vector<TargetPropertyEntry*> CompileDefinitionsEntries; + std::vector<TargetPropertyEntry*> LinkOptionsEntries; std::vector<TargetPropertyEntry*> SourceEntries; mutable std::set<std::string> LinkImplicitNullProperties; @@ -851,6 +856,7 @@ private: mutable bool DebugCompileOptionsDone; mutable bool DebugCompileFeaturesDone; mutable bool DebugCompileDefinitionsDone; + mutable bool DebugLinkOptionsDone; mutable bool DebugSourcesDone; mutable bool LinkImplementationLanguageIsContextDependent; mutable bool UtilityItemsDone; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 47741f9..b461598 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1817,6 +1817,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, linkFlags); } } + std::vector<std::string> opts; + gtgt->GetLinkOptions(opts, configName, llang); + // LINK_OPTIONS are escaped. + this->CurrentLocalGenerator->AppendCompileOptions(extraLinkOptions, opts); } // Set target-specific architectures. diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index a3f4a8f..072b958 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1042,6 +1042,10 @@ void cmLocalGenerator::GetTargetFlags( linkFlags += " "; } } + std::vector<std::string> opts; + target->GetLinkOptions(opts, config, linkLanguage); + // LINK_OPTIONS are escaped. + this->AppendCompileOptions(linkFlags, opts); if (pcli) { this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, linkPath); @@ -1113,6 +1117,10 @@ void cmLocalGenerator::GetTargetFlags( linkFlags += " "; } } + std::vector<std::string> opts; + target->GetLinkOptions(opts, config, linkLanguage); + // LINK_OPTIONS are escaped. + this->AppendCompileOptions(linkFlags, opts); } break; default: break; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 3460289..4b0b66d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -977,6 +977,13 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( extraLinkOptions += " "; extraLinkOptions += targetLinkFlags; } + + std::vector<std::string> opts; + target->GetLinkOptions(opts, configName, + target->GetLinkerLanguage(configName)); + // LINK_OPTIONS are escaped. + this->AppendCompileOptions(extraLinkOptions, opts); + Options linkOptions(this, Options::Linker); if (this->FortranProject) { linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 3c7a4cf..a9b0b78 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -216,6 +216,16 @@ cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const .GetCompileDefinitionsEntryBacktraces(); } +cmStringRange cmMakefile::GetLinkOptionsEntries() const +{ + return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries(); +} + +cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const +{ + return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces(); +} + cmListFileBacktrace cmMakefile::GetBacktrace() const { return this->Backtrace; @@ -1205,6 +1215,11 @@ void cmMakefile::AddCompileOption(std::string const& option) this->AppendProperty("COMPILE_OPTIONS", option.c_str()); } +void cmMakefile::AddLinkOption(std::string const& option) +{ + this->AppendProperty("LINK_OPTIONS", option.c_str()); +} + bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove) { // Create a regular expression to match valid definitions. diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index a7c8df5..616a37f 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -171,6 +171,7 @@ public: void RemoveDefineFlag(std::string const& definition); void AddCompileDefinition(std::string const& definition); void AddCompileOption(std::string const& option); + void AddLinkOption(std::string const& option); /** Create a new imported target with the name and type given. */ cmTarget* AddImportedTarget(const std::string& name, @@ -788,6 +789,8 @@ public: cmBacktraceRange GetCompileOptionsBacktraces() const; cmStringRange GetCompileDefinitionsEntries() const; cmBacktraceRange GetCompileDefinitionsBacktraces() const; + cmStringRange GetLinkOptionsEntries() const; + cmBacktraceRange GetLinkOptionsBacktraces() const; std::set<std::string> const& GetSystemIncludeDirectories() const { diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 9ffffc2..82f4683 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -154,7 +154,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( linkLanguage, this->ConfigName); // Add target-specific linker flags. - this->GetTargetLinkFlags(linkFlags); + this->GetTargetLinkFlags(linkFlags, linkLanguage); // Construct a list of files associated with this executable that // may need to be cleaned. @@ -432,7 +432,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) linkLanguage, this->ConfigName); // Add target-specific linker flags. - this->GetTargetLinkFlags(linkFlags); + this->GetTargetLinkFlags(linkFlags, linkLanguage); { std::unique_ptr<cmLinkLineComputer> linkLineComputer( diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 8a08789..036acc7 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -181,7 +181,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) linkRuleVar += "_CREATE_SHARED_LIBRARY"; std::string extraFlags; - this->GetTargetLinkFlags(extraFlags); + this->GetTargetLinkFlags(extraFlags, linkLanguage); this->LocalGenerator->AddConfigVariableFlags( extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName); @@ -222,7 +222,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) linkRuleVar += "_CREATE_SHARED_MODULE"; std::string extraFlags; - this->GetTargetLinkFlags(extraFlags); + this->GetTargetLinkFlags(extraFlags, linkLanguage); this->LocalGenerator->AddConfigVariableFlags( extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName); @@ -245,7 +245,7 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) linkRuleVar += "_CREATE_MACOSX_FRAMEWORK"; std::string extraFlags; - this->GetTargetLinkFlags(extraFlags); + this->GetTargetLinkFlags(extraFlags, linkLanguage); this->LocalGenerator->AddConfigVariableFlags( extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName); @@ -271,7 +271,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // Create set of linking flags. std::string linkFlags; - this->GetTargetLinkFlags(linkFlags); + this->GetTargetLinkFlags(linkFlags, linkLanguage); // Get the name of the device object to generate. std::string const targetOutputReal = diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 8cbddd9..08fcd8f 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -82,7 +82,8 @@ cmMakefileTargetGenerator* cmMakefileTargetGenerator::New( return result; } -void cmMakefileTargetGenerator::GetTargetLinkFlags(std::string& flags) +void cmMakefileTargetGenerator::GetTargetLinkFlags( + std::string& flags, const std::string& linkLanguage) { this->LocalGenerator->AppendFlags( flags, this->GeneratorTarget->GetProperty("LINK_FLAGS")); @@ -91,6 +92,11 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags(std::string& flags) linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName); this->LocalGenerator->AppendFlags( flags, this->GeneratorTarget->GetProperty(linkFlagsConfig)); + + std::vector<std::string> opts; + this->GeneratorTarget->GetLinkOptions(opts, this->ConfigName, linkLanguage); + // LINK_OPTIONS are escaped. + this->LocalGenerator->AppendCompileOptions(flags, opts); } void cmMakefileTargetGenerator::CreateRuleFile() diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 4e6849a..4d1c9ec 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -52,7 +52,7 @@ public: cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; } protected: - void GetTargetLinkFlags(std::string& flags); + void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage); // create the file and directory etc void CreateRuleFile(); diff --git a/Source/cmState.cxx b/Source/cmState.cxx index a57be4d..dcf6ea0 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -280,6 +280,8 @@ cmStateSnapshot cmState::Reset() it->CompileDefinitionsBacktraces.clear(); it->CompileOptions.clear(); it->CompileOptionsBacktraces.clear(); + it->LinkOptions.clear(); + it->LinkOptionsBacktraces.clear(); it->DirectoryEnd = pos; it->NormalTargetNames.clear(); it->Properties.clear(); diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index 85e6366..6eac8e2 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -360,6 +360,42 @@ void cmStateDirectory::ClearCompileOptions() this->Snapshot_.Position->CompileOptionsPosition); } +cmStringRange cmStateDirectory::GetLinkOptionsEntries() const +{ + return GetPropertyContent(this->DirectoryState->LinkOptions, + this->Snapshot_.Position->LinkOptionsPosition); +} + +cmBacktraceRange cmStateDirectory::GetLinkOptionsEntryBacktraces() const +{ + return GetPropertyBacktraces(this->DirectoryState->LinkOptions, + this->DirectoryState->LinkOptionsBacktraces, + this->Snapshot_.Position->LinkOptionsPosition); +} + +void cmStateDirectory::AppendLinkOptionsEntry(const std::string& vec, + const cmListFileBacktrace& lfbt) +{ + AppendEntry(this->DirectoryState->LinkOptions, + this->DirectoryState->LinkOptionsBacktraces, + this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt); +} + +void cmStateDirectory::SetLinkOptions(const std::string& vec, + const cmListFileBacktrace& lfbt) +{ + SetContent(this->DirectoryState->LinkOptions, + this->DirectoryState->LinkOptionsBacktraces, + this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt); +} + +void cmStateDirectory::ClearLinkOptions() +{ + ClearContent(this->DirectoryState->LinkOptions, + this->DirectoryState->LinkOptionsBacktraces, + this->Snapshot_.Position->LinkOptionsPosition); +} + void cmStateDirectory::SetProperty(const std::string& prop, const char* value, cmListFileBacktrace const& lfbt) { @@ -387,6 +423,14 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value, this->SetCompileDefinitions(value, lfbt); return; } + if (prop == "LINK_OPTIONS") { + if (!value) { + this->ClearLinkOptions(); + return; + } + this->SetLinkOptions(value, lfbt); + return; + } this->DirectoryState->Properties.SetProperty(prop, value); } @@ -407,6 +451,10 @@ void cmStateDirectory::AppendProperty(const std::string& prop, this->AppendCompileDefinitionsEntry(value, lfbt); return; } + if (prop == "LINK_OPTIONS") { + this->AppendLinkOptionsEntry(value, lfbt); + return; + } this->DirectoryState->Properties.AppendProperty(prop, value, asString); } @@ -490,6 +538,10 @@ const char* cmStateDirectory::GetProperty(const std::string& prop, output = cmJoin(this->GetCompileDefinitionsEntries(), ";"); return output.c_str(); } + if (prop == "LINK_OPTIONS") { + output = cmJoin(this->GetLinkOptionsEntries(), ";"); + return output.c_str(); + } const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop); if (!retVal && chain) { diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h index 79bb369..bc96cc9 100644 --- a/Source/cmStateDirectory.h +++ b/Source/cmStateDirectory.h @@ -58,6 +58,13 @@ public: cmListFileBacktrace const& lfbt); void ClearCompileOptions(); + cmStringRange GetLinkOptionsEntries() const; + cmBacktraceRange GetLinkOptionsEntryBacktraces() const; + void AppendLinkOptionsEntry(std::string const& vec, + cmListFileBacktrace const& lfbt); + void SetLinkOptions(std::string const& vec, cmListFileBacktrace const& lfbt); + void ClearLinkOptions(); + void SetProperty(const std::string& prop, const char* value, cmListFileBacktrace const& lfbt); void AppendProperty(const std::string& prop, const char* value, diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h index f36ee37..7177221 100644 --- a/Source/cmStatePrivate.h +++ b/Source/cmStatePrivate.h @@ -42,6 +42,7 @@ struct cmStateDetail::SnapshotDataType std::vector<std::string>::size_type IncludeDirectoryPosition; std::vector<std::string>::size_type CompileDefinitionsPosition; std::vector<std::string>::size_type CompileOptionsPosition; + std::vector<std::string>::size_type LinkOptionsPosition; }; struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap @@ -84,6 +85,9 @@ struct cmStateDetail::BuildsystemDirectoryStateType std::vector<std::string> CompileOptions; std::vector<cmListFileBacktrace> CompileOptionsBacktraces; + std::vector<std::string> LinkOptions; + std::vector<cmListFileBacktrace> LinkOptionsBacktraces; + std::vector<std::string> NormalTargetNames; std::string ProjectName; diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index 8f5f58c..ec428a6 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -390,6 +390,13 @@ void cmStateSnapshot::InitializeFromParent() this->Position->BuildSystemDirectory->CompileOptionsBacktraces, this->Position->CompileOptionsPosition); + InitializeContentFromParent( + parent->BuildSystemDirectory->LinkOptions, + this->Position->BuildSystemDirectory->LinkOptions, + parent->BuildSystemDirectory->LinkOptionsBacktraces, + this->Position->BuildSystemDirectory->LinkOptionsBacktraces, + this->Position->LinkOptionsPosition); + const char* include_regex = parent->BuildSystemDirectory->Properties.GetPropertyValue( "INCLUDE_REGULAR_EXPRESSION"); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 1868816..1a6e1d1 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -166,6 +166,8 @@ public: std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces; std::vector<std::string> SourceEntries; std::vector<cmListFileBacktrace> SourceBacktraces; + std::vector<std::string> LinkOptionsEntries; + std::vector<cmListFileBacktrace> LinkOptionsBacktraces; std::vector<std::string> LinkImplementationPropertyEntries; std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces; }; @@ -343,17 +345,29 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(), parentSystemIncludes.end()); - const cmStringRange parentOptions = + const cmStringRange parentCompileOptions = this->Makefile->GetCompileOptionsEntries(); - const cmBacktraceRange parentOptionsBts = + const cmBacktraceRange parentCompileOptionsBts = this->Makefile->GetCompileOptionsBacktraces(); this->Internal->CompileOptionsEntries.insert( - this->Internal->CompileOptionsEntries.end(), parentOptions.begin(), - parentOptions.end()); + this->Internal->CompileOptionsEntries.end(), + parentCompileOptions.begin(), parentCompileOptions.end()); this->Internal->CompileOptionsBacktraces.insert( - this->Internal->CompileOptionsBacktraces.end(), parentOptionsBts.begin(), - parentOptionsBts.end()); + this->Internal->CompileOptionsBacktraces.end(), + parentCompileOptionsBts.begin(), parentCompileOptionsBts.end()); + + const cmStringRange parentLinkOptions = + this->Makefile->GetLinkOptionsEntries(); + const cmBacktraceRange parentLinkOptionsBts = + this->Makefile->GetLinkOptionsBacktraces(); + + this->Internal->LinkOptionsEntries.insert( + this->Internal->LinkOptionsEntries.end(), parentLinkOptions.begin(), + parentLinkOptions.end()); + this->Internal->LinkOptionsBacktraces.insert( + this->Internal->LinkOptionsBacktraces.end(), + parentLinkOptionsBts.begin(), parentLinkOptionsBts.end()); } if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && @@ -822,6 +836,16 @@ cmBacktraceRange cmTarget::GetSourceBacktraces() const return cmMakeRange(this->Internal->SourceBacktraces); } +cmStringRange cmTarget::GetLinkOptionsEntries() const +{ + return cmMakeRange(this->Internal->LinkOptionsEntries); +} + +cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const +{ + return cmMakeRange(this->Internal->LinkOptionsBacktraces); +} + cmStringRange cmTarget::GetLinkImplementationEntries() const { return cmMakeRange(this->Internal->LinkImplementationPropertyEntries); @@ -847,6 +871,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) MAKE_STATIC_PROP(EXPORT_NAME); MAKE_STATIC_PROP(IMPORTED_GLOBAL); MAKE_STATIC_PROP(INCLUDE_DIRECTORIES); + MAKE_STATIC_PROP(LINK_OPTIONS); MAKE_STATIC_PROP(LINK_LIBRARIES); MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES); MAKE_STATIC_PROP(NAME); @@ -925,6 +950,14 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); this->Internal->CompileDefinitionsBacktraces.push_back(lfbt); } + } else if (prop == propLINK_OPTIONS) { + this->Internal->LinkOptionsEntries.clear(); + this->Internal->LinkOptionsBacktraces.clear(); + if (value) { + this->Internal->LinkOptionsEntries.push_back(value); + cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); + this->Internal->LinkOptionsBacktraces.push_back(lfbt); + } } else if (prop == propLINK_LIBRARIES) { this->Internal->LinkImplementationPropertyEntries.clear(); this->Internal->LinkImplementationPropertyBacktraces.clear(); @@ -1030,6 +1063,12 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); this->Internal->CompileDefinitionsBacktraces.push_back(lfbt); } + } else if (prop == "LINK_OPTIONS") { + if (value && *value) { + this->Internal->LinkOptionsEntries.push_back(value); + cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); + this->Internal->LinkOptionsBacktraces.push_back(lfbt); + } } else if (prop == "LINK_LIBRARIES") { if (value && *value) { cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); @@ -1111,6 +1150,21 @@ void cmTarget::InsertCompileDefinition(std::string const& entry, this->Internal->CompileDefinitionsBacktraces.push_back(bt); } +void cmTarget::InsertLinkOption(std::string const& entry, + cmListFileBacktrace const& bt, bool before) +{ + std::vector<std::string>::iterator position = before + ? this->Internal->LinkOptionsEntries.begin() + : this->Internal->LinkOptionsEntries.end(); + + std::vector<cmListFileBacktrace>::iterator btPosition = before + ? this->Internal->LinkOptionsBacktraces.begin() + : this->Internal->LinkOptionsBacktraces.end(); + + this->Internal->LinkOptionsEntries.insert(position, entry); + this->Internal->LinkOptionsBacktraces.insert(btPosition, bt); +} + static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop, const char* value, cmMakefile* context, @@ -1230,6 +1284,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const MAKE_STATIC_PROP(COMPILE_FEATURES); MAKE_STATIC_PROP(COMPILE_OPTIONS); MAKE_STATIC_PROP(COMPILE_DEFINITIONS); + MAKE_STATIC_PROP(LINK_OPTIONS); MAKE_STATIC_PROP(IMPORTED); MAKE_STATIC_PROP(IMPORTED_GLOBAL); MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES); @@ -1245,6 +1300,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const specialProps.insert(propCOMPILE_FEATURES); specialProps.insert(propCOMPILE_OPTIONS); specialProps.insert(propCOMPILE_DEFINITIONS); + specialProps.insert(propLINK_OPTIONS); specialProps.insert(propIMPORTED); specialProps.insert(propIMPORTED_GLOBAL); specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES); @@ -1303,6 +1359,15 @@ const char* cmTarget::GetProperty(const std::string& prop) const output = cmJoin(this->Internal->CompileDefinitionsEntries, ";"); return output.c_str(); } + if (prop == propLINK_OPTIONS) { + if (this->Internal->LinkOptionsEntries.empty()) { + return nullptr; + } + + static std::string output; + output = cmJoin(this->Internal->LinkOptionsEntries, ";"); + return output.c_str(); + } if (prop == propMANUALLY_ADDED_DEPENDENCIES) { if (this->Utilities.empty()) { return nullptr; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 3abb47e..5f0b33c 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -239,6 +239,8 @@ public: cmListFileBacktrace const& bt, bool before = false); void InsertCompileDefinition(std::string const& entry, cmListFileBacktrace const& bt); + void InsertLinkOption(std::string const& entry, + cmListFileBacktrace const& bt, bool before = false); void AppendBuildInterfaceIncludes(); @@ -265,6 +267,10 @@ public: cmStringRange GetSourceEntries() const; cmBacktraceRange GetSourceBacktraces() const; + + cmStringRange GetLinkOptionsEntries() const; + cmBacktraceRange GetLinkOptionsBacktraces() const; + cmStringRange GetLinkImplementationEntries() const; cmBacktraceRange GetLinkImplementationBacktraces() const; diff --git a/Source/cmTargetLinkOptionsCommand.cxx b/Source/cmTargetLinkOptionsCommand.cxx new file mode 100644 index 0000000..f0f13fd --- /dev/null +++ b/Source/cmTargetLinkOptionsCommand.cxx @@ -0,0 +1,41 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmTargetLinkOptionsCommand.h" + +#include <sstream> + +#include "cmAlgorithms.h" +#include "cmListFileCache.h" +#include "cmMakefile.h" +#include "cmTarget.h" +#include "cmake.h" + +class cmExecutionStatus; + +bool cmTargetLinkOptionsCommand::InitialPass( + std::vector<std::string> const& args, cmExecutionStatus&) +{ + return this->HandleArguments(args, "LINK_OPTIONS", PROCESS_BEFORE); +} + +void cmTargetLinkOptionsCommand::HandleMissingTarget(const std::string& name) +{ + std::ostringstream e; + e << "Cannot specify link options for target \"" << name + << "\" which is not built by this project."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +std::string cmTargetLinkOptionsCommand::Join( + const std::vector<std::string>& content) +{ + return cmJoin(content, ";"); +} + +bool cmTargetLinkOptionsCommand::HandleDirectContent( + cmTarget* tgt, const std::vector<std::string>& content, bool, bool) +{ + cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); + tgt->InsertLinkOption(this->Join(content), lfbt); + return true; // Successfully handled. +} diff --git a/Source/cmTargetLinkOptionsCommand.h b/Source/cmTargetLinkOptionsCommand.h new file mode 100644 index 0000000..a1fc9fc --- /dev/null +++ b/Source/cmTargetLinkOptionsCommand.h @@ -0,0 +1,41 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmTargetLinkOptionsCommand_h +#define cmTargetLinkOptionsCommand_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> +#include <vector> + +#include "cmTargetPropCommandBase.h" + +class cmCommand; +class cmExecutionStatus; +class cmTarget; + +class cmTargetLinkOptionsCommand : public cmTargetPropCommandBase +{ +public: + /** + * This is a virtual constructor for the command. + */ + cmCommand* Clone() override { return new cmTargetLinkOptionsCommand; } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus& status) override; + +private: + void HandleMissingTarget(const std::string& name) override; + + bool HandleDirectContent(cmTarget* tgt, + const std::vector<std::string>& content, + bool prepend, bool system) override; + std::string Join(const std::vector<std::string>& content) override; +}; + +#endif diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1768c57..549c8af 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3234,6 +3234,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( flags += flagsConfig; } + std::vector<std::string> opts; + this->GeneratorTarget->GetLinkOptions(opts, config, linkLanguage); + // LINK_OPTIONS are escaped. + this->LocalGenerator->AppendCompileOptions(flags, opts); + cmComputeLinkInformation* pcli = this->GeneratorTarget->GetLinkInformation(config); if (!pcli) { |