summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/target_link_libraries.rst5
-rw-r--r--Help/manual/cmake-properties.7.rst1
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/prop_tgt/LINK_LIBRARIES.rst5
-rw-r--r--Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst11
-rw-r--r--Help/release/dev/link-strategy.rst7
-rw-r--r--Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst68
-rw-r--r--Source/cmComputeLinkDepends.cxx22
-rw-r--r--Source/cmComputeLinkDepends.h10
-rw-r--r--Source/cmComputeLinkInformation.cxx20
-rw-r--r--Source/cmTarget.cxx1
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt1
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt7
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake2
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt6
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake2
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake15
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Basic.c11
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/BasicA.c4
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/BasicB.c5
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/BasicC.c5
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/BasicX.c7
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt15
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake2
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt9
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake2
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake12
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c4
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake12
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake36
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt1
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt4
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake5
-rw-r--r--Tests/RunCMake/LinkLibrariesStrategy/main.c4
38 files changed, 323 insertions, 5 deletions
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index a82adda..94a2429 100644
--- a/Help/command/target_link_libraries.rst
+++ b/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.
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 9ad856d..10dbe10 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/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
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index a79747f..cc10950 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/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
diff --git a/Help/prop_tgt/LINK_LIBRARIES.rst b/Help/prop_tgt/LINK_LIBRARIES.rst
index b5c1d89..b449aa1 100644
--- a/Help/prop_tgt/LINK_LIBRARIES.rst
+++ b/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.
diff --git a/Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst b/Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst
new file mode 100644
index 0000000..bba707c
--- /dev/null
+++ b/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.
diff --git a/Help/release/dev/link-strategy.rst b/Help/release/dev/link-strategy.rst
new file mode 100644
index 0000000..ab626d1
--- /dev/null
+++ b/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.
diff --git a/Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst b/Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst
new file mode 100644
index 0000000..1ba6b27
--- /dev/null
+++ b/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`.
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index ae33c12..70e992e 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/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
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 55f0032..8b8aba4 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/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;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index dd194ed..26ff326 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/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;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index da0091b..f220837 100644
--- a/Source/cmTarget.cxx
+++ b/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
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 40db51b..ba8776f 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/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)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt
new file mode 100644
index 0000000..7e46d1ba
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt
@@ -0,0 +1 @@
+^Library 'B' was linked first\.$
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt
new file mode 100644
index 0000000..6ef12eb
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt
@@ -0,0 +1 @@
+^Library 'A' was linked first\.$
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt
new file mode 100644
index 0000000..1d8f4ba
--- /dev/null
+++ b/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:
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake
new file mode 100644
index 0000000..f3dc096
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY PRESERVE_ORDER)
+include(Basic-common.cmake)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt
new file mode 100644
index 0000000..7e46d1ba
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt
@@ -0,0 +1 @@
+^Library 'B' was linked first\.$
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt
new file mode 100644
index 0000000..54b02bd
--- /dev/null
+++ b/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:
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake
new file mode 100644
index 0000000..8e62377
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY REORDER)
+include(Basic-common.cmake)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake
new file mode 100644
index 0000000..8dbbd39
--- /dev/null
+++ b/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}>")
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic.c b/Tests/RunCMake/LinkLibrariesStrategy/Basic.c
new file mode 100644
index 0000000..124d489
--- /dev/null
+++ b/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();
+}
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicA.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicA.c
new file mode 100644
index 0000000..d3fe95d
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/BasicA.c
@@ -0,0 +1,4 @@
+int BasicA(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicB.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicB.c
new file mode 100644
index 0000000..fd7a120
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/BasicB.c
@@ -0,0 +1,5 @@
+extern int BasicA(void);
+int BasicB(void)
+{
+ return BasicA();
+}
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicC.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicC.c
new file mode 100644
index 0000000..7171dd1
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/BasicC.c
@@ -0,0 +1,5 @@
+extern int BasicA(void);
+int BasicC(void)
+{
+ return BasicA();
+}
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicX.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicX.c
new file mode 100644
index 0000000..39f7863
--- /dev/null
+++ b/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;
+}
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt b/Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt
new file mode 100644
index 0000000..dda37d8
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.30)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt
new file mode 100644
index 0000000..2637f93
--- /dev/null
+++ b/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:
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake
new file mode 100644
index 0000000..9f694db
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY PRESERVE_ORDER)
+include(Duplicate-common.cmake)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt
new file mode 100644
index 0000000..2353288
--- /dev/null
+++ b/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:
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake
new file mode 100644
index 0000000..cc51e0a
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_LINK_LIBRARIES_STRATEGY REORDER)
+include(Duplicate-common.cmake)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake
new file mode 100644
index 0000000..5050a0a
--- /dev/null
+++ b/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
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake
new file mode 100644
index 0000000..fd5da91
--- /dev/null
+++ b/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}")
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake b/Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake
new file mode 100644
index 0000000..1b02355
--- /dev/null
+++ b/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)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt b/Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt
new file mode 100644
index 0000000..3081f32
--- /dev/null
+++ b/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\)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake
new file mode 100644
index 0000000..d3ad586
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake
@@ -0,0 +1,5 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARIES_STRATEGY unknown)
+
+add_executable(main main.c)
diff --git a/Tests/RunCMake/LinkLibrariesStrategy/main.c b/Tests/RunCMake/LinkLibrariesStrategy/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/LinkLibrariesStrategy/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}