Avoid duplicate linking to avoid Xcode 15 warnings

Xcode 15 includes a new linker which complains when passing a static library more than once to the linker.

What do we need to pay attention to to prevent CMake from duplicating libraries? What is a convenient way to determine why a library got duplicated?

The motivation for this question is this issue with igraph: "ignoring duplicate libraries" and "duplicate LC_RPATH are deprecated" linker warnings · Issue #2394 · igraph/igraph · GitHub (now resolved).

Here’s a minimal example that demonstrates how a static library may get included twice on the linker line. It took much trial and error to distil down a much more complex system to this example.

cmake_minimum_required(VERSION 3.18)
project(Foo)

add_library(one one.c)

add_library(two OBJECT two.c)
target_link_libraries(two PRIVATE one)

add_executable(main main.c)
target_link_libraries(main PRIVATE one)
target_link_libraries(main PRIVATE two)

This links libone.a twice. If we reverse the order of the last two lines, as in the following code block, then there is no duplication.

target_link_libraries(main PRIVATE two)
target_link_libraries(main PRIVATE one)

Is this by design? Is there a simple way to avoid duplication without reversing the order? More importantly, is there a simple way to determine where the duplication came from (in a large CMake-based project) and what specifically needs to be reordered?

On many platforms, linkers do not re-scan static libraries from earlier on the link line to satisfy symbol dependencies of those later on the link line. target_link_libraries(two PRIVATE one) says that two’s symbols may depend on symbols from one. In order to satisfy this, CMake ensures that one appears on the link line after two. However, you also told CMake that main needs to link to one and then two. We always preserve the direct link dependencies in order, and then add transitive dependencies afterward. The only way to satisfy both requirements is to generate one two one on the link line.

IIRC, Apple’s linker does re-scan static libraries, so repeating them is not needed to satisfy dependencies. This is similar to how linkers treat shared libraries, which we do de-duplicate. That code could be updated to de-duplicate static libraries too when using the Apple linker.

1 Like

Thanks, this makes it clear what is going on.

This would be useful. I am encountering a situation where the duplicate library is -lc++, which is implicit, and I can’t seem to figure out any reordering of CMake commands that helps.

Meanwhile try adding

target_link_options(main PRIVATE LINKER:-no_warn_duplicate_libraries)

to suppress the warning, though it may take some investigation to determine the proper condition for whether the new Apple linker is used.

2 Likes

This is now tracked as CMake Issue 25297.

1 Like