Lets say I have four separate projects. Three are libraries, Common
, Foo
, and Bar
, and one of them is an executable, App
. Both Foo
and Bar
depend on the Common library, and App
depends on Foo
and Bar
. Furthermore, some of these projects have some scripts that need to run to generate some header and source files.
Right now I have a mess of calls like this:
if (NOT TARGET common)
add_subdirectory(${common_lib_directory})
endif()
But this doesn't feel like the right solution. If I don't wrap it in that if guard, then there are errors because it tries to build Common
more than once. Putting if guards in the CMakeLists for each project doesn't seem right either. Should I be writing Find<Library>
scripts for each library? I've tried looking for examples or best practices on how to set up my CMakeLists files, but the only examples I can find are either too trivial or cover completely different use cases.
It was requested in the comments that I post some code. This is more or less what my CMakeLists.txt file looks like:
cmake_minimum_required(VERSION 2.8.12)
project(app)
# Temporary files (like object files) created while compiling projects.
set(tmp_dir ${CMAKE_BINARY_DIR}/obj)
# Directory which contains the source for 3rd party libraries.
if(NOT DEFINED dependencies_root)
get_filename_component(
dependencies_root "${CMAKE_CURRENT_SOURCE_DIR}/../../../../external"
REALPATH)
endif()
set(dependencies_foo_dir "${dependencies_root}/foo"
CACHE PATH "Directory containing the foo library.")
set(dependencies_bar_dir "${dependencies_root}/bar"
CACHE PATH "Directory containing the bar library.")
if(NOT TARGET foo)
add_subdirectory("${dependencies_foo_dir}" ${tmp_dir}/foo)
endif()
if(NOT TARGET bar)
add_subdirectory("${dependencies_bar_dir}" ${tmp_dir}/bar)
endif()
include_directories(${dependencies_foo_dir}/include)
include_directories(${foo_generated_include_dir})
include_directories(${dependencies_bar_dir}/include)
include_directories(${bar_generated_include_dir})
set(app_srcs ...)
add_executable(app ${app_SRCS})
target_link_libraries(app foo bar common)
As previously mentioned, the reason I have the if (NOT TARGET blah)
guards is because if I don't then I get errors like these:
CMake Error at /path/to/my/project/CMakeLists.txt:267 (add_library):
add_library cannot create target "blah" because another target with the
same name already exists. The existing target is a static library created
in source directory
"/path/to/blah".
See documentation for policy CMP0002 for more details.
If you have such closely-linked projects, the best decision seems to use guard from re-including at the beginning of each project. Such guard can be easily implemented using return command, which returns from currently executed
add_subdirectory()
call:Foo/CMakeLists.txt:
So any project can use unprotected
add_subdirectory()
call for include given one:App/CMakeLists.txt:
It is possible to implement guard as a macro, put it into the library and use it in every your project:
cmake/utils.cmake:
Macro usage is straightforward: