Overlapping library dependencies in CMake

Suppose you have 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) 

Those. lib2 depends on lib1 and test depends on both of them. (I know that technically static libraries do not β€œlink”, but this is just an example.)

The problem is that with the current setup, lib1 compiles twice - the first time it is in the test directory of the assembly, and the second time it is in test / build_directory / lib2 / build_directory. I would like to avoid this.

I want to be able to add a dependency on lib1, lib2, or both of them (using add_subdirectory) to any project located elsewhere. Therefore, moving CMakeFiles is not an option. I also want to avoid compiling any library multiple times.

How can i do this?

Platform: CMake v. 2.8.4 and Windows XP SP3

The top-level CMakeLists.txt file is not suitable, because I want to keep a clean top-level directory and be able to include libraries in other projects that may be located elsewhere. Since this is Windows, I cannot "install the package for the entire system" - I do not want to lose the ability to switch the compiler on the fly. Utility libraries created using different compilers will use different C / ABI runtime libraries and as a result will be incompatible.

+7
source share
3 answers

With CMake, library dependencies are transitive, so you should not call add_subdirectory twice in test/CMakeFiles.txt (and you do not need to list lib1 as a test dependency, since it is already a lib2 's dependency).

So you can change test 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) 

In addition, you should probably delete cmake_minimum_required calls from your CMakeFiles.txt project files that are not project related (lib). For more information, run:

 cmake --help-policy CMP0000 


This setting will still lead to recompilation of all libs libraries if you add a similar subdirectory test2 and a project that depends on lib1 and lib2 . If you really do not want to have top-level CMakeFiles.txt in projects/ , then you are stuck in what you are doing, or you can use either the export or install command.

export will create a file that can be include d by other projects and which imports targets into the project that calls include .

install can install libraries in another common projects/ subdirectory. Depending on the structure of the source directory, this may be advantageous only so that the intended library API headers are available for dependent projects.

However, both of these options require that dependent library projects be rebuilt (and installed) if they are changed, while your current setup includes all dependent objects in your project, so any change to the source file in the dependent library will cause your object test get tired.

For more information about export and install run the following command:

 cmake --help-command export cmake --help-command install 
+4
source

Another solution is to add a defender at the top of the subdirectory - CMakeLists.txt:

 if(TARGET targetname) return() endif(TARGET targetname) 

This will cause cmake to do nothing the second time a subdirectory is added (of course, if the name of the target is defined in this file).

This will build lib beeing in an arbitrary place (depending on which module was added first) in build / tree, but it will be built only once and connected everywhere.

In your example, you would add

 if(TARGET lib1) return() endif(TARGET lib1) 

at the top of lib1 / CMakeFiles.txt

+12
source

Perhaps add top-level CMakeLists.txt to your projects. Sort of:

 project( YourProjects ) add_subdirectory( lib1 ) add_subdirectory( lib2 ) add_subdirectory( test ) 

This should be enough and give you the solution file or makefile in your top level build-dir. Then you must remove add_subdirectory( ../lib1 ... from your lib1 and lib2 projects, but just refer to them instead. CMake will know how to find lib1 and lib2 when compiling the test.

those. in lib2:

 project( lib2) add_library(lib2 STATIC lib2.cpp) target_link_libraries(lib2 lib1) 

and in the test:

 project( test ) add_executable(test main.cpp) target_link_libraries(test lib1 lib2) 

Added bonus: you get makefiles / solutionfiles to create lib2 (with dependent lib1) in the lib2 directory ...

0
source

Source: https://habr.com/ru/post/912393/


All Articles