CMake and using git-submodule for dependence proje

2019-04-14 04:32发布

问题:

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.

回答1:

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.