<Package>Config.cmake 用于库包

<Package>Config.cmake for a library package

我们按照 CMake 教程的第 11 步,为库包配备了 *Config.cmake 文件。然而我们的下游软件却找不到这个库。

我们的软件包称为“formfactor”[https://jugit.fz-juelich.de/mlz/libformfactor]。它提供了一个共享库(libformfactor)和一些头文件。

我们的下游代码使用

find_package(formfactor REQUIRED CONFIG)
message(STATUS "formfactor: found=${formfactor_FOUND}, include_dirs=${formfactor_INCLUDE_DIR}, "
    "lib=${formfactor_LIBRARY}, version=${formfactor_VERSION}")

搜索图书馆。 las,它打印

formfactor: found=1, include_dirs=/usr/local/include, lib=, version=0.1

也就是说,它没有找到库,但即使我们说“需要”也没有引发致命错误。

包“formfactor”包含以下所有内容:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.6 FATAL_ERROR)
project(formfactor VERSION 0.1.1 LANGUAGES CXX)

if(NOT DEFINED BUILD_SHARED_LIBS)
    option(BUILD_SHARED_LIBS "Build as shared library" ON)
endif()
option(WERROR "Treat warnings as errors" OFF)

add_subdirectory(ff)

install(EXPORT formfactorTargets
  FILE formfactorTargets.cmake
  DESTINATION cmake
)

include(CMakePackageConfigHelpers)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
    "${CMAKE_CURRENT_BINARY_DIR}/formfactorConfig.cmake"
    INSTALL_DESTINATION cmake
    NO_SET_AND_CHECK_MACRO
    NO_CHECK_REQUIRED_COMPONENTS_MACRO
    )

write_basic_package_version_file(
    "${CMAKE_CURRENT_BINARY_DIR}/formfactorConfigVersion.cmake"
    VERSION "${formfactor_VERSION_MAJOR}.${formfactor_VERSION_MINOR}"
    COMPATIBILITY AnyNewerVersion
    )

install(FILES
    ${PROJECT_BINARY_DIR}/formfactorConfig.cmake
    ${PROJECT_BINARY_DIR}/formfactorConfigVersion.cmake
    DESTINATION cmake)

export(EXPORT formfactorTargets
  FILE ${CMAKE_CURRENT_BINARY_DIR}/formfactorTargets.cmake
)

Config.cmake.in:


set(formfactor_INCLUDE_DIR @CMAKE_INSTALL_PREFIX@/include)
include(${CMAKE_CURRENT_LIST_DIR}/formfactorTargets.cmake)

ff/CMakeLists.txt:

set(lib formfactor)
set(${lib}_LIBRARY ${lib} PARENT_SCOPE)

file(GLOB src_files *.cpp)
set(api_files Polyhedron.h PolyhedralTopology.h PolyhedralComponents.h)

add_library(${lib} ${src_files})

target_include_directories(${lib}
    PUBLIC
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
    $<INSTALL_INTERFACE:include>
    )

set_target_properties(
    ${lib} PROPERTIES
    OUTPUT_NAME ${lib}
    VERSION ${formfactor_VERSION}
    SOVERSION ${formfactor_VERSION_MAJOR})

install(
    TARGETS ${lib}
    EXPORT formfactorTargets
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION lib
    ARCHIVE DESTINATION lib)

install(
    FILES ${api_files}
    DESTINATION include/ff)

有什么问题吗?有什么遗漏吗?为什么它不起作用?

披露:

CMake 通过

生成的脚本 formfactorTargets.cmake
install(EXPORT formfactorTargets
  FILE formfactorTargets.cmake
  DESTINATION cmake
)

仅定义 目标 ,它已添加到具有该名称的导出集 (formfactorTargets)。

因为您只添加了一个库

set(lib formfactor)
...
install(
    TARGETS ${lib}
    EXPORT formfactorTargets
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION lib
    ARCHIVE DESTINATION lib)

脚本只定义了一个库target formfactor.

与该目标的链接是 find_package 结果的“现代”用法:

# downstream
find_package(formfactor REQUIRED CONFIG)
target_link_libraries(<my executable> PUBLIC formfactor)

由您的 Config.cmake.in 脚本(将作为 formfactorConfig.cmake 安装,由 find_package(formfactor) 读取)为您的包提供额外信息 and/or 它的额外用法。

例如你可以设置变量 formfactor_INCLUDE_DIRSformfactor_LIBRARIES 因此下游可以通过“旧方式”使用您的库,假设变量 formfactor_INCLUDE_DIR 包含包含目录,变量 formfactor_LIBRARIES 包含 link 所需的库文件:

find_package(formfactor REQUIRED CONFIG)
include_directories(${formfactor_INCLUDE_DIRS})
add_executable(my_exe <sources>)
target_link_libraries(my_exe PUBLIC ${formfactor_LIBRARIES})

您(作为包的开发者)很难提供库的绝对路径。但是你可以在 a 中分配变量 formfactor_LIBRARIES “正常工作”的方式:

# Config.cmake.in

# Value of 'formfactor_INCLUDE_DIRS' is real: it contains the include directory.
set(formfactor_INCLUDE_DIRS @CMAKE_INSTALL_PREFIX@/include)

# Value of 'formfactor_LIBRARIES' is fake: it doesn't contain a library path.
# But linking with ${formfactor_LIBRARIES} will work, as it will link
# to the **target**, and CMake will extract a library path from it.
set(formfactor_LIBRARIES formfactor)

# In any case we need to include the export script generated by CMake:
# exactly this script defines 'formfactor' target.
include(${CMAKE_CURRENT_LIST_DIR}/formfactorTargets.cmake)