Ver Fonte

Linking: Optionally reorder direct dependencies from LINK_LIBRARIES

Traditionally CMake generates link lines by starting with the direct
link dependencies specified by `LINK_LIBRARIES` in their original order
and then appending indirect dependencies that the direct dependencies
do not express.  This gives projects control over ordering among
independent entries, which can be important when intermixing flags
and libraries, or when multiple libraries provide the same symbol.
However, it may also result in inefficient link lines.

Add support for an alternative strategy that can reorder direct link
dependencies to produce more efficient link lines.  This is useful
for projects that cannot easily specify their targets' direct
dependencies in an order that satisfies indirect dependencies.

Add a `CMAKE_LINK_LIBRARIES_STRATEGY` variable and corresponding
`LINK_LIBRARIES_STRATEGY` target property to select a strategy.

Fixes: #26271
Brad King há 1 ano atrás
pai
commit
7abd3137b7
38 ficheiros alterados com 323 adições e 5 exclusões
  1. 5 0
      Help/command/target_link_libraries.rst
  2. 1 0
      Help/manual/cmake-properties.7.rst
  3. 1 0
      Help/manual/cmake-variables.7.rst
  4. 5 0
      Help/prop_tgt/LINK_LIBRARIES.rst
  5. 11 0
      Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst
  6. 7 0
      Help/release/dev/link-strategy.rst
  7. 68 0
      Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst
  8. 19 3
      Source/cmComputeLinkDepends.cxx
  9. 9 1
      Source/cmComputeLinkDepends.h
  10. 19 1
      Source/cmComputeLinkInformation.cxx
  11. 1 0
      Source/cmTarget.cxx
  12. 1 0
      Tests/RunCMake/CMakeLists.txt
  13. 1 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt
  14. 1 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt
  15. 7 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt
  16. 2 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake
  17. 1 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt
  18. 6 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt
  19. 2 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake
  20. 15 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake
  21. 11 0
      Tests/RunCMake/LinkLibrariesStrategy/Basic.c
  22. 4 0
      Tests/RunCMake/LinkLibrariesStrategy/BasicA.c
  23. 5 0
      Tests/RunCMake/LinkLibrariesStrategy/BasicB.c
  24. 5 0
      Tests/RunCMake/LinkLibrariesStrategy/BasicC.c
  25. 7 0
      Tests/RunCMake/LinkLibrariesStrategy/BasicX.c
  26. 3 0
      Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt
  27. 15 0
      Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt
  28. 2 0
      Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake
  29. 9 0
      Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt
  30. 2 0
      Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake
  31. 12 0
      Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake
  32. 4 0
      Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c
  33. 12 0
      Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake
  34. 36 0
      Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake
  35. 1 0
      Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt
  36. 4 0
      Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt
  37. 5 0
      Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake
  38. 4 0
      Tests/RunCMake/LinkLibrariesStrategy/main.c

+ 5 - 0
Help/command/target_link_libraries.rst

@@ -140,6 +140,11 @@ Items containing ``::``, such as ``Foo::Bar``, are assumed to be
 target names and will cause an error if no such target exists.
 See policy :policy:`CMP0028`.
 
+See the :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable and
+corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target property
+for details on how CMake orders direct link dependencies on linker
+command lines.
+
 See the :manual:`cmake-buildsystem(7)` manual for more on defining
 buildsystem properties.
 

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

@@ -336,6 +336,7 @@ Properties on Targets
    /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG
    /prop_tgt/LINK_LIBRARIES
    /prop_tgt/LINK_LIBRARIES_ONLY_TARGETS
+   /prop_tgt/LINK_LIBRARIES_STRATEGY
    /prop_tgt/LINK_LIBRARY_OVERRIDE
    /prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY
    /prop_tgt/LINK_OPTIONS

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

@@ -491,6 +491,7 @@ Variables that Control the Build
    /variable/CMAKE_LINK_GROUP_USING_FEATURE
    /variable/CMAKE_LINK_GROUP_USING_FEATURE_SUPPORTED
    /variable/CMAKE_LINK_INTERFACE_LIBRARIES
+   /variable/CMAKE_LINK_LIBRARIES_STRATEGY
    /variable/CMAKE_LINK_LIBRARY_FEATURE_ATTRIBUTES
    /variable/CMAKE_LINK_LIBRARY_FILE_FLAG
    /variable/CMAKE_LINK_LIBRARY_FLAG

+ 5 - 0
Help/prop_tgt/LINK_LIBRARIES.rst

@@ -28,3 +28,8 @@ In advanced use cases, the list of direct link dependencies specified
 by this property may be updated by usage requirements from dependencies.
 See the :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` and
 :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE` target properties.
+
+See the :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable and
+corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target property
+for details on how CMake orders direct link dependencies on linker
+command lines.

+ 11 - 0
Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst

@@ -0,0 +1,11 @@
+LINK_LIBRARIES_STRATEGY
+-----------------------
+
+.. versionadded:: 3.31
+
+Specify a strategy for ordering a target's direct link dependencies
+on linker command lines.
+
+See the :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable for details
+and supported values.  This property is initialized by the value of that
+variable when a target is created.

+ 7 - 0
Help/release/dev/link-strategy.rst

@@ -0,0 +1,7 @@
+link-strategy
+-------------
+
+* The :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable and
+  corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target
+  property were added to optionally specify the strategy
+  CMake uses to generate link lines.

+ 68 - 0
Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst

@@ -0,0 +1,68 @@
+CMAKE_LINK_LIBRARIES_STRATEGY
+-----------------------------
+
+.. versionadded:: 3.31
+
+Specify a strategy for ordering targets' direct link dependencies
+on linker command lines.
+
+The value of this variable initializes the :prop_tgt:`LINK_LIBRARIES_STRATEGY`
+target property of targets as they are created.  Set that property directly
+to specify a strategy for a single target.
+
+CMake generates a target's link line using its :ref:`Target Link Properties`.
+In particular, the :prop_tgt:`LINK_LIBRARIES` target property records the
+target's direct link dependencies, typically populated by calls to
+:command:`target_link_libraries`.  Indirect link dependencies are
+propagated from those entries of :prop_tgt:`LINK_LIBRARIES` that name
+library targets by following the transitive closure of their
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` properties.  CMake supports multiple
+strategies for passing direct and indirect link dependencies to the linker.
+
+Consider this example for the strategies below:
+
+.. code-block:: cmake
+
+  add_library(A STATIC ...)
+  add_library(B STATIC ...)
+  add_library(C STATIC ...)
+  add_executable(main ...)
+  target_link_libraries(B PRIVATE A)
+  target_link_libraries(C PRIVATE A)
+  target_link_libraries(main PRIVATE A B C)
+
+The supported strategies are:
+
+``PRESERVE_ORDER``
+  Entries of :prop_tgt:`LINK_LIBRARIES` always appear first and in their
+  original order.  Indirect link dependencies not satisfied by the
+  original entries may be reordered and de-duplicated with respect to
+  one another, but are always appended after the original entries.
+  This may result in less efficient link lines, but gives projects
+  control of ordering among independent entries.  Such control may be
+  important when intermixing link flags with libraries, or when multiple
+  libraries provide a given symbol.
+
+  This is the default.
+
+  In the above example, this strategy computes a link line for ``main``
+  by starting with its original entries ``A B C``, and then appends
+  another ``A`` to satisfy the dependencies of ``B`` and ``C`` on ``A``.
+  The final order is ``A B C A``.
+
+``REORDER``
+  Entries of :prop_tgt:`LINK_LIBRARIES` may be reordered, de-duplicated,
+  and intermixed with indirect link dependencies.  This may result in
+  more efficient link lines, but does not give projects any control of
+  ordering among independent entries.
+
+  In the above example, this strategy computes a link line for ``main``
+  by re-ordering its original entries ``A B C`` to satisfy the
+  dependencies of ``B`` and ``C`` on ``A``.
+  The final order is ``B C A``.
+
+.. note::
+
+  Regardless of the strategy used, the actual linker invocation for
+  some platforms may de-duplicate entries based on linker capabilities.
+  See policy :policy:`CMP0156`.

+ 19 - 3
Source/cmComputeLinkDepends.cxx

@@ -581,7 +581,8 @@ std::string const& cmComputeLinkDepends::LinkEntry::DEFAULT =
 
 cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
                                            const std::string& config,
-                                           const std::string& linkLanguage)
+                                           const std::string& linkLanguage,
+                                           LinkLibrariesStrategy strategy)
   : Target(target)
   , Makefile(this->Target->Target->GetMakefile())
   , GlobalGenerator(this->Target->GetLocalGenerator()->GetGlobalGenerator())
@@ -592,6 +593,7 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
   , LinkLanguage(linkLanguage)
   , LinkType(CMP0003_ComputeLinkType(
       this->Config, this->Makefile->GetCMakeInstance()->GetDebugConfigs()))
+  , Strategy(strategy)
 
 {
   // target oriented feature override property takes precedence over
@@ -1488,8 +1490,22 @@ void cmComputeLinkDepends::OrderLinkEntries()
   }
 
   // Start with the original link line.
-  for (size_t originalEntry : this->OriginalEntries) {
-    this->VisitEntry(originalEntry);
+  switch (this->Strategy) {
+    case LinkLibrariesStrategy::PRESERVE_ORDER: {
+      // Emit the direct dependencies in their original order.
+      // This gives projects control over ordering.
+      for (size_t originalEntry : this->OriginalEntries) {
+        this->VisitEntry(originalEntry);
+      }
+    } break;
+    case LinkLibrariesStrategy::REORDER: {
+      // Schedule the direct dependencies for emission in topo order.
+      // This may produce more efficient link lines.
+      for (size_t originalEntry : this->OriginalEntries) {
+        this->MakePendingComponent(
+          this->CCG->GetComponentMap()[originalEntry]);
+      }
+    } break;
   }
 
   // Now explore anything left pending.  Since the component graph is

+ 9 - 1
Source/cmComputeLinkDepends.h

@@ -27,6 +27,12 @@ class cmMakefile;
 class cmSourceFile;
 class cmake;
 
+enum class LinkLibrariesStrategy
+{
+  PRESERVE_ORDER,
+  REORDER,
+};
+
 /** \class cmComputeLinkDepends
  * \brief Compute link dependencies for targets.
  */
@@ -35,7 +41,8 @@ class cmComputeLinkDepends
 public:
   cmComputeLinkDepends(cmGeneratorTarget const* target,
                        const std::string& config,
-                       const std::string& linkLanguage);
+                       const std::string& linkLanguage,
+                       LinkLibrariesStrategy strategy);
   ~cmComputeLinkDepends();
 
   cmComputeLinkDepends(const cmComputeLinkDepends&) = delete;
@@ -94,6 +101,7 @@ private:
   bool DebugMode = false;
   std::string LinkLanguage;
   cmTargetLinkLibraryType LinkType;
+  LinkLibrariesStrategy Strategy;
 
   EntryVector FinalLinkEntries;
   std::map<std::string, std::string> LinkLibraryOverride;

+ 19 - 1
Source/cmComputeLinkInformation.cxx

@@ -9,6 +9,7 @@
 
 #include <cm/memory>
 #include <cm/optional>
+#include <cm/string_view>
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
@@ -567,8 +568,25 @@ bool cmComputeLinkInformation::Compute()
     return false;
   }
 
+  LinkLibrariesStrategy strategy = LinkLibrariesStrategy::PRESERVE_ORDER;
+  if (cmValue s = this->Target->GetProperty("LINK_LIBRARIES_STRATEGY")) {
+    if (*s == "PRESERVE_ORDER"_s) {
+      strategy = LinkLibrariesStrategy::PRESERVE_ORDER;
+    } else if (*s == "REORDER"_s) {
+      strategy = LinkLibrariesStrategy::REORDER;
+    } else {
+      this->CMakeInstance->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("LINK_LIBRARIES_STRATEGY value '", *s,
+                 "' is not recognized."),
+        this->Target->GetBacktrace());
+      return false;
+    }
+  }
+
   // Compute the ordered link line items.
-  cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage);
+  cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage,
+                           strategy);
   cld.SetOldLinkDirMode(this->OldLinkDirMode);
   cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
   FeatureDescriptor const* currentFeature = nullptr;

+ 1 - 0
Source/cmTarget.cxx

@@ -466,6 +466,7 @@ TargetProperty const StaticTargetProperties[] = {
   { "LINKER_TYPE"_s, IC::CanCompileSources },
   { "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports },
   { "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget },
+  { "LINK_LIBRARIES_STRATEGY"_s, IC::NormalNonImportedTarget },
   { "LINK_SEARCH_START_STATIC"_s, IC::CanCompileSources },
   { "LINK_SEARCH_END_STATIC"_s, IC::CanCompileSources },
   // Initialize per-configuration name postfix property from the variable only

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -836,6 +836,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin|Windows)"
 endif()
 
 add_RunCMake_test(LinkLibrariesProcessing)
+add_RunCMake_test(LinkLibrariesStrategy)
 add_RunCMake_test(File_Archive)
 add_RunCMake_test(File_Configure)
 add_RunCMake_test(File_Generate)

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

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

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

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

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

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

+ 2 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake

@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY PRESERVE_ORDER)
+include(Basic-common.cmake)

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

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

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

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

+ 2 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake

@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY REORDER)
+include(Basic-common.cmake)

+ 15 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake

@@ -0,0 +1,15 @@
+enable_language(C)
+
+add_library(A STATIC BasicA.c BasicX.c)
+add_library(B STATIC BasicB.c BasicX.c)
+add_library(C STATIC BasicC.c BasicX.c)
+target_link_libraries(B PRIVATE A)
+target_link_libraries(C PRIVATE A)
+target_compile_definitions(A PRIVATE BASIC_ID="A")
+target_compile_definitions(B PRIVATE BASIC_ID="B")
+target_compile_definitions(C PRIVATE BASIC_ID="C")
+
+add_executable(main Basic.c)
+target_link_libraries(main PRIVATE A B C)
+set_property(TARGET main PROPERTY LINK_DEPENDS_DEBUG_MODE 1) # undocumented
+set_property(TARGET main PROPERTY RUNTIME_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}>")

+ 11 - 0
Tests/RunCMake/LinkLibrariesStrategy/Basic.c

@@ -0,0 +1,11 @@
+extern int BasicB(void);
+extern int BasicC(void);
+
+/* Use a symbol provided by a dedicated object file in A, B, and C.
+   The first library linked will determine the return value.  */
+extern int BasicX(void);
+
+int main(void)
+{
+  return BasicB() + BasicC() + BasicX();
+}

+ 4 - 0
Tests/RunCMake/LinkLibrariesStrategy/BasicA.c

@@ -0,0 +1,4 @@
+int BasicA(void)
+{
+  return 0;
+}

+ 5 - 0
Tests/RunCMake/LinkLibrariesStrategy/BasicB.c

@@ -0,0 +1,5 @@
+extern int BasicA(void);
+int BasicB(void)
+{
+  return BasicA();
+}

+ 5 - 0
Tests/RunCMake/LinkLibrariesStrategy/BasicC.c

@@ -0,0 +1,5 @@
+extern int BasicA(void);
+int BasicC(void)
+{
+  return BasicA();
+}

+ 7 - 0
Tests/RunCMake/LinkLibrariesStrategy/BasicX.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int BasicX(void)
+{
+  printf("Library '%s' was linked first.\n", BASIC_ID);
+  return 0;
+}

+ 3 - 0
Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.30)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 15 - 0
Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt

@@ -0,0 +1,15 @@
+target \[main\] link dependency ordering:
+  item \[-Flag1\]
+  target \[A\]
+  item \[-Flag1\]
+  target \[B\]
+  item \[-Flag2\]
+  target \[C\]
+  item \[-Flag2\]
+  target \[A\]
+  item \[-Flag2\]
+  target \[B\]
+  item \[-Flag3\]
+  target \[C\]
+
+target \[main\] link line:

+ 2 - 0
Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake

@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY PRESERVE_ORDER)
+include(Duplicate-common.cmake)

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

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

+ 2 - 0
Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake

@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY REORDER)
+include(Duplicate-common.cmake)

+ 12 - 0
Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake

@@ -0,0 +1,12 @@
+enable_language(C)
+
+add_library(A INTERFACE IMPORTED)
+add_library(B INTERFACE IMPORTED)
+add_library(C INTERFACE IMPORTED)
+set_property(TARGET A PROPERTY IMPORTED_LIBNAME A)
+set_property(TARGET B PROPERTY IMPORTED_LIBNAME B)
+set_property(TARGET C PROPERTY IMPORTED_LIBNAME C)
+
+add_executable(main Duplicate.c)
+target_link_libraries(main PRIVATE -Flag1 A -Flag1 B -Flag2 C -Flag2 A -Flag2 B -Flag3 C)
+set_property(TARGET main PROPERTY LINK_DEPENDS_DEBUG_MODE 1) # undocumented

+ 4 - 0
Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}

+ 12 - 0
Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake

@@ -0,0 +1,12 @@
+enable_language(C)
+
+set(info "")
+foreach(var
+    CMAKE_C_LINK_LIBRARIES_PROCESSING
+    )
+  if(DEFINED ${var})
+    string(APPEND info "set(${var} \"${${var}}\")\n")
+  endif()
+endforeach()
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")

+ 36 - 0
Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake

@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.30)
+
+include(RunCMake)
+
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
+else()
+  set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+endif()
+
+# Detect information from the toolchain:
+# - CMAKE_C_LINK_LIBRARIES_PROCESSING
+run_cmake(Inspect)
+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)
+    endif()
+    run_cmake_command(${case}-run ${RunCMake_TEST_BINARY_DIR}/${exe})
+    unset(RunCMake-stdout-file)
+  endif()
+endfunction()
+
+run_strategy(Basic-PRESERVE_ORDER "main")
+run_strategy(Basic-REORDER "main")
+
+run_cmake(Duplicate-PRESERVE_ORDER)
+run_cmake(Duplicate-REORDER)

+ 1 - 0
Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at Unknown.cmake:5 \(add_executable\):
+  LINK_LIBRARIES_STRATEGY value 'unknown' is not recognized\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9] \(include\)

+ 5 - 0
Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARIES_STRATEGY unknown)
+
+add_executable(main main.c)

+ 4 - 0
Tests/RunCMake/LinkLibrariesStrategy/main.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}