Static libraries de-duplication: keep first occurrence

Fixes: #26335
This commit is contained in:
Marc Chevrier 2024-09-29 15:56:04 +02:00 committed by Brad King
parent 9b5c805bf6
commit cd418d4bb6
9 changed files with 134 additions and 24 deletions

View File

@ -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>

View File

@ -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
Help/policy/CMP0179.rst Normal file
View File

@ -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

View File

@ -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`.

View File

@ -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`.

View File

@ -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));
}

View File

@ -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) \

View File

@ -16,29 +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)
if("DEDUPLICATION=ALL" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING)
if("ORDER=REVERSE" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING)
set(RunCMake-stderr-file ${case}-stderr-dedup-reverse.txt)
else()
set(RunCMake-stderr-file ${case}-stderr-dedup.txt)
endif()
endif()
run_cmake(${case})
unset(RunCMake-stderr-file)
set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
if(exe)
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)
set(RunCMake-stdout-file ${case}-run-stdout-dedup-reverse.txt)
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-stdout-file ${case}-run-stdout-dedup.txt)
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")

View File

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