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
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?
The two projects are structured are as follows:
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
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}
)
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}
)
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)
For project munch
, the file munch/CMakeLists.txt
is simply
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
)
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
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.
How to export libraries with components in CMAKE?
Please feel free to pull me up on any mistakes I have made, or anything that could be done better. Thanks
* UPDATE *
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!
See Question&Answers more detail:os