Automatically wrapping a static library in "whole-archive"/"no-whole-archive" when used during linking

Hi,

what is the correct way to add some linking flags whenever a certain static library is used when linking an executable?

Example:

  • there is a static library L (providing its own public include directories and maybe depending on other libraries)
  • whenever L is linked into an exectuable, the reference to L shall be enclosed in an -Wl,--whole-archive / -Wl,--no-whole-archive pair

During my search for a solution, I found this message in the forum, but got errors for instance because the static jni_component does not contain any sources.

I tried to modify the example a litte, and apparently the following seems to work somehow…

# this is the *actual* library (with a little decoration) but named internal_L rather than just L
add_library(internal_L my.c sources.c)
target_include_directories(internal_L my_header_folder)
target_link_libraries(internal_L libraries_we_depend_on)

# this is the "wrapper", but defined as *INTERFACE* library
add_library(L INTERFACE)
target_link_libraries(L INTERFACE internal_L)
target_link_options(L INTERFACE "SHELL:-Wl,--whole-archive $<TARGET_FILE:internal_L> -Wl,--no-whole-archive")

# now use L in an executable
add_executable(my_executable some.c source.c)
target_link_libraries(my_executable PRIVATE L)

Can you confirm that this is the correct way to solve the problem (apart from the limitation to toolchains which support the -Wl,--*whole-archive options)? If not, can you suggest an alternative approach?

Kind regards
Ingolf

Starting with CMake 3.24 (currently in RC1), you can use $<LINK_LIBRARY> generator expression with feature WHOLE_ARCHIVE to achieve what you want:

add_library(L INTERFACE)
target_link_libraries(L INTERFACE "$<LINK_LIBRARY:WHOLE_ARCHIVE,internal_L>")
1 Like

@marc.chevrier, thank you for this hint. Unfortunately, we cannot switch to a RC. Would you recommend a different approach also to pre-3.24 CMake users (3.21.3 in our case)?

Before 3.24, there is no specific CMake feature to support this requirement.
What you did seems reasonable, but be aware that the library internal_L will be repeated twice on the link command (one from target_link_libraries and one from target_link_options).

1 Like

From several search results I previously encountered the following solution. Using CMake 3.17 on a native build environment [Ubuntu 22.04 with gcc or Windows 10 with MinGW] this yielded the desired effects [correct linking and target-properties propagation]:

target_link_libraries(L
    INTERFACE -Wl,--whole-archive internal_L -Wl,--no-whole-archive
)

However using this approach failed [i.e. no `whole-archive` was present in the created compile command] with a cross-compile setup [on an Ubuntu 18.04 server with a gcc for a non-native architecture] - whereas the approach detailed in @ingolf 's question above seemed to work [target_link_options].

Does anyone have an idea as to why CMake might behave differently? Is this a CMake behaviour or is something else involved?

I would appreciate any ideas

Johannes