GenEx/LINK_LIBRARY: Add NEEDED_LIBRARY support on Linux

This commit is contained in:
Robert Maynard
2026-08-13 13:45:19 -04:00
committed by Brad King
parent 158b64688f
commit a2e6306c27
7 changed files with 66 additions and 0 deletions
@@ -0,0 +1,6 @@
link-library-needed-library-linux
----------------------------------
* The :genex:`$<LINK_LIBRARY:NEEDED_LIBRARY,...>` generator expression feature
is now supported on Linux with GNU-compatible linkers (GNU ld, gold, LLD,
MOLD).
@@ -101,6 +101,19 @@
Uses the ``-needed_library`` or ``-needed-l`` option as appropriate,
with the same linker constraints as ``NEEDED_FRAMEWORK``.
Linux
.. versionadded:: 4.5
Wraps the library with ``--no-as-needed`` / ``--as-needed`` to force
an entry in the binary's ``DT_NEEDED`` list regardless of whether any
symbols from the library are directly referenced. When the linker
supports ``--push-state`` / ``--pop-state`` (GNU ld >= 2.25, gold,
LLD, MOLD), the state-stacking form is used instead to correctly
restore the pre-existing ``--as-needed`` state rather than
unconditionally enabling it after the library. This feature is only
meaningful for shared libraries; applying it to a static library
produces a developer warning and has no effect.
``REEXPORT_LIBRARY``
This is similar to the ``REEXPORT_FRAMEWORK`` feature, except it is for use
with non-framework targets or libraries (Apple platforms only).
+25
View File
@@ -57,6 +57,31 @@ function(__cmake_set_whole_archive_feature __linker __linker_options)
set(CMAKE_${__lang}LINKER_PUSHPOP_STATE_SUPPORTED "${CMAKE_${__lang}LINKER_PUSHPOP_STATE_SUPPORTED}" PARENT_SCOPE)
endfunction()
# NEEDED_LIBRARY Feature for LINK_LIBRARY generator expression
## Force a shared library into DT_NEEDED even when no symbols are referenced
function(__cmake_set_needed_library_feature __linker __linker_options)
unset(__lang)
if(ARGC EQUAL "3")
set(__lang "${ARGV2}_")
endif()
__cmake_check_linker_pushpop_state("${__linker}" "${__linker_options}" ${ARGV2})
## NEEDED_LIBRARY: Force DT_NEEDED entry for a shared library
if(CMAKE_${__lang}LINKER_PUSHPOP_STATE_SUPPORTED)
set(CMAKE_${__lang}LINK_LIBRARY_USING_NEEDED_LIBRARY "LINKER:--push-state,--no-as-needed"
"<LINK_ITEM>"
"LINKER:--pop-state" PARENT_SCOPE)
else()
set(CMAKE_${__lang}LINK_LIBRARY_USING_NEEDED_LIBRARY "LINKER:--no-as-needed"
"<LINK_ITEM>"
"LINKER:--as-needed" PARENT_SCOPE)
endif()
set(CMAKE_${__lang}LINK_LIBRARY_USING_NEEDED_LIBRARY_SUPPORTED TRUE PARENT_SCOPE)
set(CMAKE_${__lang}LINK_LIBRARY_NEEDED_LIBRARY_ATTRIBUTES LIBRARY_TYPE=SHARED DEDUPLICATION=DEFAULT OVERRIDE=DEFAULT PARENT_SCOPE)
set(CMAKE_${__lang}LINKER_PUSHPOP_STATE_SUPPORTED "${CMAKE_${__lang}LINKER_PUSHPOP_STATE_SUPPORTED}" PARENT_SCOPE)
endfunction()
## Configure system linker
__cmake_set_whole_archive_feature("${CMAKE_LINKER}" "")
__cmake_set_needed_library_feature("${CMAKE_LINKER}" "")
+3
View File
@@ -13,5 +13,8 @@ macro(__linux_linker_gnu lang)
__cmake_set_whole_archive_feature("${CMAKE_${lang}_COMPILER_LINKER}"
"${CMAKE_${lang}_COMPILER_LINKER_ARCHITECTURE_FLAGS}"
"${lang}")
__cmake_set_needed_library_feature("${CMAKE_${lang}_COMPILER_LINKER}"
"${CMAKE_${lang}_COMPILER_LINKER_ARCHITECTURE_FLAGS}"
"${lang}")
endif()
endmacro()
@@ -123,6 +123,11 @@ if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES
if (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION GREATER_EQUAL "12")
run_cmake_target(apple_library needed_library main-needed_library)
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang"))
run_cmake(linux_library_external)
run_cmake_target(linux_library_external build external)
run_cmake_with_options(linux_library "-DRunCMake_BINARY_DIR=${RunCMake_BINARY_DIR}")
run_cmake_target(linux_library needed_library main-needed_library)
endif()
# WHOLE_ARCHIVE feature
@@ -0,0 +1,10 @@
enable_language(C)
add_library(lib SHARED base.c lib.c)
# feature NEEDED_LIBRARY
add_executable(main-needed_library main.c)
target_link_directories(main-needed_library PRIVATE "${RunCMake_BINARY_DIR}/linux_library_external-build"
"${RunCMake_BINARY_DIR}/linux_library_external-build/$<CONFIG>")
target_link_libraries(main-needed_library PRIVATE "$<LINK_LIBRARY:NEEDED_LIBRARY,lib,external>")
@@ -0,0 +1,4 @@
enable_language(C)
add_library(external SHARED unref.c)