# How to write a configurable import target

**URL:** <https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197>\
**Category:** Code\
**Created:** [June 4, 2025, 8:30am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197 "2025-06-04T08:30:27Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Matthias\_Wiesenberge](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/7bcc69/32.png) [@Matthias\_Wiesenberge](https://discourse.cmake.org/u/Matthias_Wiesenberge)\
**Post date:** [June 4, 2025, 8:30am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/1 "2025-06-04T08:30:27Z")

</div>

Hi,  
I have a header-only library mylib consisting of the header `mylib.h` . Inside the header I have a template function. Given a preprocessor macro `USE_FAST_LIB` the implementation of that function redirects to a third party library “fastlib”. When writing my CMakeLists.txt it looks something like

```cmake

```

cmake\_minimum\_required(VERSION 3.26)  
project(mylib LANGUAGES CXX)

option(MYLIB\_USE\_FAST\_LIB “Use fast third-party implementation” OFF)

add\_library(mylib INTERFACE)  
target\_include\_directories(mylib INTERFACE  
$\<BUILD\_INTERFACE:${CMAKE\_CURRENT\_SOURCE\_DIR}\>  
$\<INSTALL\_INTERFACE:include\>  
)

if(MYLIB\_USE\_FAST\_LIB)  
find\_package(fastlib REQUIRED)  
target\_link\_libraries(mylib INTERFACE fastlib::fastlib)  
target\_compile\_definitions(mylib INTERFACE USE\_FAST\_LIB)  
endif()

```auto

```

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [June 4, 2025, 8:40am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/2 "2025-06-04T08:40:50Z")

</div>

If you want to install it, you need much more!

I recommend to use [FILE\_SETS](https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets) HEADER too.

If you are not experience with `CMake`, try [GitHub - friendlyanon/cmake-init: The missing CMake project initializer](https://github.com/friendlyanon/cmake-init)

---

<div class="post-metadata">

**Author:** ![mattwi](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/f07891/32.png) [@mattwi](https://discourse.cmake.org/u/mattwi)\
**Post date:** [June 4, 2025, 9:19am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/3 "2025-06-04T09:19:19Z")

</div>

For some reason my e-mail was not formatted correctly here, so I repost my question

Hi,

I have a header-only library mylib consisting of the header `mylib.h` . Inside the header I have a template function. Given a preprocessor macro `USE_FAST_LIB` the implementation of that function redirects to a third party library “fastlib”. When writing my CMakeLists.txt it looks something like

```cmake

cmake_minimum_required(VERSION 3.26 )
project(mylib LANGUAGES CXX)

option(MYLIB_USE_FAST_LIB "Use fast third-party implementation" OFF)

add_library(mylib INTERFACE)
target_include_directories(mylib INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
    $<INSTALL_INTERFACE:include>
)

if(MYLIB_USE_FAST_LIB)
    find_package(fastlib REQUIRED)
    target_link_libraries(mylib INTERFACE fastlib::fastlib)
    target_compile_definitions(mylib INTERFACE USE_FAST_LIB)
endif()

```

My question is: How do I need to write the install rules and package configuration file such that downstream users can use mylib like

```cmake

# Optionally, before find_package:

set(MYLIB_USE_FAST_LIB ON) # or OFF

find_package(mylib REQUIRED)

target_link_libraries(their_target PRIVATE mylib::mylib)

```

I.e. they can optionally opt in or out of using the third party library fastlib (because it may not be available on all systems / target-architectues or may not be freely available etc). I know a downstream user can use FetchContent (or CPM) instead of find\_package and the above example works. But I have not managed to achieve the same following the cmake tutorial [https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html](https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html) meaning my installed IMPORTED targets have the option “baked-in” depending on what I choose at configuration time of mylib and the option to choose is no longer available to a downstream user. I also dislike the option of providing two targets `mylib::mylib_fast` and `mylib::mylib_regular` because it is (i) not scalable with the number of configuration options and (ii) it just pushes the problem off to downstream users who then face the same issue. In my mind there should not be a difference in cmake between importing an interface target with CPMAddPackage / FetchContent or find\_package (after all it is the same header file that is being imported and the same configuration options for that header should be exposed to a downstream user).

I would appreciate any help on this

Matthias

---

<div class="post-metadata">

**Author:** ![mattwi](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/f07891/32.png) [@mattwi](https://discourse.cmake.org/u/mattwi)\
**Post date:** [June 4, 2025, 9:26am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/4 "2025-06-04T09:26:57Z")

</div>

Sure, if it makes the discussion easier let’s pretend I used this init project [GitHub - friendlyanon/cmake-init-header-only: Example header-only library output of cmake-init](https://github.com/friendlyanon/cmake-init-header-only)

How do I need to modify the [install-rules.cmake](https://github.com/friendlyanon/cmake-init-header-only/blob/master/cmake/install-rules.cmake) and the `install-config.cmake` such that a downstream user of `find_package(mylib)` can set an option `MYLIB_USE_FAST_LIB` as described above?

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [June 4, 2025, 10:36am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/5 "2025-06-04T10:36:31Z")

</div>

I use this `install-config.cmake` for my [asio](https://github.com/ClausKlein/asio/pull/4) project:

```cmake
include(CMakeFindDependencyMacro)
find_dependency(Threads)

find_package(OpenSSL QUIET)

function(add_asio_module NAME)
    set(ASIO_ROOT @CMAKE_INSTALL_PREFIX@)
    message(STATUS "ASIO_ROOT is: ${ASIO_ROOT}")

    add_library(${NAME})
    target_include_directories(${NAME} PRIVATE ${ASIO_ROOT}/include)
    target_compile_features(${NAME} PUBLIC cxx_std_23)

    set(CPPdefinitions "@CPPdefinitions@")
    if(CPPdefinitions)
        target_compile_definitions(${NAME} PUBLIC ${CPPdefinitions})
    endif()

    # cmake-format: off
    target_sources(
        ${NAME}
        PUBLIC
            FILE_SET modules_public
            TYPE CXX_MODULES
            BASE_DIRS ${ASIO_ROOT}
            FILES ${ASIO_ROOT}/lib/cmake/asio/module/asio.cppm
    )
    # cmake-format: on
    if(OpenSSL_FOUND)
        target_link_libraries(${NAME} PUBLIC OpenSSL::SSL OpenSSL::Crypto)
    endif()
endfunction()

include("${CMAKE_CURRENT_LIST_DIR}/asioTargets.cmake")

if(OpenSSL_FOUND)
    set_target_properties(asio::asio_header PROPERTIES
        # TODO(CK): how to append? INTERFACE_COMPILE_DEFINITIONS "ASIO_HAS_OPENSSL"
        INTERFACE_LINK_LIBRARIES "OpenSSL::SSL;OpenSSL::Crypto;Threads::Threads"
    )
endif()

```

---

<div class="post-metadata">

**Author:** ![mattwi](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/f07891/32.png) [@mattwi](https://discourse.cmake.org/u/mattwi)\
**Post date:** [June 4, 2025, 11:21am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/6 "2025-06-04T11:21:44Z")

</div>

Thank you for the reply. Just to clarify that I understand this correctly The `find_package( OpenSSL QUIET)` line will set the `OpenSSL_FOUND` variable that you use to conditionally add the `OpenSSL` and `Threads` targets to the interface of `asio::asio_headers`?

I have a couple of follow-up questions: Why can’t you use `target_link_librarires( asio_headers INTERFACE OpenSSL::SSL)` instead of `set_target_properties`?  
Also, I am wondering how this is working when the asio library is installed because in your main `CMakeLists.txt` you have the line `find_package( OpenSSL REQUIRED)` and `target_link_libraries(asio_header INTERFACE OpenSSL::SSL OpenSSL::Crypto)`  
So to my understanding the `asio` library can never be configured without `OpenSSL` because cmake throws an error if OpenSSL is not available. So when someone installs the asio library the `OpenSSL_FOUND` variable is always true because it cannot be configured without it? What am I missing?

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [June 4, 2025, 11:28am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/7 "2025-06-04T11:28:17Z")

</div>

> [@mattwi](#):
>
> So to my understanding the `asio` library can never be configured without `OpenSSL` because cmake throws an error if OpenSSL is not available. So when someone installs the asio library the `OpenSSL_FOUND` variable is always true because it cannot be configured without it? What am I missing?

That is a tricky part of `asio`

- as header only, It use dynamic features testing for most options.
- as static lib, it depends on the static configuration.

This was only a experimental study to help you!

My focus on this MR is the `CXX_MODULE`.

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [June 4, 2025, 11:34am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/8 "2025-06-04T11:34:34Z")

</div>

> [@mattwi](#):
>
> Why can’t you use `target_link_librarires( asio_headers INTERFACE OpenSSL::SSL)` instead of `set_target_properties`?

That is the tricky part of `CMake`:  
I checked the `stagedir/lib/cmake/asioTargets-debug.cmake`

```cmake
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Debug".
#----------------------------------------------------------------

# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)

# Import target "asio::asio" for configuration "Debug"
set_property(TARGET asio::asio APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(asio::asio PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
  IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/libasioD.a"
  )

list(APPEND _cmake_import_check_targets asio::asio )
list(APPEND _cmake_import_check_files_for_asio::asio "${_IMPORT_PREFIX}/lib/libasioD.a" )

# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

```

in `stagedir/lib/cmake/asioTargets.cmake` you will find this:

```cmake
# Create imported target asio::asio_header
add_library(asio::asio_header INTERFACE IMPORTED)

set_target_properties(asio::asio_header PROPERTIES
  INTERFACE_COMPILE_DEFINITIONS "ASIO_NO_DEPRECATED;ASIO_DISABLE_BOOST_CONTEXT_FIBER;ASIO_HAS_SNPRINTF"
  INTERFACE_COMPILE_FEATURES "\$<\$<COMPILE_FEATURES:cxx_std_23>:cxx_std_23>;\$<\$<NOT:\$<COMPILE_FEATURES:cxx_std_23>>:cxx_std_20>"
  INTERFACE_LINK_LIBRARIES "OpenSSL::SSL;OpenSSL::Crypto;Threads::Threads"
)

```

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [June 4, 2025, 11:43am UTC](https://discourse.cmake.org/t/how-to-write-a-configurable-import-target/14197/9 "2025-06-04T11:43:38Z")

</div>

> [@mattwi](#):
>
> Also, I am wondering how this is working when the asio library is installed because in your main `CMakeLists.txt` you have the line `find_package( OpenSSL REQUIRED)`

Yes, good question!

**Found OpenSSL: /usr/local/Cellar/openssl@3/3.5.0/lib/libcrypto.dylib (found version “3.5.0”)**

if not, it would not work with the static lib. I have this runtime dependency for it!

### The dynamic is only for the header only library!
