如何在 cmake 中使用 COMPONENTS 配置项目
我想使用 cmake 创建一个项目项目,该项目的访问方式与 Poco 使用的方式类似.我发现以 Poco 为例非常拥挤且难以理解,因此我正在尝试创建一个没有宏的最小版本,以便我可以看到发生了什么.我在这里为这个示例构建了一个存储库.
I want to create a project of projects using cmake which is accessible in a similar manner to that used by Poco. I find that using Poco as an example is crowded and difficult to follow so I am trying to create a minimal version, without macros so that I can see what is going on. I have constructed a repository for this example here.
https://github.com/markeastwood82/nomnoms
这和下面写的内容是我在阅读/研究现代 CMake"几天后如何解决这个问题的最佳猜测,除了它不太管用.本质上,我有一个库 noms
,其中包含组件 fruit
和 veg
,我希望从应用程序 munch
动态链接它们.我可以安装 noms
库,但无法使用 munch
找到它.有人可以帮我把这个东西放在一起吗?
This, and what is written below is currently my best guess at how to solve this problem after some days of reading up / grappling with "modern CMake", except that it doesn't quite work. Essentially I have a library noms
with components fruit
and veg
which I want link dynamically from an application munch
. I can install the noms
library, but cannot find it with munch
. Can someone please help me to put this thing together?
两个项目的结构如下:
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
包含以下内容.
The file noms/CMakeLists.txt
contains the following.
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
几乎相同)是
The file noms/fruit/CMakeLists.txt
(and almost identical for noms/veg/CMakeLists.txt
) is
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
几乎相同)是
Finally, the file for noms/fruit/fruit-config.cmake.in
(and almost identical for noms/veg/veg-config.cmake
) is
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/<food-type>/CMakeLists.txt
中使用 configure_file
的方法是否合适,因为这似乎不需要这里的例子
After installing noms
I try to build munch
, however cmake can't find the noms-config.cmake
file. I don't know what it should contain, nor where I should really put it. I am also not sure it the method of using configure_file
in noms/<food-type>/CMakeLists.txt
is appropriate, given this does not seem to be required in the example here
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 方法.
My question is essentially the same as was asked here, which is currently unanswered (the accepted answer is incorrect, as I have commented in that thread). Actually to be fair, since that thread is 6 years old, it may have been correct at the time of writing, but does not appear to utilize the xxx-config.cmake method that is now recommended.
如何在 CMAKE 中导出带有组件的库?
请随时提出我所犯的任何错误,或者任何可以做得更好的事情.谢谢
Please feel free to pull me up on any mistakes I have made, or anything that could be done better. Thanks
* 更新 *
除了上面更新的 noms/CMakeLists.txt
文件之外,我还根据下面 @Tsyvarev 的建议实现了以下 noms/noms-config.cmake
文件...
In addition to the updated noms/CMakeLists.txt
file above, I have implemented the following noms/noms-config.cmake
file as per advice from @Tsyvarev below ...
foreach(component ${noms_FIND_COMPONENTS})
include(${CMAKE_CURRENT_LIST_DIR}/noms-${component}-config.cmake)
endforeach()
生成的代码现在可以工作了,谢谢!
The resulting code now works, thankyou!
推荐答案
CMake 不会自动处理 COMPONENTS
列表.它将任务留给 noms-config.cmake
脚本,在发出命令时搜索并执行该脚本
CMake doesn't process COMPONENTS
list automatically. It leaves that mission to noms-config.cmake
script, which is searched and executed when one issues the command
find_package(noms COMPONENTS fruit veg)
来自 find_package 文档:
在配置模式下,find_package
会自动处理 REQUIRED
、QUIET
和 [version]
选项,但将其留给包配置文件以对包有意义的方式处理组件.
In Config mode
find_package
handlesREQUIRED
,QUIET
, and[version]
options automatically but leaves it to the package configuration file to handle components in a way that makes sense for the package.
在此配置文件中,您可以从 noms_FIND_COMPONENTS
变量中提取请求的组件列表(通过 find_package()
的 COMPONENTS
选项给出),并执行适当的操作.例如:
Inside this config file, you may extract list of requested components (given via COMPONENTS
option to find_package()
) from the noms_FIND_COMPONENTS
variable, and perform appropriate actions. For example:
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
您已经在项目中安装的脚本.
This implies, that you will install the script noms-config.cmake
to lib/cmake/noms
subdirectory, near the other .cmake
scripts you have already installed in your project.
相关文章