Browse Source

LINK_LIBRARIES: Add support for LINK_ONLY genex

Previously we always used content guarded by `$<LINK_ONLY:...>`
in `LINK_LIBRARIES`, even when evaluating for non-linking usage
requirements.  Add a policy to honor `LINK_ONLY` in `LINK_LIBRARIES`
the same way we already do in `INTERFACE_LINK_LIBRARIES`.
Brad King 3 years ago
parent
commit
cf312a2e54

+ 9 - 6
Help/manual/cmake-generator-expressions.7.rst

@@ -1106,12 +1106,15 @@ Output-Related Expressions
 
   .. versionadded:: 3.1
 
-  Content of ``...`` except when evaluated in a link interface while
-  propagating :ref:`Target Usage Requirements`, in which case it is the
-  empty string.
-  Intended for use only in an :prop_tgt:`INTERFACE_LINK_LIBRARIES` target
-  property, perhaps via the :command:`target_link_libraries` command,
-  to specify private link dependencies without other usage requirements.
+  Content of ``...``, except while collecting :ref:`Target Usage Requirements`,
+  in which case it is the empty string.  This is intended for use in an
+  :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property, typically populated
+  via the :command:`target_link_libraries` command, to specify private link
+  dependencies without other usage requirements.
+
+  .. versionadded:: 3.24
+    ``LINK_ONLY`` may also be used in a :prop_tgt:`LINK_LIBRARIES` target
+    property.  See policy :policy:`CMP0131`.
 
 .. genex:: $<LINK_LIBRARY:feature,library-list>
 

+ 1 - 0
Help/manual/cmake-policies.7.rst

@@ -58,6 +58,7 @@ Policies Introduced by CMake 3.24
 .. toctree::
    :maxdepth: 1
 
+   CMP0131: LINK_LIBRARIES supports the LINK_ONLY generator expression. </policy/CMP0131>
    CMP0130: while() diagnoses condition evaluation errors. </policy/CMP0130>
 
 Policies Introduced by CMake 3.23

+ 31 - 0
Help/policy/CMP0131.rst

@@ -0,0 +1,31 @@
+CMP0131
+-------
+
+.. versionadded:: 3.24
+
+:prop_tgt:`LINK_LIBRARIES` supports the :genex:`$<LINK_ONLY:...>`
+generator expression.
+
+CMake 3.23 and below documented the :genex:`$<LINK_ONLY:...>` generator
+expression only for use in :prop_tgt:`INTERFACE_LINK_LIBRARIES`.
+When used in :prop_tgt:`LINK_LIBRARIES`, the content guarded inside
+:genex:`$<LINK_ONLY:...>` was always used, even when collecting non-linking
+usage requirements such as :prop_tgt:`INTERFACE_COMPILE_DEFINITIONS`.
+
+CMake 3.24 and above prefer to support :genex:`$<LINK_ONLY:...>`, when
+used in :prop_tgt:`LINK_LIBRARIES`, by using the guarded content only
+for link dependencies and not other usage requirements.  This policy
+provides compatibility for projects that have not been updated to
+account for this change.
+
+The ``OLD`` behavior for this policy is to use :prop_tgt:`LINK_LIBRARIES`
+content guarded by :genex:`$<LINK_ONLY:...>` even for non-linking
+usage requirements.  The ``NEW`` behavior for this policy is to to use
+the guarded content only for link dependencies.
+
+This policy was introduced in CMake version 3.24.  Use the
+:command:`cmake_policy` command to set this policy to ``OLD`` or ``NEW``
+explicitly.  Unlike many policies, CMake version |release| does *not*
+warn when this policy is not set, and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt

+ 4 - 0
Help/release/dev/link-interface-direct.rst

@@ -5,3 +5,7 @@ link-interface-direct
   :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE` target properties
   were added to express usage requirements affecting a consumer's
   direct link dependencies.
+
+* The :prop_tgt:`LINK_LIBRARIES` target property now supports
+  the :genex:`$<LINK_ONLY:...>` generator expression.
+  See policy :policy:`CMP0131`.

+ 14 - 0
Source/cmGeneratorTarget.cxx

@@ -8152,6 +8152,20 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
     // Keep this logic in sync with ExpandLinkItems.
     cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
                                                nullptr);
+    // The $<LINK_ONLY> expression may be used to specify link dependencies
+    // that are otherwise excluded from usage requirements.
+    if (implFor == LinkInterfaceFor::Usage) {
+      switch (this->GetPolicyStatusCMP0131()) {
+        case cmPolicies::WARN:
+        case cmPolicies::OLD:
+          break;
+        case cmPolicies::REQUIRED_IF_USED:
+        case cmPolicies::REQUIRED_ALWAYS:
+        case cmPolicies::NEW:
+          dagChecker.SetTransitivePropertiesOnly();
+          break;
+      }
+    }
     cmGeneratorExpression ge(entry.Backtrace);
     std::unique_ptr<cmCompiledGeneratorExpression> const cge =
       ge.Parse(entry.Value);

+ 6 - 2
Source/cmPolicies.h

@@ -390,7 +390,10 @@ class cmMakefile;
          "Compiler id for MCST LCC compilers is now LCC, not GNU.", 3, 23, 0, \
          cmPolicies::WARN)                                                    \
   SELECT(POLICY, CMP0130, "while() diagnoses condition evaluation errors.",   \
-         3, 24, 0, cmPolicies::WARN)
+         3, 24, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0131,                                                     \
+         "LINK_LIBRARIES supports the LINK_ONLY generator expression.", 3,    \
+         24, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
@@ -426,7 +429,8 @@ class cmMakefile;
   F(CMP0108)                                                                  \
   F(CMP0112)                                                                  \
   F(CMP0113)                                                                  \
-  F(CMP0119)
+  F(CMP0119)                                                                  \
+  F(CMP0131)
 
 /** \class cmPolicies
  * \brief Handles changes in CMake behavior and policies

+ 9 - 0
Tests/InterfaceLinkLibraries/CMakeLists.txt

@@ -59,3 +59,12 @@ set_property(TARGET bar_static_private APPEND PROPERTY INTERFACE_LINK_LIBRARIES
 
 add_executable(InterfaceLinkLibraries main_vs6_4.cpp)
 set_property(TARGET InterfaceLinkLibraries APPEND PROPERTY LINK_LIBRARIES bar_static_private)
+
+add_library(foo_link_only STATIC foo_link_only.c)
+target_compile_definitions(foo_link_only PUBLIC FOO_LINK_ONLY)
+add_executable(use_foo_link_only_CMP0131_OLD use_foo_link_only.c)
+target_link_libraries(use_foo_link_only_CMP0131_OLD PRIVATE "$<LINK_ONLY:foo_link_only>")
+target_compile_definitions(use_foo_link_only_CMP0131_OLD PRIVATE EXPECT_FOO_LINK_ONLY)
+cmake_policy(SET CMP0131 NEW)
+add_executable(use_foo_link_only_CMP0131_NEW use_foo_link_only.c)
+target_link_libraries(use_foo_link_only_CMP0131_NEW PRIVATE "$<LINK_ONLY:foo_link_only>")

+ 8 - 0
Tests/InterfaceLinkLibraries/foo_link_only.c

@@ -0,0 +1,8 @@
+#ifndef FOO_LINK_ONLY
+#  error "FOO_LINK_ONLY incorrectly not defined"
+#endif
+
+int foo_link_only(void)
+{
+  return 0;
+}

+ 16 - 0
Tests/InterfaceLinkLibraries/use_foo_link_only.c

@@ -0,0 +1,16 @@
+#ifdef EXPECT_FOO_LINK_ONLY
+#  ifndef FOO_LINK_ONLY
+#    error "FOO_LINK_ONLY incorrectly not defined"
+#  endif
+#else
+#  ifdef FOO_LINK_ONLY
+#    error "FOO_LINK_ONLY incorrectly defined"
+#  endif
+#endif
+
+extern int foo_link_only(void);
+
+int main(void)
+{
+  return foo_link_only();
+}

+ 1 - 0
Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt

@@ -35,6 +35,7 @@
    \* CMP0112
    \* CMP0113
    \* CMP0119
+   \* CMP0131
 
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)