# Should cmake install an INTERFACE library when linked as PRIVATE dependency ?

**URL:** <https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449>\
**Category:** Code\
**Tags:** os:linux\
**Created:** [November 17, 2023, 3:22pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449 "2023-11-17T15:22:03Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 17, 2023, 3:22pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/1 "2023-11-17T15:22:03Z")

</div>

Hi folks,

I’m having a hard time understanding how cmake should behave regarding installation of dependencies added with FetchContent so I’m sorry if this is a noob question, but I couldn’t find a satisfying answer so far.

I’m working with the C++ library [xsimd](https://github.com/xtensor-stack/xsimd) and we’re having a [discussion](https://github.com/xtensor-stack/xsimd/issues/959) on how should behave the library in case of installing.

We’re including the library using FetchContent :

```cmake
include(FetchContent)

FetchContent_Declare(
  xsimd
  GIT_REPOSITORY git@github.com:xtensor-stack/xsimd.git
  GIT_TAG 11.1.0
  GIT_SHALLOW ON
)

FetchContent_MakeAvailable(xsimd)

```

The library itself is an INTERFACE declared header-only library.

From what I understand, if the `xsimd` library is declared as a PRIVATE dependency of my project, it should not be installed alongside my project (since its header-only) when installing. Whereas with PUBLIC/INTERFACE it should.  
However with this library, it is always installed alongside the parent project.

Regarding current modern best practices, how do you think you it behave ?

If you think this is a bug, have you any ideas why does it behaves like that ?

Here is the `CMakeLists.txt`

```cmake

cmake_minimum_required(VERSION 3.8)
project(xsimd)
option(XSIMD_REFACTORING ON)

set(XSIMD_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)

# Versioning
# ==========

file(STRINGS "${XSIMD_INCLUDE_DIR}/xsimd/config/xsimd_config.hpp" xsimd_version_defines
     REGEX "#define XSIMD_VERSION_(MAJOR|MINOR|PATCH)")
foreach(ver ${xsimd_version_defines})
    if(ver MATCHES "#define XSIMD_VERSION_(MAJOR|MINOR|PATCH) +([^]+)$")
        set(XSIMD_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
    endif()
endforeach()
set(${PROJECT_NAME}_VERSION
    ${XSIMD_VERSION_MAJOR}.${XSIMD_VERSION_MINOR}.${XSIMD_VERSION_PATCH})
message(STATUS "xsimd v${${PROJECT_NAME}_VERSION}")

# Build
# =====

set(XSIMD_HEADERS
[...]
${XSIMD_INCLUDE_DIR}/xsimd/xsimd.hpp
)

add_library(xsimd INTERFACE)

target_include_directories(xsimd INTERFACE
    $<BUILD_INTERFACE:${XSIMD_INCLUDE_DIR}>
    $<INSTALL_INTERFACE:include>)

OPTION(ENABLE_XTL_COMPLEX "enables support for xcomplex defined in xtl" OFF)
OPTION(BUILD_TESTS "xsimd test suite" OFF)

if(ENABLE_XTL_COMPLEX)
    find_package(xtl 0.7.0 REQUIRED)
    target_compile_features(xsimd INTERFACE cxx_std_14)
    target_compile_definitions(xsimd INTERFACE XSIMD_ENABLE_XTL_COMPLEX=1)
    target_link_libraries(xsimd INTERFACE xtl)
else()
    target_compile_features(xsimd INTERFACE cxx_std_11)
endif()

if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(test)
endif()

OPTION(BUILD_BENCHMARK "xsimd benchmarks" OFF)
if(BUILD_BENCHMARK)
    add_subdirectory(benchmark)
endif()

OPTION(BUILD_EXAMPLES "xsimd examples" OFF)
if(BUILD_EXAMPLES)
    add_subdirectory(examples)
endif()

# Installation
# ============

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(JoinPaths)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

install(TARGETS xsimd
        EXPORT ${PROJECT_NAME}-targets)

# Makes the project importable from the build directory
export(EXPORT ${PROJECT_NAME}-targets
       FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake")

install(DIRECTORY ${XSIMD_INCLUDE_DIR}/xsimd
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

# GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share".
set(XSIMD_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for xsimdConfig.cmake")

configure_package_config_file(${PROJECT_NAME}Config.cmake.in
                              "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
                              INSTALL_DESTINATION ${XSIMD_CMAKECONFIG_INSTALL_DIR})

# xsimd is header-only and does not depend on the architecture.
# Remove CMAKE_SIZEOF_VOID_P from xtensorConfigVersion.cmake so that an xtensorConfig.cmake
# generated for a 64 bit target can be used for 32 bit targets and vice versa.
set(_XTENSOR_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
unset(CMAKE_SIZEOF_VOID_P)
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
                                 VERSION ${${PROJECT_NAME}_VERSION}
                                 COMPATIBILITY SameMajorVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
              ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
        DESTINATION ${XSIMD_CMAKECONFIG_INSTALL_DIR})
install(EXPORT ${PROJECT_NAME}-targets
        FILE ${PROJECT_NAME}Targets.cmake
        DESTINATION ${XSIMD_CMAKECONFIG_INSTALL_DIR})

configure_file(${PROJECT_NAME}.pc.in
               "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
                @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
        DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/")

```

---

<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:** [November 19, 2023, 2:42am UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/2 "2023-11-19T02:42:50Z")

</div>

`INTERFACE` libraries may have link requirements (e.g., a header-only C++ library that wraps some C library still needs to link to the C library when used). If you know that you don’t need it in the install, `$<INSTALL_INTERFACE>` will get you that. If you know you don’t need it in any export, `$<BUILD_LOCAL_INTERFACE>` is available in CMake 3.26+ as an further enhancement.

```cmake
if (CMAKE_VERSION VERSION_LESS "3.26")
  set(iface_type "INSTALL_INTERFACE") # still need to make the target available to `export()`
else ()
  set(iface_type "BUILD_LOCAL_INTERFACE")
endif ()

target_link_libraries(tgt PRIVATE "$<${iface_type}:xsimd>")

```

---

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 21, 2023, 9:37am UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/3 "2023-11-21T09:37:08Z")

</div>

Thanks a lot for the reply ! I finally had time to test it.

I tested what you suggested, but I had an issue that I kinda expected.

```cmake
target_link_libraries(
  adawata
  PRIVATE $<INSTALL_INTERFACE:xsimd>
)

```

When doing this the library is not available at build time for my library. I though of doing the exact opposite (I need it a build time, not install time) by using `$<BUILD_INTERFACE:xsimd>` but it ends up installing xsimd anyway.

---

<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:** [November 21, 2023, 1:16pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/4 "2023-11-21T13:16:23Z")

</div>

Err, yeah. `BUILD_INTERFACE`, not `INSTALL_INTERFACE`. Does `BUILD_LOCAL_INTERFACE` work?

---

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 21, 2023, 1:25pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/6 "2023-11-21T13:25:39Z")

</div>

No, `BUILD_LOCAL_INTERFACE` doesn’t work either

---

<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:** [November 21, 2023, 1:26pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/7 "2023-11-21T13:26:23Z")

</div>

When you say “it ends up installing xsimd anyways”, what do you mean specifically?

---

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 21, 2023, 1:30pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/8 "2023-11-21T13:30:29Z")

</div>

Sorry, I’ll try to be more clear.

When installing my lib, xsimd is installed too, in the same folder, even though I don’t need it to.

When you check `install/include` you can see the `xsimd` folder with all the headers :

```auto
╰─➤ tree install -L 2
install
├── include
│ ├── adwt
│ ├── cppitertools
│ ├── gsl
│ └── xsimd <-------- should not be here
└── lib
    ├── cmake
    ├── libadawata.a
    ├── libsamplerate.a
    └── pkgconfig

```

---

<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:** [November 21, 2023, 1:31pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/9 "2023-11-21T13:31:32Z")

</div>

Oh, `xsimd` probably has install rules you need to suppress there. No `_INTERFACE` genex will undo that request.

---

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 21, 2023, 1:37pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/10 "2023-11-21T13:37:07Z")

</div>

Ok thanks 🙂 That what I ended up thinking. However I could not identify what is causing this in the install rules of xsimd.

In xsimd’s CMakeLists.txt (I copied the whole CMakeList.txt in the first message) I suspect this :

```cmake
install(DIRECTORY ${XSIMD_INCLUDE_DIR}/xsimd
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

```

Would you have a tip or some resources to read on how to make it more “proper” ?

The thing is, I don’t want to completely disable the feature to install xsimd with my library, because some users might need it when linking to it publicly.

---

<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:** [November 21, 2023, 1:38pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/11 "2023-11-21T13:38:57Z")

</div>

Just wrapping it up in an `if (NO XSIMD_NO_INSTALL)` conditional that lets you set `set(XSIMD_NO_INSTALL 1)` before including your vendored copy.

---

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 21, 2023, 1:41pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/12 "2023-11-21T13:41:05Z")

</div>

Are there no cmake features that would allow dealing with it in a more “automatic” way ? (Sorry if this is a repetitive question, I’m trying to wrap my head around cmake’s modern features)

---

<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:** [November 21, 2023, 1:42pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/13 "2023-11-21T13:42:34Z")

</div>

Install rules are imperative; there’s no “modern” usage-requirement way to make them “go away”.

---

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 21, 2023, 1:43pm UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/14 "2023-11-21T13:43:52Z")

</div>

Ok, thanks a lot for your time !

---

<div class="post-metadata">

**Author:** ![maxmarsc](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@maxmarsc](https://discourse.cmake.org/u/maxmarsc)\
**Post date:** [November 23, 2023, 11:51am UTC](https://discourse.cmake.org/t/should-cmake-install-an-interface-library-when-linked-as-private-dependency/9449/15 "2023-11-23T11:51:08Z")

</div>

For the record, I found a new way using FetchContent and the EXCLUDE\_FROM\_ALL flag, thanks to this [StackOverflow post](https://stackoverflow.com/questions/65527126/disable-install-for-fetchcontent).

For short, with cmake \<3.28 you’d use :

```cmake
include(FetchContent)

FetchContent_Declare(
  xsimd
  GIT_REPOSITORY git@github.com:xtensor-stack/xsimd.git
  GIT_TAG 11.1.0
  GIT_SHALLOW ON
)

FetchContent_GetProperties(xsimd)
if(NOT xsimd_POPULATED)
  FetchContent_Populate(xsimd)
  add_subdirectory(${xsimd_SOURCE_DIR} ${xsimd_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()

```

And with cmake \>= 3.28 we’ll be able to use this syntax :

```cmake
include(FetchContent)

FetchContent_Declare(
  xsimd
  GIT_REPOSITORY git@github.com:xtensor-stack/xsimd.git
  GIT_TAG 11.1.0
  GIT_SHALLOW ON
  # Other content options...
  EXCLUDE_FROM_ALL
)

FetchContent_MakeAvailable(xsimd)

```
