CMake and using git-submodule for dependence projects - cmake

Consider the following three projects.
ProjectA does not have any dependencies and its CMakeLists.txt at top level is like the following,
cmake_minimum_required(VERSION 2.8.4)
project(A CXX)
add_library(a ${PROJECT_SOURCE_DIR}/liba.cpp)
ProjectB depend on ProjectA, and I add ProjectA as a git-submodule, so its structure will be like below,
ProjectB
CMakeLists.txt
libb.cpp
ProjectA (git submodule)
CMakeLists.txt
liba.cpp
and ProjectB's CMakeLists.txt look like the following
cmake_minimum_required(VERSION 2.8.4)
project(B CXX)
add_subdirectory(ProjectA)
add_library(b ${PROJECT_SOURCE_DIR}/libb.cpp)
target_link_libraries(b a)
So far it is alright.
Now let's say it comes a ProjectC. It depends on both ProjectA and ProjectB. And let's assume that I am not aware that ProjectB depends on ProjectA already (e.g., I did not create the two before. Or think that ProjectC actually have many dependencies and I shall not be forced to figure out an exact dependency tree among them).
Anyway, I add both ProjectA and ProjectB as git submodules in ProjectC. So it has the following structure,
ProjectC
CMakeLists.txt
libc.cpp
ProjectA (git submodule)
CMakeLists.txt
liba.cpp
ProjectB (git submodule)
CMakeLists.txt
libb.cpp
ProjectA (git submodule of the submodule ProjectB)
CMakeLists.txt
liba.cpp
And it has the following CMakeLists.txt.
cmake_minimum_required(VERSION 2.8.4)
project(C CXX)
add_subdirectory(ProjectA)
add_subdirectory(ProjectB)
add_library(c ${PROJECT_SOURCE_DIR}/libc.cpp)
target_link_libraries(c a b)
Now if I try to run cmake for ProjectC, I get the following error.
add_library cannot create target "a" because another target with the same
name already exists....
I understand the reason of this error. It is because ProjectA is added as a subdirectory twice and all targets created by add_library is Global. For this particular case, I can fix it by remove add_subdirectory(ProjectA) in the ProjectC/CMakeLists.txt. However, consider a situation that ProjectC has many dependencies, and there might or might not be dependencies among them. From point of view of the developer of ProjectC, he should not need to care about the inter-dependencies among its own dependencies.
In this situation, what is the best way to have ProjectC include its dependencies? Having ProjectA and ProjectB as a git-submodule in source form is a must. I am aware that I can simply install ProjectA and ProjectB somewhere, and ProjectC only need to find the installed files somewhere. However, if possible, I would like to avoid that kind of solution (for example, if the installation was built with a different ABI than the one used by ProjectC, incompatibility issues arise). I would like all three projects to be built inside the build tree of ProjectC.

You can check whether the target a already exists before calling add_subdirectory:
if (NOT TARGET a)
add_subdirectory(ProjectA)
endif ()
so that it only adds the subdirectory once for your whole CMake project.

Related

Using third-party libraries with CMake

I want anyone who cloned the repository can build it immediately, and don't need to install the dependencies.
Therefore, I found several ways:
Use git submodule and add_subdirectory.
Use find_package to find the built libraries and the headers.
The first one takes much time to build, so I think the second might be better. To make people be able to build the project instantly, I put the the files in the project, but it saied it doesn't know the linker language. What's this? And how to solve?
Direstories:
Project Root
lib
SDL2
(generated files when install)
include
(headers)
src
(sources)
CMakeLists.txt
CMakeLists.txt:
# ...
list(APPEND CMAKE_PREFIX_PATH lib)
find_package(SDL2)
# ...

Building Documentation for Nested projects with CMake

I'm working on a project that contains other projects as libraries using git
submodules. These sub-projects are under active development as well, so the root
cmake file will run the sub-project cmake files as well.
Example Project Structure:
current_project/
src/
include/
docs/
libs/
sub_module_1/
src/
include/
docs/
sub_module_2/
src/
include/
docs/
sub_module_3/
src/
include/
docs/
src/
The actual building portion works fine. In some of the sub projects, the custom target docs is used to
generate the documentation. Since there are multiple docs targets defined for each
subproject, cmake complains. I don't have control over the sub-projects, and
therefore cannot simply edit the cmake files for those. Is there a way to, without
editing the sub-projects (as the changes will be overwritten when I do a git
update), either have cmake combine all the commands for each sub-project and run all
of them, or have it generate a prefix (probably the project name) for the docs
target for each project?
Edit: I see that CMake has projects as a defined term. I'm not referring to cmake projects. When I am saying project, I am referring to libraries and programs that, while related, are independent of each other.

cmake subdirectories install

I would like to set up a new project using CMake.
My working dir is the following :
CMakeLists.txt
include
- file1.h
src
- file1.cpp
- CMakeLists.txt
tests
- test1.cpp
- CMakeLists.txt
The main CMakeList.txt is the following:
cmake_minimum_required(VERSION 2.8)
project(bench CXX)
include_directories(include)
subdirs(src tests)
The src CMakeList.txt is :
add_library(foo SHARED file1.cpp)
install(TARGETS foo DESTINATION lib)
And the tests CMakeList.txt is:
add_executable(test1 test1.cpp)
target_link_libraries(test1 foo)
install(TARGETS test1 DESTINATION bin)
I would expect the files to be located in
<build_dir>/bin/test1
<build_dir>/lib/libfoo.so
But instead they are organized like this :
<build_dir>/src/test1
<build_dir>/tests/libfoo.so
What am I doing wrong ?
Thanks in advance,
You are giving instructions for the install step/build target, which is independent from the build tree under <binary_dir>.
Set CMAKE_INSTALL_PREFIX to a folder of your choice and run make install (assuming make build system here) after your build. The you will find CMAKE_INSTALL_PREFIX/lib/libfoo.so and CMAKE_INSTALL_PREFIX/bin/test1 as you told cmake. The DESTINATION path is always relative to CMAKE_INSTALL_PREFIX (unless you specify an absolute path, of course).
The compiled libs and binaries within the build tree (i.e. <build_dir>) will always reflect the source tree structure with respect to location; this cannot be changed and is not the intended way of use.
Generally there are three different "things": Source/Build/Install trees. The build tree mirrors the source tree structure and contains cmake-generated extra files and objects. The install "tree" is a setting of your choice, where CMAKE_INSTALL_PREFIX is the root directory under which libraries, archives and binaries are placed. You can control the behaviour completely (what you already intend to do!), although there are reasonable default settings.

CMake and dependencies

I have the following directory structure and library dependencies:
./lib-a
./lib-b (depending on lib-a)
Each directory contains a CMakeLists.txt file for generating its own library.
I am using an out-of-source building policy.
In order to say that lib-b depends on lib-a, I have put the command add_subdirectory(../lib-a lib-a) in ./lib-b/CMakeLists.txt, according to what is taught by the official CMake tutorial. This way I obtain that a subdirectory lib-a is created in ./lib-b/build dir.
This is not the behaviour I desire. What I would like to obtain is CMake making reference to lib-a in generating lib-b and, if lib-a has not been already generated, CMake should generate it inside ./lib-a/build by using the CMakeLists.txt of lib-a (in a behaviour similar to the one of the make tool when dealing with dependencies).
I would also like to add that I am not using a root CMakeLists.txt in my example, but what I would like to have is the lib-b/CMakeLists.txt declaring the dependency on lib-a, thus making lib-a to be compiled, if not already, by using its own lib-a/CMakeLists.txt.
Here is the dirs structure and their contents:
lib-a/
CMakeLists.txt (for compiling lib-a)
src/
test.cpp
include/
test.hpp
lib-b/
main.cpp
CMakeLists.txt (for compiling lib-b; here is the point where I would like to make reference to lib-a, that I need for the generation of lib-b)
lib-b/main.cpp contains also an include of test.hpp of lib-a, because it is using a function of lib-a. This should be taken into consideration in the specification of lib-b/CMakeLists.txt.
What should the content of the two lib-a/CMakeLists.txt and lib-b/CMakeLists.txt files be?
I think you misunderstand the tutorial. The thing that links the libraries together is target_link_library(lib_b lib_a). If the name of the dependency is a library that is part of the build, CMake will magically make the dependencies work. It has nothing to do with subdirectories. In fact, if I have the following directory structure:
./
./a.hpp
./a.cpp
./b.hpp
./b.cpp
./CMakeLists.txt
The following will set the dependencies just fine:
PROJECT(lib_a)
ADD_LIBRARY(lib_a a.hpp a.cpp)
PROJECT(lib_b)
ADD_LIBRARY(lib_b b.hpp b.cpp)
TARGET_LINK_LIBRARIES(lib_b lib_a)
This will work across subdirectory projects as well:
./
./CMakeLists.txt
./lib_a/CMakeLists.txt
./lib_a/a.hpp
./lib_a/a.cpp
./lib_b/CMakeLists.txt
./lib_b/b.hpp
./lib_b/b.cpp
And the list files:
# ./CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
ADD_SUBDIRECTORY(lib_a)
ADD_SUBDIRECTORY(lib_b)
# ./lib_a/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(lib_a)
ADD_LIBRARY(lib_a a.hpp a.cpp)
# ./lib_b/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(lib_b)
INCLUDE_DIRECTORIES(${lib_a_SOURCE_DIR})
ADD_LIBRARY(lib_b b.hpp b.cpp)
TARGET_LINK_LIBRARIES(lib_b lib_a)

Overlapping dependencies between libraries in CMake

Let's say there's the following directory structure:
projects
|
+--lib1
| |
| +-CMakeFiles.txt
|
+--lib2
| |
| +-CMakeFiles.txt
|
+--test
|
+-CMakeFiles.txt
lib1/CMakeFiles.txt:
cmake_minimum_required(VERSION 2.0)
add_library(lib1 STATIC lib1.cpp)
lib2/CMakeFiles.txt:
cmake_minimum_required(VERSION 2.0)
add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)
test/CMakeFiles.txt:
cmake_minimum_required(VERSION 2.0)
project(test)
add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)
add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)
I.e. lib2 depends on lib1 and test depends on both of them. (I know that technically static libraries don't "link", but that's just an example.)
The problem is that with the current setup, lib1 compiles twice - the first time it is within the "test" build directory, and a second time it is within "test/build_directory/lib2/build_directory". I'd like to avoid that.
I want to be able to add a dependency on lib1, lib2 or both of them (using add_subdirectory) to any project that's located elsewhere. So moving CMakeFiles isn't an option. I also want to avoid compiling any library several times.
How can I do that?
Platform: CMake v. 2.8.4 and Windows XP SP3
A top-level CMakeLists.txt file isn't an option, because I want to keep a clean top-level directory and be able to include libraries in other projects that can be located elsewhere. Because it is Windows, I can't "install package system-wide" - I don't want to lose ability to switch compiler on the fly. Utility libraries built with different compilers will use different C runtime libraries/ABI, and as a result will be incompatible.
One other solution is to add a guard at the top of the subdirectory-CMakeLists.txt:
if(TARGET targetname)
return()
endif(TARGET targetname)
Which will cause cmake to do nothing the second time the subdirectory is added (if targetname is being defined in that file, of course).
This will lead to the lib beeing build in an sort-of-arbitrary place (depending on which module added it first) in the build/ tree, but it will be built only once and linked everywhere.
In your example, you would add
if(TARGET lib1)
return()
endif(TARGET lib1)
at the top of lib1/CMakeFiles.txt
With CMake, library dependencies are transitive, so you shouldn't call add_subdirectory twice in test/CMakeFiles.txt (nor do you need to list lib1 as a dependency of test since it is already a dependency of lib2's).
So you could modify test's CMakeFiles.txt to:
cmake_minimum_required(VERSION 2.8.7) # Prefer the most current version possible
project(test)
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)
add_executable(test main.cpp)
target_link_libraries(test lib2)
Also, you should probably remove the cmake_minimum_required calls from your non-project CMakeFiles.txt files (the lib ones). For further info, run:
cmake --help-policy CMP0000
This setup will still cause all libs to be recompiled if you add a similar test2 subdirectory and project which depends on lib1 and lib2. If you really don't want to have a top-level CMakeFiles.txt in projects/, then you're stuck with what you're doing, or you could use either the export or install command.
export would create a file which could be included by other projects and which imports the targets into the project which calls include.
install could install the libraries to another common subdirectory of projects/. Depending on your source directory structure, this could have the benefit of only making the intended library API headers available to dependent projects.
However, both of these options require the dependent library projects to be rebuilt (and installed) if they are modified, whereas your current setup includes all the dependent targets in your project, so any change to a source file in a dependent library will cause your test target to go out of date.
For further details about export and install, run:
cmake --help-command export
cmake --help-command install
Perhaps add a top-level CMakeLists.txt in your projects dir. Something like:
project( YourProjects )
add_subdirectory( lib1 )
add_subdirectory( lib2 )
add_subdirectory( test )
This should be sufficient and will give you a solution-file or makefile in your top-level build-dir. You should then remove the add_subdirectory( ../lib1 ... from your lib1 and lib2 projects, but instead simply link to them. CMake will know how to find lib1 and lib2 when compiling test.
I.e. in lib2:
project( lib2)
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)
and in test:
project( test )
add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)
Added bonus: you will get makefiles/solutionfiles for building lib2 (with dependent lib1) in the lib2 directory...