【问题标题】:How to configure project with COMPONENTS in cmake如何在 cmake 中使用 COMPONENTS 配置项目
【发布时间】:2019-07-09 04:46:16
【问题描述】:

我想使用 cmake 创建一个项目项目,该项目的访问方式与 Poco 使用的方式类似。我发现以 Poco 为例非常拥挤且难以理解,因此我正在尝试创建一个没有宏的最小版本,以便我可以看到发生了什么。我在这里为这个示例构建了一个存储库。

https://github.com/markeastwood82/nomnoms

这和下面写的内容是我在阅读/研究“现代 CMake”几天后如何解决这个问题的最佳猜测,但它不太有效。本质上,我有一个库noms,其中包含组件fruitveg,我希望从应用程序munch 动态链接它们。我可以安装noms 库,但无法使用munch 找到它。有人可以帮我把这个东西放在一起吗?

两个项目的结构如下:

noms
|---- CMakeLists.txt
+---- fruit
|     |---- CMakeLists.txt
|     |---- fruit-config.cmake.in
|     +---- src
|     |     |----apple.cpp
|     |
|     +---- include/noms/fruit
|           |----apple.h
|
+---- veg
      |---- CMakeLists.txt
      |---- veg-config.cmake.in
      +---- src
      |     |---- asparagus.cpp
      |
      +---- include/noms/veg
            |---- asparagus.h
munch
|---- CmakeLists.txt
+---- src
      |---- main.cpp

文件noms/CMakeLists.txt 包含以下内容。

cmake_minimum_required(VERSION 3.0)
set(project noms)
set(version 1.0.0)

project(${project})

add_subdirectory(fruit)
add_subdirectory(veg)

# UPDATE: implement advice from Tsyvarev

configure_file(${project}-config.cmake
  "${CMAKE_BINARY_DIR}/${project}-config.cmake"
  @ONLY
)

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
  "${CMAKE_BINARY_DIR}/${project}-config-version.cmake"
  VERSION ${version}
  COMPATIBILITY AnyNewerVersion
)

install(
  FILES
    "${CMAKE_BINARY_DIR}/${project}-config.cmake"
  DESTINATION lib/cmake/${project}
)

文件noms/fruit/CMakeLists.txt(和noms/veg/CMakeLists.txt几乎相同)是

set(component fruit)

add_library(${component} SHARED src/apple.cpp)

# namespaced alias
add_library(${project}::${component} ALIAS ${component})

target_include_directories(${component}
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

install(TARGETS ${component} EXPORT ${component}-targets
  COMPONENT ${component}
  LIBRARY DESTINATION lib
  ARCHIVE DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

install(EXPORT ${component}-targets
  FILE "${project}-${component}-targets.cmake"
  NAMESPACE ${project}::
  DESTINATION lib/cmake/${project}
  COMPONENT ${component}
)

# This seems like a kludge, but it does place the file in the correct location
# on my machine (Ubuntu 18.04). Idea taken from Poco
configure_file("${component}-config.cmake.in"
  "${CMAKE_BINARY_DIR}/${project}-${component}-config.cmake"
  @ONLY
)

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
  "${CMAKE_BINARY_DIR}/${project}-${component}-config-version.cmake"
  VERSION ${version}
  COMPATIBILITY AnyNewerVersion
)

install(
  FILES
    "${CMAKE_BINARY_DIR}/${project}-${component}-config.cmake"
    "${CMAKE_BINARY_DIR}/${project}-${component}-config-version.cmake"
  DESTINATION lib/cmake/${project}
  COMPONENT ${component}
)

# DESTINATION will be automatically prefixed by ${CMAKE_INSTALL_PREFIX}
install(
  DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include
  COMPONENT ${component}
  DESTINATION ${CMAKE_INSTALL_PREFIX}
)

最后,noms/fruit/fruit-config.cmake.in 的文件(noms/veg/veg-config.cmake 几乎相同)是

include(${CMAKE_CURRENT_LIST_DIR}/noms-fruit-config-version.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/noms-fruit-config-targets.cmake)

对于项目munch,文件munch/CMakeLists.txt很简单

cmake_minimum_required(VERSION 3.0)
set(project munch)

find_package(noms REQUIRED COMPONENTS fruit)

add_executable(${project} src/main.cpp)

target_include_directories(${project}
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:$include>
)

target_link_libraries(${project}
  PUBLIC
    noms::fruit
)

安装noms 后,我尝试构建munch,但是cmake 找不到noms-config.cmake 文件。我不知道它应该包含什么,也不知道我应该把它放在哪里。我也不确定在noms/&lt;food-type&gt;/CMakeLists.txt 中使用configure_file 的方法是否合适,因为这里的示例似乎不需要这样做

https://github.com/boostcon/cppnow_presentations_2017/blob/master/05-19-2017_friday/effective_cmake__daniel_pfeifer__cppnow_05-19-2017.pdf

我的问题与此处提出的问题基本相同,目前没有答案(接受的答案不正确,正如我在该线程中评论的那样)。实际上公平地说,由于该线程已有 6 年历史,在撰写本文时它可能是正确的,但似乎没有使用现在推荐的 xxx-config.cmake 方法。

How to export libraries with components in CMAKE?

请随时提出我所犯的任何错误,或者任何可以做得更好的事情。谢谢

* 更新 *

除了上面更新的noms/CMakeLists.txt 文件之外,我还根据下面@Tsyvarev 的建议实现了以下noms/noms-config.cmake 文件...

foreach(component ${noms_FIND_COMPONENTS})
    include(${CMAKE_CURRENT_LIST_DIR}/noms-${component}-config.cmake)
endforeach()

生成的代码现在可以工作了,谢谢!


【问题讨论】:

    标签: c++ cmake components


    【解决方案1】:

    CMake 不会自动处理 COMPONENTS 列表。它将任务留给noms-config.cmake 脚本,在发出命令时搜索并执行该脚本

    find_package(noms COMPONENTS fruit veg)
    

    来自find_package 文档:

    在配置模式下find_package 自动处理REQUIREDQUIET[version] 选项,但将其留给包配置文件以对包有意义的方式处理组件。

    在此配置文件中,您可以从noms_FIND_COMPONENTS 变量中提取请求的组件列表(通过find_package()COMPONENTS 选项给出),并执行适当的操作。例如:

    noms-config.cmake

    foreach(component ${noms_FIND_COMPONENTS})
      # For requested component, execute its "config" script
      include(${CMAKE_CURRENT_LIST_DIR}/${component}-config.cmake)
    endforeach()
    

    这意味着,您将安装脚本 noms-config.cmakelib/cmake/noms 子目录,靠近您已在项目中安装的其他 .cmake 脚本。

    【讨论】:

    • 感谢您的帮助。我已经实施了您的建议并编辑了问题代码和回购。当我安装时,该过程不再抱怨缺少 noms-config.cmake 文件,但确实给了我以下错误... CMakeLists.txt:6 (add_executable) 处的 CMake 错误:目标“munch”链接到目标“ noms::fruit" 但未找到目标。也许 IMPORTED 目标缺少 find_package() 调用,或者缺少 ALIAS 目标?
    • 变量 noms_FIND_COMPONENTS 的名称错误,抱歉。答案帖现已修复。
    • 这是使该代码有效的关键更改。谢谢你的帮助!
    • 这真的是处理基于组件列表的 CMake 项目的最简单方法吗? CMAKE 文件似乎非常冗长,例如,对于类似的组件(水果/蔬菜),CMakeLists.txt 和 .in 文件几乎相同。我面临着类似的情况,模块/组件始终是文件夹的一部分,但并非每个项目都必须选择所有模块/组件(无法删除未使用的组件)。
    猜你喜欢
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    • 1970-01-01
    • 2016-11-25
    相关资源
    最近更新 更多