diff options
22 files changed, 195 insertions, 42 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 03a6a27..9c2ac03 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -198,6 +198,7 @@ Properties on Targets /prop_tgt/IMPORTED_LIBNAME_CONFIG /prop_tgt/IMPORTED_LIBNAME /prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG + /prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES_CONFIG /prop_tgt/IMPORTED_LINK_DEPENDENT_LIBRARIES /prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES_CONFIG /prop_tgt/IMPORTED_LINK_INTERFACE_LANGUAGES @@ -225,6 +226,7 @@ Properties on Targets /prop_tgt/INTERFACE_COMPILE_FEATURES /prop_tgt/INTERFACE_COMPILE_OPTIONS /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES + /prop_tgt/INTERFACE_LINK_DEPENDS /prop_tgt/INTERFACE_LINK_LIBRARIES /prop_tgt/INTERFACE_LINK_OPTIONS /prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE diff --git a/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst new file mode 100644 index 0000000..d07f8ea --- /dev/null +++ b/Help/prop_tgt/INTERFACE_LINK_DEPENDS.rst @@ -0,0 +1,31 @@ +INTERFACE_LINK_DEPENDS +---------------------- + +Additional public interface files on which a target binary depends for linking. + +This property is supported only by Makefile and Ninja generators. It is +intended to specify dependencies on "linker scripts" for custom Makefile link +rules. + +When target dependencies are specified using :command:`target_link_libraries`, +CMake will read this property from all target dependencies to determine the +build properties of the consumer. + +Contents of ``INTERFACE_LINK_DEPENDS`` may use "generator expressions" +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. + +Link dependency files usage requirements commonly differ between the build-tree +and the install-tree. The ``BUILD_INTERFACE`` and ``INSTALL_INTERFACE`` +generator expressions can be used to describe separate usage requirements +based on the usage location. Relative paths are allowed within the +``INSTALL_INTERFACE`` expression and are interpreted relative to the +installation prefix. For example: + +.. code-block:: cmake + + set_property(TARGET mylib PROPERTY INTERFACE_LINK_DEPENDS + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/mylinkscript> + $<INSTALL_INTERFACE:mylinkscript> # <prefix>/mylinkscript + ) diff --git a/Help/prop_tgt/LINK_DEPENDS.rst b/Help/prop_tgt/LINK_DEPENDS.rst index 5576b85..bc83393 100644 --- a/Help/prop_tgt/LINK_DEPENDS.rst +++ b/Help/prop_tgt/LINK_DEPENDS.rst @@ -7,6 +7,6 @@ Specifies a semicolon-separated list of full-paths to files on which the link rule for this target depends. The target binary will be linked if any of the named files is newer than it. -This property is ignored by non-Makefile generators. It is intended -to specify dependencies on "linker scripts" for custom Makefile link +This property is supported only by Makefile and Ninja generators. It is +intended to specify dependencies on "linker scripts" for custom Makefile link rules. diff --git a/Help/release/dev/INTERFACE_LINK_DEPENDS-property.rst b/Help/release/dev/INTERFACE_LINK_DEPENDS-property.rst new file mode 100644 index 0000000..9527c97 --- /dev/null +++ b/Help/release/dev/INTERFACE_LINK_DEPENDS-property.rst @@ -0,0 +1,4 @@ +INTERFACE_LINK_DEPENDS-property +------------------------------- + +* Binary targets gained new :prop_tgt:`INTERFACE_LINK_DEPENDS` property. diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 9f2e01d..7f42035 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -98,6 +98,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, properties); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 5f61571..ec68fce 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -420,6 +420,37 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( } } +void cmExportFileGenerator::PopulateLinkDependsInterface( + cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties, std::vector<std::string>& missingTargets) +{ + cmGeneratorTarget* gt = tei->Target; + assert(preprocessRule == cmGeneratorExpression::InstallInterface); + + const char* propName = "INTERFACE_LINK_DEPENDS"; + const char* input = gt->GetProperty(propName); + + if (!input) { + return; + } + + if (!*input) { + properties[propName].clear(); + return; + } + + std::string prepro = + cmGeneratorExpression::Preprocess(input, preprocessRule, true); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets); + + if (!checkInterfaceDirs(prepro, gt, propName)) { + return; + } + properties[propName] = prepro; + } +} + void cmExportFileGenerator::PopulateInterfaceProperty( const std::string& propName, cmGeneratorTarget* target, cmGeneratorExpression::PreprocessContext preprocessRule, diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 954e6c5..6ca2e07 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -147,6 +147,10 @@ protected: cmTargetExport* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); + void PopulateLinkDependsInterface( + cmTargetExport* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties, std::vector<std::string>& missingTargets); void SetImportLinkInterface( const std::string& config, std::string const& suffix, diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 1db76ac..3595708 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -106,6 +106,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); + this->PopulateLinkDependsInterface( + te, cmGeneratorExpression::InstallInterface, properties, missingTargets); std::string errorMessage; if (!this->PopulateExportProperties(gt, properties, errorMessage)) { diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index cfe31f1..cd23904 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -26,7 +26,8 @@ struct cmGeneratorExpressionContext; SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \ SELECT(F, EvaluatingSources, SOURCES) \ SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \ - SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) + SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \ + SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS) #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 41e55a5..d4686c2 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -3008,6 +3008,42 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, } } +namespace { +void processLinkDepends( + 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, + std::string const& language) +{ + processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, + config, false, "link depends", language, + OptionsParse::None); +} +} + +void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result, + const std::string& config, + const std::string& language) const +{ + if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) { + cmSystemTools::ExpandListArgument(linkDepends, result); + } + + std::unordered_set<std::string> uniqueOptions; + std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkDependsEntries; + cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), "LINK_DEPENDS", + nullptr, nullptr); + + AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", + linkDependsEntries); + processLinkDepends(this, linkDependsEntries, result, uniqueOptions, + &dagChecker, config, language); + + cmDeleteAll(linkDependsEntries); +} + void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const { if (this->IsImported()) { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index aa36823..4cc0aac 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -422,6 +422,10 @@ public: const std::string& config, const std::string& language) const; + void GetLinkDepends(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; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 82f4683..b9845ba 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -97,15 +97,15 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( std::vector<std::string> commands; - // Build list of dependencies. - std::vector<std::string> depends; - this->AppendLinkDepends(depends); - // Get the language to use for linking this library. std::string linkLanguage = "CUDA"; std::string const objExt = this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); + // Build list of dependencies. + std::vector<std::string> depends; + this->AppendLinkDepends(depends, linkLanguage); + // Get the name of the device object to generate. std::string const targetOutputReal = this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt; @@ -294,13 +294,6 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) { std::vector<std::string> commands; - // Build list of dependencies. - std::vector<std::string> depends; - this->AppendLinkDepends(depends); - if (!this->DeviceLinkObject.empty()) { - depends.push_back(this->DeviceLinkObject); - } - // Get the name of the executable to generate. std::string targetName; std::string targetNameReal; @@ -378,6 +371,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) return; } + // Build list of dependencies. + std::vector<std::string> depends; + this->AppendLinkDepends(depends, linkLanguage); + if (!this->DeviceLinkObject.empty()) { + depends.push_back(this->DeviceLinkObject); + } + this->NumberOfProgressActions++; if (!this->NoRuleMessages) { cmLocalUnixMakefileGenerator3::EchoProgress progress; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 036acc7..571e74b 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -260,15 +260,15 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // code duplication. std::vector<std::string> commands; - // Build list of dependencies. - std::vector<std::string> depends; - this->AppendLinkDepends(depends); - // Get the language to use for linking this library. std::string linkLanguage = "CUDA"; std::string const objExt = this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); + // Build list of dependencies. + std::vector<std::string> depends; + this->AppendLinkDepends(depends, linkLanguage); + // Create set of linking flags. std::string linkFlags; this->GetTargetLinkFlags(linkFlags, linkLanguage); @@ -444,13 +444,6 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // code duplication. std::vector<std::string> commands; - // Build list of dependencies. - std::vector<std::string> depends; - this->AppendLinkDepends(depends); - if (!this->DeviceLinkObject.empty()) { - depends.push_back(this->DeviceLinkObject); - } - // Get the language to use for linking this library. std::string linkLanguage = this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); @@ -462,6 +455,13 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( return; } + // Build list of dependencies. + std::vector<std::string> depends; + this->AppendLinkDepends(depends, linkLanguage); + if (!this->DeviceLinkObject.empty()) { + depends.push_back(this->DeviceLinkObject); + } + // Create set of linking flags. std::string linkFlags; this->LocalGenerator->AppendFlags(linkFlags, extraFlags); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 08fcd8f..7cae305 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1387,7 +1387,7 @@ void cmMakefileTargetGenerator::AppendObjectDepends( } void cmMakefileTargetGenerator::AppendLinkDepends( - std::vector<std::string>& depends) + std::vector<std::string>& depends, const std::string& linkLanguage) { this->AppendObjectDepends(depends); @@ -1411,10 +1411,8 @@ void cmMakefileTargetGenerator::AppendLinkDepends( } // Add user-specified dependencies. - if (const char* linkDepends = - this->GeneratorTarget->GetProperty("LINK_DEPENDS")) { - cmSystemTools::ExpandListArgument(linkDepends, depends); - } + this->GeneratorTarget->GetLinkDepends(depends, this->ConfigName, + linkLanguage); } std::string cmMakefileTargetGenerator::GetLinkRule( diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 4d1c9ec..f21362a 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -128,7 +128,8 @@ protected: void AppendObjectDepends(std::vector<std::string>& depends); // Append link rule dependencies (objects, etc.). - void AppendLinkDepends(std::vector<std::string>& depends); + void AppendLinkDepends(std::vector<std::string>& depends, + const std::string& linkLanguage); // Lookup the link rule for this target. std::string GetLinkRule(const std::string& linkRuleVar); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 7394188..f94e5bc 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -625,7 +625,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() outputs.push_back(targetOutputReal); // Compute specific libraries to link with. cmNinjaDeps explicitDeps = this->GetObjects(); - cmNinjaDeps implicitDeps = this->ComputeLinkDeps(); + cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); std::string frameworkPath; std::string linkPath; @@ -794,7 +794,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Compute specific libraries to link with. cmNinjaDeps explicitDeps = this->GetObjects(); - cmNinjaDeps implicitDeps = this->ComputeLinkDeps(); + cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); if (!this->DeviceLinkObject.empty()) { explicitDeps.push_back(this->DeviceLinkObject); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 9d41948..df32f40 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -235,7 +235,8 @@ std::string cmNinjaTargetGenerator::ComputeIncludes( return includesString; } -cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const +cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( + const std::string& linkLanguage) const { // Static libraries never depend on other targets for linking. if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -270,13 +271,11 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const } // Add user-specified dependencies. - if (const char* linkDepends = - this->GeneratorTarget->GetProperty("LINK_DEPENDS")) { - std::vector<std::string> linkDeps; - cmSystemTools::ExpandListArgument(linkDepends, linkDeps); - std::transform(linkDeps.begin(), linkDeps.end(), - std::back_inserter(result), MapToNinjaPath()); - } + std::vector<std::string> linkDeps; + this->GeneratorTarget->GetLinkDepends(linkDeps, this->ConfigName, + linkLanguage); + std::transform(linkDeps.begin(), linkDeps.end(), std::back_inserter(result), + MapToNinjaPath()); return result; } diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 4660a3a..e58a8a0 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -95,7 +95,7 @@ protected: } /// @return the list of link dependency for the given target @a target. - cmNinjaDeps ComputeLinkDeps() const; + cmNinjaDeps ComputeLinkDeps(const std::string& linkLanguage) const; /// @return the source file path for the given @a source. std::string GetSourceFilePath(cmSourceFile const* source) const; diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt index 3b4ff60..39a5131 100644 --- a/Tests/BuildDepends/CMakeLists.txt +++ b/Tests/BuildDepends/CMakeLists.txt @@ -345,6 +345,17 @@ is not newer than dependency ${TEST_LINK_DEPENDS} ") endif() + + set(linkdep2 ${BuildDepends_BINARY_DIR}/Project/linkdep2${CMAKE_EXECUTABLE_SUFFIX}) + if(${linkdep2} IS_NEWER_THAN ${TEST_LINK_DEPENDS}) + message("INTERFACE_LINK_DEPENDS worked") + else() + message(SEND_ERROR "INTERFACE_LINK_DEPENDS failed. Executable + ${linkdep2} +is not newer than dependency + ${TEST_LINK_DEPENDS} +") + endif() endif() if(EXISTS "${link_depends_no_shared_check_txt}") diff --git a/Tests/BuildDepends/Project/CMakeLists.txt b/Tests/BuildDepends/Project/CMakeLists.txt index 127b365..09be3ea 100644 --- a/Tests/BuildDepends/Project/CMakeLists.txt +++ b/Tests/BuildDepends/Project/CMakeLists.txt @@ -107,6 +107,11 @@ set_property( if(TEST_LINK_DEPENDS) add_executable(linkdep linkdep.cxx) set_property(TARGET linkdep PROPERTY LINK_DEPENDS ${TEST_LINK_DEPENDS}) + + add_library(foo_interface INTERFACE) + set_property(TARGET foo_interface PROPERTY INTERFACE_LINK_DEPENDS $<1:${TEST_LINK_DEPENDS}>) + add_executable(linkdep2 linkdep.cxx) + target_link_libraries(linkdep2 PRIVATE foo_interface) endif() add_library(link_depends_no_shared_lib SHARED link_depends_no_shared_lib.c diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index a1c4993..470a5bd 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -607,3 +607,17 @@ target_link_options(testLinkOptions INTERFACE INTERFACE_FLAG) install(TARGETS testLinkOptions EXPORT RequiredExp DESTINATION lib) export(TARGETS testLinkOptions NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake) + + +#------------------------------------------------------------------------------ +# test export of INTERFACE_LINK_DEPENDS +if(CMAKE_GENERATOR MATCHES "Make|Ninja") + add_library(testLinkDepends INTERFACE) + set_property(TARGET testLinkDepends PROPERTY INTERFACE_LINK_DEPENDS + $<BUILD_INTERFACE:BUILD_LINK_DEPENDS> + $<INSTALL_INTERFACE:INSTALL_LINK_DEPENDS>) + + install(TARGETS testLinkDepends + EXPORT RequiredExp DESTINATION lib) + export(TARGETS testLinkDepends NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake) +endif() diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index f8eb721..7510d7e 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -477,3 +477,10 @@ endif() # check that imported libraries have the expected INTERFACE_LINK_OPTIONS property checkForProperty(bld_testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG") checkForProperty(Req::testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG") + +#--------------------------------------------------------------------------------- +# check that imported libraries have the expected INTERFACE_LINK_DEPENDS property +if(CMAKE_GENERATOR MATCHES "Make|Ninja") + checkForProperty(bld_testLinkDepends "INTERFACE_LINK_DEPENDS" "BUILD_LINK_DEPENDS") + checkForProperty(Req::testLinkDepends "INTERFACE_LINK_DEPENDS" "${CMAKE_INSTALL_PREFIX}/INSTALL_LINK_DEPENDS") +endif() |