c++ - 如何在 cmake 中使用 COMPONENTS 配置项目
问题描述
我想使用 cmake 创建一个项目项目,该项目的访问方式与 Poco 使用的方式类似。我发现以 Poco 为例非常拥挤且难以理解,因此我正在尝试创建一个没有宏的最小版本,以便我可以看到发生了什么。我在这里为这个例子构建了一个存储库。
https://github.com/markeastwood82/nomnoms
这一点,以及下面写的内容,目前是我在阅读/努力解决“现代 CMake”几天后如何解决这个问题的最佳猜测,除了它不太有效。本质上,我有一个noms
包含组件fruit
的库veg
,我希望从应用程序动态链接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
文件。我不知道它应该包含什么,也不知道我应该把它放在哪里。我也不确定使用configure_file
in的方法noms/<food-type>/CMakeLists.txt
是否合适,因为这里的示例似乎不需要这样做
我的问题与此处提出的问题基本相同,目前没有答案(接受的答案不正确,正如我在该线程中评论的那样)。实际上公平地说,由于该线程已有 6 年历史,在撰写本文时它可能是正确的,但似乎没有使用现在推荐的 xxx-config.cmake 方法。
请随时提出我所犯的任何错误,或任何可以做得更好的事情。谢谢
* 更新 *
除了上面更新的noms/CMakeLists.txt
文件之外,我还根据下面noms/noms-config.cmake
@Tsyvarev 的建议实施了以下文件......
foreach(component ${noms_FIND_COMPONENTS})
include(${CMAKE_CURRENT_LIST_DIR}/noms-${component}-config.cmake)
endforeach()
生成的代码现在可以工作了,谢谢!
解决方案
CMake 不会COMPONENTS
自动处理列表。它将任务留给noms-config.cmake
脚本,在发出命令时搜索并执行
find_package(noms COMPONENTS fruit veg)
从find_package文档中:
在 Config 模式下,自动
find_package
处理REQUIRED
、QUIET
和[version]
options ,但将其留给包配置文件以对包有意义的方式处理组件。
在此配置文件中,您可以从变量中提取请求的组件列表(通过COMPONENTS
选项 to给出),并执行适当的操作。例如:find_package()
noms_FIND_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.cmake
到lib/cmake/noms
子目录中,靠近.cmake
您已在项目中安装的其他脚本。
推荐阅读
- windows - 使用 Wireshark 捕获网络路由器流量
- prolog - SWI-Prolog 给我错误信息
- android - 使用 maven-publish 发布带有构建变体的 android apk 和 aar (android gradle plugin 4.0)
- c# - 从子触发器设置父 Visible 属性
- asp.net-core - ASP.NET Core MVC 错误处理禁用默认处理
- shiny - 渲染图像不输出闪亮
- android - Flutter-“extendBody: true” 完全没有任何作用。我想在导航栏后面扩展body
- java - Java 新手,尝试解决 OldMacdonald Had a Farm 歌曲练习的主要部分
- vba - 根据单元格值发送自动电子邮件
- c# - 在 JetBrains Rider 中使用“Ado.net 实体数据模型”