# Encapsulating Link Arguments

**URL:** https://discourse.cmake.org/t/encapsulating-link-arguments/1171
**Category:** Usage
**Created:** [May 8, 2020, 5:01pm UTC](https://discourse.cmake.org/t/encapsulating-link-arguments/1171 "2020-05-08T17:01:48Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![stefansjs](https://discourse.cmake.org/user_avatar/discourse.cmake.org/stefansjs/32/1915_2.png) [@stefansjs](https://discourse.cmake.org/u/stefansjs)
#### Post date: [May 8, 2020, 5:01pm UTC](https://discourse.cmake.org/t/encapsulating-link-arguments/1171/1 "2020-05-08T17:01:48Z")

</div>

Hey CMake community,

I’m trying to figure out how to encapsulate linker flags in one of the subdirectories of my cmake project. Is there a way for be to set link flags on a target so that when it is linked against, those flags are added to the link command? Specifically by wrapping the target library with `-Wl` flags?

I have a rather large, overly complicated build that I’m trying to clean up a little bit by encapsulating some of the build components into their own cmake. At first I was defining object libraries, but I found the use of `target_include_directories` and `target_link_libraries` very convenient for defining those things on static libraries.

I have one component that defines symbols that need to be kept in the final binary (dynamic library) because they’re JNI symbols and even though they aren’t referenced in c++ code, they will be used by java code. Those symbols are defined in one component that is now being linked as a static library. Without additional flags, all those JNI symbols get stripped out when doing the final link. Furthermore that library has other dependencies that don’t need to be forced to be in the final binary.

The solution I’ve found with my current structure is the following

```cmake
add_subdirectory(jni_component_dir)
add_library(final_lib SHARED ${final_lib_src})
target_link_libraries(final_lib
                      -Wl,-whole-archive
                      jni_component
                      -Wl,-no-whole-archive
                      ... other libs too ... )

```

With this structure the linker command looks like `ld ... -whole-archive jni_component -no-whole-archive dep1 dep2 ...`. Hopefully you get the idea.

This actually works, but now I wonder if I can move this awareness to the jni directory itself. Afterall, that component is responsible for knowing if it has “unused” symbols that need to be kept.

If I try to move the linker flags to the subdirectory then I get something more akin to this:

```cmake
add_library(jni_component_helper STATIC ${jni_src})
target_link_libraries(jni_component_helper dep1 dep2)
add_library(jni_component STATIC "")
target_link_libraries(jni_component 
                      -Wl,-whole-archive
                      jni_component_helper
                      -Wl,-no-whole-archive)

```

which produces `ld ... -whole-archive jni_component jni_compent_depa dep1 dep2 dep1_dep -no-whole-archive ...` and ultimately gives me link errors with duplicate symbols.

What I want is something similar to this but without all the dependent libraries getting pulled into _that_ link commands. It seems like subdirectories imposes some sort of boundary where the link flags are treated differently. Is there any way to impose this kind of boundary on a target without requiring another subdirectory? Furthermore, is there any way to componentize this without cluttering the top-level cmake?

---

<div class="post-metadata">

### Author: ![marc.chevrier](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/ecb155/32.png) [@marc.chevrier](https://discourse.cmake.org/u/marc.chevrier)
#### Post date: [May 9, 2020, 1:23pm UTC](https://discourse.cmake.org/t/encapsulating-link-arguments/1171/2 "2020-05-09T13:23:03Z")

</div>

First, it is not a good practice to specify link options through `target_link_libraries()` command. It is preferable to use `target_link_options()`.  
And also, it is strongly recommended using the up-to-date syntax regarding `target_link_libraries()` by specifying one of following keyword `PUBLIC`, `PRIVATE` or `INTERFACE`.  
And to finish, to avoid unexpected de-duplicated link options, it is required to use the `SHELL:` prefix.

Here is possible approach:

```cmake
add_library(jni_component_helper STATIC ${jni_src})
target_link_libraries(jni_component_helper PRIVATE dep1 dep2)

add_library(jni_component STATIC "")
# add dependency of jni_component over jni_component_helper
target_link_libraries (jni_component PRIVATE jni_component_helper)
# ensure the required link option is specified for the helper library only
target_link_options(jni_component INTERFACE "SHELL:-Wl,-whole-archive $<TARGET_FILE:jni_component_helper> -Wl,-no-whole-archive")

```

And for the final step:

```cmake
add_subdirectory(jni_component_dir)
add_library(final_lib SHARED ${final_lib_src})
target_link_libraries(final_lib PRIVATE jni_component ... other libs...)

```
