Reputation: 4663
I have a project main_project
. It depends on two libraries - libA
and libB
, which in turn depend on lib_common
each.
Graphically project's structure looks like this:
main_project
|
+-libA
| |
| +-CMakeLists.txt
|
+-libB
| |
| +-CMakeLists.txt
|
+-lib_common
| |
| +-CMakeLists.txt
|
+-CMakeLists.txt
Since libA
uses lib_common
it's pretty natural to call add_subdirectory(lib_common)
inside libA
's CMakeLists.txt
. But the libB
also depends on lib_common
. If I put it in a subdirectory again it will compile twice. And I don't want that. Also I want to keep all my subprojects clean and self-contained - that's why I don't want to put lib_common
in top-level main_project
's CMakeLists.txt
(because lib_common
have nothing with main_project
).
Which options do I have?
Upvotes: 7
Views: 2916
Reputation: 4473
I would add one more abstraction level to your project structure:
app
- this is for executables and for everything that belongs to them,lib
- libraries for the application.The top-level CMakeLists.txt
will only know that there is two different thing, the app
sub-project and the lib
sub-project. An example directory structure could look like follows:
FooProject
|-- app
| |-- CMakeLists.txt
| `-- src
| `-- foo.cpp
|-- CMakeLists.txt
`-- lib
|-- CMakeLists.txt
|-- libA
| |-- CMakeLists.txt
| |-- inc
| | `-- bar.h
| `-- src
| `-- bar.cpp
|-- libB
| |-- CMakeLists.txt
| |-- inc
| | `-- baz.h
| `-- src
| `-- baz.cpp
`-- lib_common
|-- CMakeLists.txt
|-- inc
| `-- common_tool.h
`-- src
`-- common_tool.cpp
The top-level CMakeLists.txt
contains only the following:
cmake_minimum_required(VERSION 2.8)
project(FooProject)
add_subdirectory(lib)
add_subdirectory(app)
The app/CMakeLists.txt
should know that there is a lib
folder from where you can include headers and that the executable depends on the libA
and the libB
:
project(foo)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lib)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src FOO_SOURCES)
add_executable(foo ${FOO_SOURCES})
add_dependencies(foo libA libB)
target_link_libraries(foo libA libB)
install(TARGETS foo RUNTIME DESTINATION bin ARCHIVE DESTINATION bin)
The lib/CMakeLists.txt
exists to tie together the libA
, libB
and lib_common
:
cmake_minimum_required(VERSION 2.8)
add_subdirectory(lib_common)
add_subdirectory(libA)
add_subdirectory(libB)
Let's say that lib_common
has no dependencies, so the lib/lib_common/CMakeLists.txt
won't see outside of its folder:
project(lib_common)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src LIBCOMMON_SOURCES)
add_library(lib_common ${LIBCOMMON_SOURCES})
In this example the lib/libA/CMakeLists.txt
and lib/libB/CMakeLists.txt
have almost identical content and only they deal with the lib_common
:
project(libA)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc ${CMAKE_CURRENT_SOURCE_DIR}/..)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src LIBA_SOURCES)
add_library(libA ${LIBA_SOURCES})
add_dependencies(libA lib_common)
target_link_libraries(libA lib_common)
install(TARGETS libA LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
In this example the lib
sub-project is what you can call as clean and self-contained.
Upvotes: 5
Reputation: 1258
I think this a fairly standard CMake solution:
# toplevel CMakeLists.txt
add_subdirectory(libA)
add_subdirectory(libB)
add_subdirectory(lib_common)
# libA CmakeLists.txt
add_library(libA ${LIBA_SOURCES})
target_link_libraries(libA lib_common)
and similar for libB
.
You do not have to call add_subdirectory(lib_common)
before add_subdirectory(libA)
, CMake handles the dependency management automatically.
Upvotes: 2