Browse Source

Merge topic 'static-libraries-deduplication'

cd418d4bb6 Static libraries de-duplication: keep first occurrence
9b5c805bf6 Tests/RunCMake/LinkLibrariesStrategy: Check ordering results more strongly

Acked-by: Kitware Robot <[email protected]>
Tested-by: buildbot <[email protected]>
Merge-request: !9864
Brad King 1 year ago
parent
commit
1ee630e06f

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

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.31
 .. toctree::
    :maxdepth: 1
 
+   CMP0179: De-duplication of static libraries on link lines keeps first occurrence. </policy/CMP0179>
    CMP0178: Test command lines preserve empty arguments. </policy/CMP0178>
    CMP0177: install() DESTINATION paths are normalized. </policy/CMP0177>
    CMP0176: execute_process() ENCODING is UTF-8 by default. </policy/CMP0176>

+ 5 - 0
Help/policy/CMP0156.rst

@@ -34,6 +34,11 @@ are de-duplicated by keeping their first occurrence, thus respecting the
 project-specified order.  This policy provides compatibility with projects
 that have not been updated to expect the latter behavior.
 
+.. note::
+
+  When this policy is set to ``NEW``, the policy :policy:`CMP0179` controls
+  which occurrence of the static libraries is kept when they are de-duplicated.
+
 The ``OLD`` behavior for this policy is to always repeat static libraries
 as if using a traditional linker, and always de-duplicate shared libraries
 by keeping the last occurrence of each.  The ``NEW`` behavior for this policy

+ 28 - 0
Help/policy/CMP0179.rst

@@ -0,0 +1,28 @@
+CMP0179
+-------
+
+.. versionadded:: 3.31
+
+De-duplication of static libraries on link lines keeps first occurrence.
+This policy is only relevant when policy :policy:`CMP0156` is set to ``NEW``.
+
+Based on the linker capabilities, the static libraries can
+be de-duplicated. See policy :policy:`CMP0156` for more information.
+
+CMake 3.30 and below may choose to keep, on some platforms, the last occurrence
+of the static libraries rather than the fist occurrence when they are
+de-duplicated.
+
+CMake 3.31 and above prefer to keep, on all platforms, the first occurrence of
+the static libraries when they are de-duplicated.
+
+The ``OLD`` behavior for this policy is to keep, on some platforms, the last
+occurrence of the static libraries when they are de-duplicated.  The ``NEW``
+behavior for this policy is to keep the first occurrence of the static
+libraries when they are de-duplicated, regardless of the platform.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.31
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: STANDARD_ADVICE.txt
+
+.. include:: DEPRECATED.txt

+ 6 - 0
Help/release/dev/static-libraries-deduplication.rst

@@ -0,0 +1,6 @@
+static-libraries-deduplication
+------------------------------
+
+* When static libraries on link lines are de-duplicated (by policy
+  :policy:`CMP0156`), the first occurrence is now kept on all platforms.
+  See policy :policy:`CMP0179`.

+ 1 - 1
Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst

@@ -65,4 +65,4 @@ The supported strategies are:
 
   Regardless of the strategy used, the actual linker invocation for
   some platforms may de-duplicate entries based on linker capabilities.
-  See policy :policy:`CMP0156`.
+  See policies :policy:`CMP0156` and :policy:`CMP0179`.

+ 63 - 2
Source/cmComputeLinkDepends.cxx

@@ -381,6 +381,34 @@ public:
           target->GetBacktrace());
         CM_FALLTHROUGH;
       case cmPolicies::NEW: {
+        // Policy 0179 applies only when policy 0156 is new
+        switch (target->GetPolicyStatusCMP0179()) {
+          case cmPolicies::WARN:
+            if (!makefile->GetCMakeInstance()->GetIsInTryCompile() &&
+                makefile->PolicyOptionalWarningEnabled(
+                  "CMAKE_POLICY_WARNING_CMP0179")) {
+              makefile->GetCMakeInstance()->IssueMessage(
+                MessageType::AUTHOR_WARNING,
+                cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0179),
+                         "\nSince the policy is not set, static libraries "
+                         "de-duplication will keep the last occurrence of the "
+                         "static libraries."),
+                target->GetBacktrace());
+            }
+            CM_FALLTHROUGH;
+          case cmPolicies::OLD:
+            break;
+          case cmPolicies::REQUIRED_IF_USED:
+          case cmPolicies::REQUIRED_ALWAYS:
+            makefile->GetCMakeInstance()->IssueMessage(
+              MessageType::FATAL_ERROR,
+              cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0179),
+              target->GetBacktrace());
+            CM_FALLTHROUGH;
+          case cmPolicies::NEW:
+            break;
+        }
+
         if (auto libProcessing = makefile->GetDefinition(cmStrCat(
               "CMAKE_", linkLanguage, "_LINK_LIBRARIES_PROCESSING"))) {
           // UNICITY keyword is just for compatibility with previous
@@ -444,9 +472,42 @@ public:
   void AddLibraries(const std::vector<size_t>& libEntries)
   {
     if (this->Order == Reverse) {
+      std::vector<size_t> entries;
+      if (this->Deduplication == All &&
+          this->Target->GetPolicyStatusCMP0179() == cmPolicies::NEW) {
+        // keep the first occurrence of the static libraries
+        std::set<size_t> emitted{ this->Emitted };
+        std::set<std::string> importedEmitted;
+        for (auto index : libEntries) {
+          LinkEntry const& entry = this->Entries[index];
+          if (!entry.Target ||
+              entry.Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
+            entries.emplace_back(index);
+            continue;
+          }
+          if (this->IncludeEntry(entry)) {
+            entries.emplace_back(index);
+            continue;
+          }
+          if (entry.Target->IsImported()) {
+            if (emitted.insert(index).second &&
+                importedEmitted
+                  .insert(cmSystemTools::GetRealPath(entry.Item.Value))
+                  .second) {
+              entries.emplace_back(index);
+            }
+            continue;
+          }
+          if (emitted.insert(index).second) {
+            entries.emplace_back(index);
+          }
+        }
+      } else {
+        entries = libEntries;
+      }
       // Iterate in reverse order so we can keep only the last occurrence
-      // of a library.
-      this->AddLibraries(cmReverseRange(libEntries));
+      // of the shared libraries.
+      this->AddLibraries(cmReverseRange(entries));
     } else {
       this->AddLibraries(cmMakeRange(libEntries));
     }

+ 7 - 2
Source/cmPolicies.h

@@ -545,7 +545,11 @@ class cmMakefile;
   SELECT(POLICY, CMP0177, "install() DESTINATION paths are normalized.", 3,   \
          31, 0, cmPolicies::WARN)                                             \
   SELECT(POLICY, CMP0178, "Test command lines preserve empty arguments.", 3,  \
-         31, 0, cmPolicies::WARN)
+         31, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0179,                                                     \
+         "De-duplication of static libraries on link lines keeps first "      \
+         "occurrence.",                                                       \
+         3, 31, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
@@ -589,7 +593,8 @@ class cmMakefile;
   F(CMP0156)                                                                  \
   F(CMP0157)                                                                  \
   F(CMP0160)                                                                  \
-  F(CMP0162)
+  F(CMP0162)                                                                  \
+  F(CMP0179)
 
 #define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F)                                  \
   F(CMP0116)                                                                  \

+ 0 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt → Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-dedup-reverse.txt


+ 1 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-dedup.txt

@@ -0,0 +1 @@
+^Library 'A' was linked first\.$

+ 10 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr-dedup-reverse.txt

@@ -0,0 +1,10 @@
+target \[main\] link dependency ordering:
+  target \[A\]
+  target \[B\]
+  target \[C\]
+  target \[A\]
+
+target \[main\] link line:
+  target \[B\]
+  target \[C\]
+  target \[A\]$

+ 10 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr-dedup.txt

@@ -0,0 +1,10 @@
+target \[main\] link dependency ordering:
+  target \[A\]
+  target \[B\]
+  target \[C\]
+  target \[A\]
+
+target \[main\] link line:
+  target \[A\]
+  target \[B\]
+  target \[C\]$

+ 4 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt

@@ -5,3 +5,7 @@ target \[main\] link dependency ordering:
   target \[A\]
 
 target \[main\] link line:
+  target \[A\]
+  target \[B\]
+  target \[C\]
+  target \[A\]$

+ 1 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout-dedup-reverse.txt

@@ -0,0 +1 @@
+^Library 'B' was linked first\.$

+ 1 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout-dedup.txt

@@ -0,0 +1 @@
+^Library 'B' was linked first\.$

+ 9 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr-dedup-reverse.txt

@@ -0,0 +1,9 @@
+target \[main\] link dependency ordering:
+  target \[B\]
+  target \[C\]
+  target \[A\]
+
+target \[main\] link line:
+  target \[B\]
+  target \[C\]
+  target \[A\]$

+ 9 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr-dedup.txt

@@ -0,0 +1,9 @@
+target \[main\] link dependency ordering:
+  target \[B\]
+  target \[C\]
+  target \[A\]
+
+target \[main\] link line:
+  target \[B\]
+  target \[C\]
+  target \[A\]$

+ 3 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt

@@ -4,3 +4,6 @@ target \[main\] link dependency ordering:
   target \[A\]
 
 target \[main\] link line:
+  target \[B\]
+  target \[C\]
+  target \[A\]$

+ 25 - 10
Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake

@@ -16,17 +16,32 @@ include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake")
 run_cmake(Unknown)
 
 function(run_strategy case exe)
-  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
-  run_cmake(${case})
-  set(RunCMake_TEST_NO_CLEAN 1)
-  run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
-  if(exe)
-    if("ORDER=REVERSE" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING)
-      set(RunCMake-stdout-file ${case}-run-stdout-reverse.txt)
+  foreach(cmp0179 OLD NEW)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-CMP0179-${cmp0179}-build)
+    set(RunCMake_TEST_VARIANT_DESCRIPTION "...CMP0179-${cmp0179}")
+    if("DEDUPLICATION=ALL" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING)
+      if("ORDER=REVERSE" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING AND cmp0179 STREQUAL "OLD")
+        set(RunCMake-stderr-file ${case}-stderr-dedup-reverse.txt)
+      else()
+        set(RunCMake-stderr-file ${case}-stderr-dedup.txt)
+      endif()
     endif()
-    run_cmake_command(${case}-run ${RunCMake_TEST_BINARY_DIR}/${exe})
-    unset(RunCMake-stdout-file)
-  endif()
+    run_cmake_with_options(${case} -DCMAKE_POLICY_DEFAULT_CMP0179=${cmp0179})
+    unset(RunCMake-stderr-file)
+    set(RunCMake_TEST_NO_CLEAN 1)
+    run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
+    if(exe)
+      if("DEDUPLICATION=ALL" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING)
+        if("ORDER=REVERSE" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING AND cmp0179 STREQUAL "OLD")
+          set(RunCMake-stdout-file ${case}-run-stdout-dedup-reverse.txt)
+        else()
+          set(RunCMake-stdout-file ${case}-run-stdout-dedup.txt)
+        endif()
+      endif()
+      run_cmake_command(${case}-run ${RunCMake_TEST_BINARY_DIR}/${exe})
+      unset(RunCMake-stdout-file)
+    endif()
+  endforeach()
 endfunction()
 
 run_strategy(Basic-PRESERVE_ORDER "main")

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

@@ -43,6 +43,7 @@
    \* CMP0157
    \* CMP0160
    \* CMP0162
+   \* CMP0179
 
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)