First I have to admit that I agree with @Tsyvarev. Your CMake environment should fit to your processes/workflow and should take project sizes and team structure into account. Or generally speaking the environment CMake will be used in. And this tends to be – in a positive way – very alive.
So this part of your question is difficult to answer and I’ll concentrate on the technical part:
- CMake has to know the location of the dependencies – relative or absolute – by
- having a monolithic source tree (the one you don’t want anymore)
- a common directory location for includes/libraries/binaries
- getting the paths via config files/variable definitions
- using registration in or installation from a database provided on the host
- To keep your CMake files as simple as possible I would recommend to group your CMake code into separate dedicated files:
- Prefer toolchain files over
if(SomeCompiler)
statements - Move common/repeating code parts as
function()
bodies into a shared CMake include file - Move complex non-target specific code parts into their own (CMake) script files
- Prefer toolchain files over
Example Code
Since you have specifically asked for the find_package()
variant, taking Use CMake-enabled libraries in your CMake project and the things listed above:
MyCommonCode.cmake
cmake_policy(SET CMP0022 NEW)
function(my_export_target _target _include_dir)
file(
WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Config.cmake"
"
include(\"\$\{CMAKE_CURRENT_LIST_DIR\}/${_target}Targets.cmake\")
set_property(
TARGET ${_target}
APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES \"${_include_dir}\"
)
"
)
export(
TARGETS ${_target}
FILE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Targets.cmake"
EXPORT_LINK_INTERFACE_LIBRARIES
)
export(PACKAGE ${_target})
endfunction(my_export_target)
C/CMakeLists.txt
include(MyCommonCode.cmake)
...
my_export_target(C "${CMAKE_CURRENT_SOURCE_DIR}/include")
B/CMakeLists.txt
include(MyCommonCode.cmake)
find_package(C REQUIRED)
...
target_link_libraries(B C)
my_export_target(B "${CMAKE_CURRENT_SOURCE_DIR}/include")
A/CMakeLists.txt
include(MyCommonCode.cmake)
find_package(B REQUIRED)
...
target_link_libraries(A B)
This keeps all 3 build environments separate, only sharing the relatively static MyCommonCode.cmake
file. So in this approach I have so far not covered your first point, but would recommend the use of a external script to chain/trigger your build steps for A/B/C.