# Managing namelink install target export

**URL:** <https://discourse.cmake.org/t/managing-namelink-install-target-export/3134>\
**Category:** Code\
**Tags:** os:windows\
**Created:** [April 13, 2021, 10:12am UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134 "2021-04-13T10:12:22Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![VRonin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/vronin/32/1369_2.png) [@VRonin](https://discourse.cmake.org/u/VRonin)\
**Post date:** [April 13, 2021, 10:12am UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/1 "2021-04-13T10:12:22Z")

</div>

Hi Everyone,  
I have a problem using `install(TARGETS EXPORT` and `install(EXPORT`.  
I have to support CMake 3.2 so I can’t use `NAMELINK_COMPONENT`.  
My simplified code is below, it’s taken mostly from @craig.scott’s book.  
My problem is that `MyLibTargetsDevelopment` on windows when building a dll has no contents so the command `install(EXPORT MyLibTargetsDevelopment` complains that the export does not exist.  
Does anyone know how to fix it without having to wrap stuff in `IF (WIN32)`?  
Thanks in advance!

```auto
add_library(MyLib some.cpp sources.cpp)
add_library(MyLib::MyLib ALIAS MyLib)
set_target_properties(MyLib PROPERTIES
        CXX_STANDARD 11
        CXX_STANDARD_REQUIRED ON
        CXX_VISIBILITY_PRESET hidden
        VISIBILITY_INLINES_HIDDEN ON
        SOVERSION ${VERSION_MAJOR}
        VERSION ${VERSION_SHORT}
        EXPORT_NAME "MyLib"
)
install(TARGETS MyLib
        EXPORT MyLibTargetsRuntime
        RUNTIME
            DESTINATION ${CMAKE_INSTALL_BINDIR}
            COMPONENT MyLib_Runtime
        LIBRARY
            DESTINATION ${CMAKE_INSTALL_LIBDIR}
            COMPONENT MyLib_Runtime
            NAMELINK_SKIP
)
install(TARGETS MyLib
        EXPORT MyLibTargetsDevelopment
        INCLUDES
            DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
            COMPONENT MyLib_Development
        LIBRARY
            DESTINATION ${CMAKE_INSTALL_LIBDIR}
            COMPONENT MyLib_Development
            NAMELINK_ONLY
        ARCHIVE
            DESTINATION ${CMAKE_INSTALL_LIBDIR}
            COMPONENT MyLib_Development
)
install(EXPORT MyLibTargetsRuntime
        FILE MyLibTargetsRuntime.cmake
        NAMESPACE MyLib::
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyLib
        COMPONENT MyLib_Runtime
)
install(EXPORT MyLibTargetsDevelopment
        FILE MyLibTargetsDevelopment.cmake
        NAMESPACE MyLib::
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyLib
        COMPONENT MyLib_Development
)

```

---

<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:** [April 13, 2021, 11:12am UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/2 "2021-04-13T11:12:53Z")

</div>

We don’t support splitting parts of targets into different export sets. Basically, use a single export set for each target, but components to split bits of targets into different “packages”. Please see [this thread](https://discourse.cmake.org/t/how-to-export-target-which-depends-on-other-target-which-is-in-multiple-export-sets/3007) for earlier discussion.

---

<div class="post-metadata">

**Author:** ![VRonin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/vronin/32/1369_2.png) [@VRonin](https://discourse.cmake.org/u/VRonin)\
**Post date:** [April 13, 2021, 11:32am UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/3 "2021-04-13T11:32:09Z")

</div>

The problem with that thread is that they are using `NAMELINK_COMPONENT`. If I could use that I would be set and would just collapse the 2 exports in 1 but unfortunately it was added in 3.12 and I’m stuck with CMake 3.2  
I found [this talk from Mr Scott](https://crascit.com/2019/10/16/cppcon-2019-deep-cmake-for-library-authors/) where he states that it’s possible to do even without `NAMELINK_COMPONENT` but it doesn’t say how

---

<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:** [April 13, 2021, 11:38am UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/4 "2021-04-13T11:38:38Z")

</div>

@craig.scott Do you have details on that?

I’m afraid I’m not sure how it’d be done without `NAMELINK_COMPONENT`, but I’m also not any kind of authority in that area either. If you’re stuck with 3.2, you’re stuck with 3.2’s feature set which might not cover this use case. I would recommend pushing to require a newer CMake to achieve the desired results as well.

---

<div class="post-metadata">

**Author:** ![vre](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/v/f04885/32.png) [@vre](https://discourse.cmake.org/u/vre)\
**Post date:** [April 13, 2021, 12:25pm UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/5 "2021-04-13T12:25:17Z")

</div>

You may have a look onto [this](https://discourse.cmake.org/t/error-when-installing-targets-and-exports-in-3-19-1/2245) discussion. We solved it the following way:

```
  if(NOT CMAKE_VERSION VERSION_LESS 3.12)
    install(TARGETS myProj EXPORT myProj
      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_COMPONENT development
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT development
      RESOURCE DESTINATION ${CMAKE_INSTALL_DATADIR} COMPONENT development
    )
    if(BUILD_SHARED_LIBS)
      if(MSVC)
        install(FILES $<TARGET_PDB_FILE:myProj> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo COMPONENT debug)
      endif()
    endif()
  else()
    install(TARGETS myProj EXPORT myProj
      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_SKIP
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT development
      RESOURCE DESTINATION ${CMAKE_INSTALL_DATADIR} COMPONENT development
    )
    if(BUILD_SHARED_LIBS)
      install(TARGETS myProj EXPORT myProj LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT development NAMELINK_ONLY)
      if(MSVC)
        install(FILES $<TARGET_PDB_FILE:myProj> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo COMPONENT debug)
      endif()
    endif()
  endif()
```

---

<div class="post-metadata">

**Author:** ![VRonin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/vronin/32/1369_2.png) [@VRonin](https://discourse.cmake.org/u/VRonin)\
**Post date:** [April 13, 2021, 1:10pm UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/6 "2021-04-13T13:10:40Z")

</div>

This code uses the same name of export for the `NAMELINK_SKIP` and `NAMELINK_ONLY` I’m afraid the second one overwrites the first leading to `cmake --build . --target install` to just not copy the library files (I tested it). Am I missing something obvious?

---

<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:** [April 13, 2021, 1:28pm UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/7 "2021-04-13T13:28:20Z")

</div>

> [@VRonin](#):
>
> This code uses the same name of export for the `NAMELINK_SKIP` and `NAMELINK_ONLY`

Using different export names isn’t supported even with CMake `master` today either.

---

<div class="post-metadata">

**Author:** ![VRonin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/vronin/32/1369_2.png) [@VRonin](https://discourse.cmake.org/u/VRonin)\
**Post date:** [April 13, 2021, 1:31pm UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/8 "2021-04-13T13:31:15Z")

</div>

> [@ben.boeckel](#):
>
> Using different export names isn’t supported even with CMake `master` today either.

No, i get this, using different names was my failed attempt of making it work, however, using the same name owerwrites it, correct?

---

<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:** [April 13, 2021, 1:33pm UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/9 "2021-04-13T13:33:35Z")

</div>

I can see that happening, yes, but it’s not an area of CMake that I’m intimately familiar with either. I think your use case was enabled by the addition of the `NAMELINK_COMPONENT` feature and that 3.2 just doesn’t support what you’re looking for (or I could be misunderstanding your end goal here).

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [April 16, 2021, 12:54am UTC](https://discourse.cmake.org/t/managing-namelink-install-target-export/3134/10 "2021-04-16T00:54:47Z")

</div>

> [@VRonin](#):
>
> This code uses the same name of export for the `NAMELINK_SKIP` and `NAMELINK_ONLY` I’m afraid the second one overwrites the first leading to `cmake --build . --target install` to just not copy the library files (I tested it). Am I missing something obvious?

I don’t see the overwriting behavior you describe. See my demonstrator project below which seems to work as expected for me. Some points to note:

- As @ben.boeckel already noted, there should be only one export set for this scenario.
- The `func.cpp` file needs to have a `#include "func.h"` or else the `func()` function isn’t exported. The header is what marks the symbol as to be exported, so without that header being included, the compiler wouldn’t know to export the `func()` function when it compiles `func.cpp` and it compiles it with hidden visibility. That would result in no import library being generated or installed, which maybe is what you’re seeing?

> **Demonstrator project**
>
> _CMakeLists.txt:_
> 
> ```cmake
> cmake_minimum_required(VERSION 3.2)
> project(namelinks)
> 
> add_library(func SHARED func.cpp)
> set_target_properties(func PROPERTIES
> CXX_VISIBILITY_PRESET hidden
> VISIBILITY_INLINES_HIDDEN TRUE
> SOVERSION 1
> VERSION 1.2.3
> )
> target_include_directories(func PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
> 
> include(GNUInstallDirs)
> include(GenerateExportHeader)
> 
> generate_export_header(func)
> 
> install(TARGETS func EXPORT myProj
> RUNTIME
> DESTINATION ${CMAKE_INSTALL_BINDIR}
> COMPONENT runtime
> LIBRARY
> DESTINATION ${CMAKE_INSTALL_LIBDIR}
> COMPONENT runtime
> NAMELINK_SKIP
> ARCHIVE
> DESTINATION ${CMAKE_INSTALL_LIBDIR}
> COMPONENT development
> )
> install(TARGETS func EXPORT myProj
> LIBRARY
> DESTINATION ${CMAKE_INSTALL_LIBDIR}
> COMPONENT development
> NAMELINK_ONLY
> )
> install(EXPORT myProj
> DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/myProj
> NAMESPACE MyProj::
> )
> install(FILES ${CMAKE_CURRENT_BINARY_DIR}/func_export.h
> DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
> COMPONENT development
> )
> 
> ```
> 
> _func.h_
> 
> ```c++
> #pragma once
> 
> #include "func_export.h"
> 
> FUNC_EXPORT int func();
> 
> ```
> 
> _func.cpp_
> 
> ```c++
> #include "func.h"
> 
> int func() { return 23; }
> 
> ```
