# Avoid duplicate linking to avoid Xcode 15 warnings

**URL:** https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084
**Category:** Code
**Tags:** os:macos
**Created:** [September 25, 2023, 4:33pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084 "2023-09-25T16:33:18Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![szhorvat](https://discourse.cmake.org/user_avatar/discourse.cmake.org/szhorvat/32/1906_2.png) [@szhorvat](https://discourse.cmake.org/u/szhorvat)
#### Post date: [September 25, 2023, 4:33pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/1 "2023-09-25T16:33:18Z")

</div>

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](https://github.com/igraph/igraph/issues/2394) (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.

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

```auto
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?

---

<div class="post-metadata">

### Author: ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)
#### Post date: [September 25, 2023, 6:11pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/2 "2023-09-25T18:11:25Z")

</div>

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](https://gitlab.kitware.com/cmake/cmake/-/blob/v3.27.6/Source/cmComputeLinkDepends.cxx#L384). That code could be updated to de-duplicate static libraries too when using the Apple linker.

---

<div class="post-metadata">

### Author: ![szhorvat](https://discourse.cmake.org/user_avatar/discourse.cmake.org/szhorvat/32/1906_2.png) [@szhorvat](https://discourse.cmake.org/u/szhorvat)
#### Post date: [September 25, 2023, 7:32pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/3 "2023-09-25T19:32:57Z")

</div>

Thanks, this makes it clear what is going on.

---

<div class="post-metadata">

### Author: ![szhorvat](https://discourse.cmake.org/user_avatar/discourse.cmake.org/szhorvat/32/1906_2.png) [@szhorvat](https://discourse.cmake.org/u/szhorvat)
#### Post date: [September 26, 2023, 9:02am UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/4 "2023-09-26T09:02:21Z")

</div>

> [@brad.king](#):
>
> That code could be updated to de-duplicate static libraries too when using the Apple linker.

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.

---

<div class="post-metadata">

### Author: ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)
#### Post date: [September 26, 2023, 10:12am UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/5 "2023-09-26T10:12:10Z")

</div>

Meanwhile try adding

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

---

<div class="post-metadata">

### Author: ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)
#### Post date: [October 5, 2023, 2:19pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/6 "2023-10-05T14:19:01Z")

</div>

This is now tracked as [CMake Issue 25297](https://gitlab.kitware.com/cmake/cmake/-/issues/25297).

---

<div class="post-metadata">

### Author: ![amagela](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/53a042/32.png) [@amagela](https://discourse.cmake.org/u/amagela)
#### Post date: [September 5, 2024, 1:45am UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/7 "2024-09-05T01:45:13Z")

</div>

I read through this issue and I wasn’t 100% sure what the ultimate fix is. If I am building software targeting macOS and Linux, is the goal to allow the direct and transitive libs to have duplicate entries on Linux and macOS and just suppress the warnings on macOS or is it to de-duplicate the full combined set of direct and transitive libs so both systems don’t have any duplication? I apologize if this is obvious.

---

<div class="post-metadata">

### Author: ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)
#### Post date: [September 5, 2024, 12:12pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/8 "2024-09-05T12:12:37Z")

</div>

> [@amagela](#):
>
> is the goal to…suppress the warnings on macOS or is it to de-duplicate

It is to de-duplicate. [CMake MR 8946](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/8946) added de-duplication on relevant platforms, starting in CMake 3.29.

---

<div class="post-metadata">

### Author: ![amagela](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/53a042/32.png) [@amagela](https://discourse.cmake.org/u/amagela)
#### Post date: [September 5, 2024, 2:51pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/9 "2024-09-05T14:51:28Z")

</div>

Ultimately, I have the “same” scenario that is described above with some small differences (information listed below). Things are not de-duplicated for me. I am on macOS 14.6.1 utilizing CMake v3.29.5, Clang 17.0.6, and OpenMPI 4.1.6 from MacPorts.

1. libB and libC depend on libA.
2. appZ depends on libA and libB.
  1. libA is on the link line twice.

3. appY depends on libA, libB, and libC.
  1. libA is on the link line twice (so the transitive libraries appear to be de-duplicated by CMake).

I haven’t found any link specification order that results in de-duplication. This differs from the example in the aforementioned issue.

- I tried libA before libB and libC.
- I tried libA after libB and libC.

What do I need to do? The MR points to the following, although the poster seems to indicate it doesn’t work. Is this syntax correct?

```auto
cmake_policy(SET CMP0156 NEW)
set(CMAKE_C_LINK_LIBRARIES_PROCESSING ORDER=REVERSE UNICITY=ALL)
set(CMAKE_CXX_LINK_LIBRARIES_PROCESSING ORDER=REVERSE UNICITY=ALL)

```

---

<div class="post-metadata">

### Author: ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)
#### Post date: [September 6, 2024, 1:07pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/10 "2024-09-06T13:07:43Z")

</div>

With this project:

```cmake
cmake_minimum_required(VERSION 3.29) # sets CMP0156 to NEW
project(Discourse9084 C)

add_library(A a.c)
add_library(B b.c)
target_link_libraries(B PUBLIC A)
add_library(C c.c)
target_link_libraries(C PUBLIC A)
add_executable(Y y.c)
target_link_libraries(Y PRIVATE A B C)
add_executable(Z z.c)
target_link_libraries(Z PRIVATE A B)

```

On Linux I get link lines:

```auto
cc ... -o Y libA.a libB.a libC.a libA.a
cc ... -o Z libA.a libB.a libA.a

```

and on Apple I get link lines:

```auto
cc ... -o Y libB.a libC.a libA.a
cc ... -o Z libB.a libA.a

```

The latter are de-duplicated as expected because CMake (after CMP0156) knows that Apple’s linker re-scans automatically.

The `CMAKE_<LANG>_LINK_LIBRARIES_PROCESSING` variable is an undocumented implementation detail that CMake sets internally/automatically based on what linker is being used.

---

<div class="post-metadata">

### Author: ![rabartl](https://discourse.cmake.org/user_avatar/discourse.cmake.org/rabartl/32/4908_2.png) [@rabartl](https://discourse.cmake.org/u/rabartl)
#### Post date: [September 6, 2024, 4:29pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/11 "2024-09-06T16:29:13Z")

</div>

Just to provide my two cents here, I am surprised by this behavior.

I think the core problem here is that CMake does not support the ability to order the libraries according to their dependency order as:

```auto
cc ... -o Y libC.a libB.a libA.a

```

instead of the manual project ordering:

```auto
cc ... -o Y libA.a libB.a libC.a libA.a

```

for the example [above](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/10).

This is a simple graph problem to figure out the ordering of the libraries according to the dependencies and only list the libraries once. (I implemented that in old TriBITS in **CMake** code. That should be easy to implement in C++ with proper graph data-structures and algorithm.)

Any reason why CMake can’t implement library ordering based on dependencies to avoid this problem all together (unless there really are circular dependencies in the libraries and they can do it manually in your CMakeLists.txt files)? If that is a new global or target property that can be set, then fine. My guess is that 95% of customers would prefer CMake to reorder the libraries and remove duplicates. That will yield shorter link lines and faster links.

NOTE: I think the reason I never noticed this behavior this because TriBITS does auto linking and takes into account package dependency order when it does that. I can guarantee if you switch to manual linking, this problem will come up.

---

<div class="post-metadata">

### Author: ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)
#### Post date: [September 6, 2024, 5:04pm UTC](https://discourse.cmake.org/t/avoid-duplicate-linking-to-avoid-xcode-15-warnings/9084/12 "2024-09-06T17:04:47Z")

</div>

> [@rabartl](#):
>
> Any reason why CMake can’t implement library ordering based on dependencies to avoid this problem all together

CMake computes a link line by starting with the exact list provided by the project and then adding transitive dependencies it doesn’t reflect. `target_link_libraries(Y PRIVATE A B C)` says to link `Y` with `A B C` first: CMake adds another `A` to satisfy `B -> A`. This approach gives projects control over the order for cases where it matters.

I’ve opened [CMake Issue 26271](https://gitlab.kitware.com/cmake/cmake/-/issues/26271) to propose an option to re-order direct dependencies to honor their transitive dependencies.
