# How to export target which depends on other target which is in multiple export sets?

**URL:** <https://discourse.cmake.org/t/how-to-export-target-which-depends-on-other-target-which-is-in-multiple-export-sets/3007>\
**Category:** Code\
**Created:** [March 24, 2021, 4:51pm UTC](https://discourse.cmake.org/t/how-to-export-target-which-depends-on-other-target-which-is-in-multiple-export-sets/3007 "2021-03-24T16:51:33Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![dbahadir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dbahadir/32/197_2.png) [@dbahadir](https://discourse.cmake.org/u/dbahadir)\
**Post date:** [March 24, 2021, 4:51pm UTC](https://discourse.cmake.org/t/how-to-export-target-which-depends-on-other-target-which-is-in-multiple-export-sets/3007/1 "2021-03-24T16:51:33Z")

</div>

## Problem

I am currently writing `CMakeLists.txt` files for a larger code project which consists of a hierarchy of different CMake projects which can either be built alone or monolithic all together.

_Sadly, I am encountering a limitation of CMake when trying to install my targets and create export/import CMake scripts for it (using the monolithic build):_

```auto
CMake Error: install(EXPORT "Advanced-Runtime" ...) includes target 
"Advanced-library" which requires target "Fundamentals-library" 
that is not in this export set, but in multiple other export sets: 
lib/cmake/MyProj/Fundamentals-Development.cmake, 
lib/cmake/MyProj/Fundamentals-Runtime.cmake.

An exported target cannot depend upon another target which is exported 
multiple times. Consider consolidating the exports of the 
"Fundamentals-library" target to a single export.

```

However, that should not really be a problem, because the `Fundamentals-Development.cmake` export-set only exists for the namelink component of the `Fundamentals-library` shared-library (and possibly some include files that should be installed, too).  
And in fact that only seems to be a problem if I am building the `Fundamentals` project together with the `Advanced` project monolithic.  
If I cmaked and built the `Fundamentals` project before, installed its export sets and just then cmake and build the `Advanced` project (which then uses `find_package` to retrieve the `IMPORTED` target for the `Fundamentals-library`) CMake is pleased and no error occurs.

* * *

## Details and Example

_In order to hopefully better understand what I mean and did I am reproducing the important parts of the `CMakeLists.txt` files here:_

I have a project `Fundamentals` which internally creates a (shared) library target `Fundamentals-library` and exports it (as `MyProj::Fundamentals`). I am creating two export-sets for it, `Fundamentals-Runtime` and `Fundamentals-Development` and the built library file will be in the `Fundamentals-Runtime` export-set and its namelink symlink in the `Fundamentals-Development` export-set:

```cmake
...
cmake_minimum_required(VERSION 3.19...3.20)
project( Fundamentals
         VERSION "1.0.0" )

add_library( ${PROJECT_NAME}-library SHARED )
add_library( ${PROJECT_NAME}-library ALIAS MyProj::${PROJECT_NAME} )
...
# Install library
install( TARGETS ${PROJECT_NAME}-library
    EXPORT ${PROJECT_NAME}-Runtime
    LIBRARY
        DESTINATION lib
        COMPONENT ${PROJECT_NAME}-Runtime
        NAMELINK_SKIP
)
install( TARGETS ${PROJECT_NAME}-library
    EXPORT ${PROJECT_NAME}-Development
    LIBRARY
        DESTINATION lib
        NAMELINK_COMPONENT ${PROJECT_NAME}-Development
        NAMELINK_ONLY
)

# Install export-sets
install( EXPORT ${PROJECT_NAME}-Runtime
    DESTINATION lib/cmake/MyProj
    FILE ${PROJECT_NAME}-Runtime.cmake
    NAMESPACE MyProj::
    COMPONENT ${PROJECT_NAME}-Runtime
)
install( EXPORT ${PROJECT_NAME}-Development
    DESTINATION lib/cmake/MyProj
    FILE ${PROJECT_NAME}-Development.cmake
    NAMESPACE MyProj::
    COMPONENT ${PROJECT_NAME}-Development
)
...

```

(Of course, I am also exporting a `MyProj-Config.cmake` file which internally includes those export-set files shown above. However, for brevity and because it does not help in explaining the problem I am omitting that here.)

I can build this project and then install it just fine.  
In the generated import files `Fundamentals-Runtime.cmake` ~~and `Fundamentals-Development.cmake`~~ we find an `IMPORTED` target `MyProj::Fundamentals` which has no dependencies (aka no property `INTERFACE_LINK_LIBRARIES`).  
(_ **edit:** `Fundamentals-Development.cmake` seems to only contain boiler-plate code and processing returns early at the beginning of the file, because it does not contain any `IMPORTED` targets._)

I also have a second project `Advanced` whose `CMakeLists.txt` has exactly the same `install` commands, only the beginning of the file is slightly different:

```cmake
cmake_minimum_required(VERSION 3.19...3.20)
project( Advanced
         VERSION "2.0.0" )

# import dependency if not currently building it already.
if (NOT TARGET MyProj::Fundamentals)
    find_package( MyProj REQUIRED COMPONENT Fundamentals )
endif()

add_library( ${PROJECT_NAME}-library SHARED )
add_library( ${PROJECT_NAME}-library ALIAS MyProj::${PROJECT_NAME} )
# Add (public) dependency.
target_link_libraries( ${PROJECT_NAME}-library
    PUBLIC MyProj::Fundamentals )
...
# Install library and export-set as before
...

```

As one can see the target `Advanced-library` has a dependency on the `MyProj::Fundamentals` target created in project `Fundamentals`.

As I already said above in the problem description, building both projects together in a monolithic build yields the error. Only building both projects separately and using the `IMPORTED` target for `MyProj::Fundamentals` from the `Advanced` project works just fine.

When doing that I can see that the `IMPORTED` target `MyProj::Advanced` indeed has a property `INTERFACE_LINK_LIBRARIES` with `MyProj::Fundamentals` as its value. And this is what I want.  
But sadly, that seems to be the problem with the monolithic build.

For example, I can workaround the error by changing the `target_link_libraries` line above to the following:

```cmake
target_link_libraries( ${PROJECT_NAME}-library
    PUBLIC $<BUILD_INTERFACE:MyProj::Fundamentals> )

```

However, that results in the `IMPORTED` target `MyProj::Advanced` to not carry its dependency information, which is suboptimal.

Another workaround would be do not `install` the namelink in a separate export-set. But that is what I want to do and that is what the `NAMELINK_ONLY` and `NAMELINK_SKIP` options of `install(TARGETS ...)` is there for in the first place.

* * *

## Questions

Does anyone have a good suggestion how to circumvent that error and still be able to build monolithic and still have the exported `Advanced-library` carry its dependency information?

Or does anyone know where and how to change the implementation of CMake to not trip over this situation and prevent that error in this case?

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [March 25, 2021, 7:15pm UTC](https://discourse.cmake.org/t/how-to-export-target-which-depends-on-other-target-which-is-in-multiple-export-sets/3007/2 "2021-03-25T19:15:09Z")

</div>

I think the issue is that we attach the full target to each export here. I suspect that for this setup:

```cmake
# Install library
install( TARGETS ${PROJECT_NAME}-library
    EXPORT ${PROJECT_NAME}-Runtime
    LIBRARY
        DESTINATION lib
        COMPONENT ${PROJECT_NAME}-Runtime
        NAMELINK_SKIP
)
install( TARGETS ${PROJECT_NAME}-library
    EXPORT ${PROJECT_NAME}-Development
    LIBRARY
        DESTINATION lib
        NAMELINK_COMPONENT ${PROJECT_NAME}-Development
        NAMELINK_ONLY
)

```

we want to not put the full target into each export.

@kyle.edwards This feels like its somewhat in your wheelhouse (though I might be wrong). How feasible is it to just Do The Right Thing (via a policy) here or should we do:

- recommend not adding `EXPORT` on the `NAMELINK_ONLY` install rule (my gut feeling for the actual right answer here)
- add a new keyword `EXPORT_INCREMENTAL` to manually do this?

---

<div class="post-metadata">

**Author:** ![dbahadir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dbahadir/32/197_2.png) [@dbahadir](https://discourse.cmake.org/u/dbahadir)\
**Post date:** [March 25, 2021, 8:33pm UTC](https://discourse.cmake.org/t/how-to-export-target-which-depends-on-other-target-which-is-in-multiple-export-sets/3007/3 "2021-03-25T20:33:07Z")

</div>

I realized for my specific case, where the `Fundamentals-Development` export-set does not really contain any information, that the easiest solution really is to omit the `EXPORT ${PROJECT_NAME}-Development` option, possibly by combining both `INSTALL( TARGETS ... )` commands into one:

```cmake
install( TARGETS ${PROJECT_NAME}-library
    EXPORT ${PROJECT_NAME}-Runtime
    LIBRARY
        DESTINATION lib
        COMPONENT ${PROJECT_NAME}-Runtime
        NAMELINK_COMPONENT ${PROJECT_NAME}-Development
)

```

However, if I have two separate `install( TARGETS ... )` commands as in my original example and the second one does install an additional target, I cannot omit the `EXPORT` option.  
In this situation it would be great if CMake would “just Do The Right Thing”.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [March 25, 2021, 8:57pm UTC](https://discourse.cmake.org/t/how-to-export-target-which-depends-on-other-target-which-is-in-multiple-export-sets/3007/4 "2021-03-25T20:57:49Z")

</div>

I usually either try to export each target individually or as a single batch myself. I think this is a suitable solution for now; I don’t forsee this getting much attention in the near future since the workaround is pretty simple (even in your case, splitting into separate `install()` calls for targets that act differently is also possible). The main issue is that 1) deciding (on the details of), 2) implementing, and 3) documenting the Right Thing™ is not a trivial task here.
