add_library in a -config.cmake causing problem

I have three cmake-based projects: Flock, Bedrock, and Mofka. Mofka depends on Flock and Bedrock. Bedrock depends on Flock. Flock has the following in flock-config.cmake.in (which is configured and installed as flock-config.cmake):

...
add_library (flock::server ALIAS flock-server)

Bedrock uses find_package(flock REQUIRED) to find Flock, and builds fine, linking its library with target_link_libraries(bedrock PRIVATE flock::server). The bedrock-config.cmake.in has this:

find_dependency (flock)

In the Mofka project I also have find_package (bedrock REQUIRED) and find_package (flock REQUIRED), but cmake gives me the following error:

CMake Error at [...]/share/cmake/flock/flock-config.cmake:49 (add_library)
add_library cannot create ALIAS target "flock::server" because another target with the same name already exists.

I am under the impression that CMake loads flock-config.cmake twice (once when doing find_package(flock) and once when doing find_package(bedrock)), causing this add_library to be processed twice. Is my diagnosis correct and if so, how to I fix this? Is calling add_library in a -config.cmake file not correct?

It sounds like you are creating the *-config.cmake files manually, which of course works too, but I would probably recommend you to rely on standard CMake helpers for auto-generating those.

Anyway, the problem you are experiencing might be due to the fact that when CMake auto-generates those configs and targets files, this is how library targets are defined there, for example:

add_library(some::thing STATIC IMPORTED)

so maybe your config is missing this IMPORTED argument?

Also you should probably add CONFIG argument to your find_package() calls, since you are providing CMake configs for those libraries.

The following files are generated by cmake: flock-config-version.cmake, flock-config.cmake, flock-targets-release.cmake, flock-targets.cmake.

They are generated as follows:

  # installation stuff (packaging and install commands)
  write_basic_package_version_file (
      "flock-config-version.cmake"
      VERSION ${FLOCK_VERSION}
      COMPATIBILITY AnyNewerVersion)

  # generate our config file for find_package()
  set (INCLUDE_INSTALL_DIR include/)
  set (LIB_INSTALL_DIR lib/)
  configure_package_config_file (flock-config.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/flock-config.cmake
    INSTALL_DESTINATION ${LIB_INSTALL_DIR}/flock/cmake
    PATH_VARS INCLUDE_INSTALL_DIR)

  # "make install" rules
  install (TARGETS flock-server
           EXPORT flock-targets
           ARCHIVE DESTINATION lib
           LIBRARY DESTINATION lib)
  install (EXPORT flock-targets
           DESTINATION ${flock-pkg}
           FILE "flock-targets.cmake")
  install (FILES "${CMAKE_CURRENT_BINARY_DIR}/flock-config.cmake"
                 "${CMAKE_CURRENT_BINARY_DIR}/flock-config-version.cmake"
           DESTINATION ${flock-pkg} )

The flock-config.cmake.in is as follows:

  set (FLOCK_VERSION @FLOCK_VERSION@)

  @PACKAGE_INIT@

  set_and_check (FLOCK_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")

  check_required_components (flock)

  include (CMakeFindDependencyMacro)
  find_dependency (PkgConfig)
  pkg_check_modules (margo REQUIRED margo)
  pkg_check_modules (json-c REQUIRED json-c)

  include ("${CMAKE_CURRENT_LIST_DIR}/flock-targets.cmake")

  add_library (flock::server ALIAS flock-server)

Flocks’ CMakeLists.txt has add_library (flock::server ALIAS flock-server), but I looked into the generated flock-targets.cmake and it flock::server doesn’t show up, only flock-server, that’s why I initially added it to flock-config.cmake.in.

added it to flock-config.cmake.in

That looks like the source of the problem. If you are relying on auto-generated configs/targets, then all the required add_library() statements should be added there automatically.

The thing is I don’t know how to do this differently. If I add flock::server to the install(TARGETS ...) line, I get this error:

CMake Error at src/CMakeLists.txt:110 (install):
  install TARGETS given target "flock::server" which is an alias.

EDIT: also here https://cmake.org/cmake/help/latest/command/add_library.html#alias-libraries I read " An ALIAS target may not be installed or exported.", so how can I make flock::server available?

Ah, that should be trivial - just add NAMESPACE argument, like this:

install(EXPORT "flock-targets"
    FILE "flock-targets.cmake"
    NAMESPACE "flock::"
    DESTINATION "${flock-pkg}" # assuming this path is correct
)

For example, in this project the resulting auto-generated ThingyTargets.cmake will contain the following:

# ...

# Create imported target dpndnc::Thingy
add_library(dpndnc::Thingy STATIC IMPORTED)

# ...

Although since your target name is flock-server, it will then become flock::flock-server, so then you’d probably want to rename it to just server.

The EXPORT_NAME target property can help with that. For example:

set_target_properties(flock-server PROPERTIES EXPORT_NAME server)

install(EXPORT flock-targets
    FILE flock-targets.cmake
    NAMESPACE flock::
    DESTINATION "${flock-pkg}" # assuming this path is correct
)

The above would result in the flock-targets.cmake file defining the target as flock::server.

2 Likes