首页 > 解决方案 > CMake:add_subdirectory 两次作为共享项目

问题描述

我已经在互联网上到处搜索,但这个问题没有简单的答案。我读过这个:CMake: Attempted to add link library to target which is not built in this directory

但是我不想将它们target_link_libraries放入同一个 cmake 列表中,而是我想将链接命令留在每个相应的列表中,因为库 cmake 列表必须知道它必须与哪个库依赖项链接。

Mine项目的结构是这样的:

   <main_exe>     :   /main
       |          :    |
   <main_lib>     :    +- /_3dparty
    /      \      :    |   |
<lib_A>  <lib_B>  :    |   +- /lib_A/CMakeLists.txt
    \      /      :    |   +- /lib_B/CMakeLists.txt
    <lib_X>       :    |   +- /lib_X/CMakeLists.txt
                  :    |
                  :    +- /CMakeLists.txt

所有 3 个库都是独立且静态的,我不想将它们作为彼此的子目录。

但是,当我尝试分别add_subdirectory使用外部二进制目录lib_Alib_B

if (NOT TARGET lib_X)
    add_subdirectory(${lib_X_ROOT} ${CMAKE_BUILD_ROOT}/_3dparty/lib_X)
endif()

add_dependencies(${PROJECT_NAME} lib_X)

target_link_libraries(${PROJECT_NAME}
    PUBLIC
      lib_X
)

,然后cmake抛出一个错误:

Attempt to add link library "lib_X" to target "lib_B" which is not built in
this directory

有没有办法让它在不过度ExternalProject_Add使用的情况下工作?

编辑:

我在最小的例子中重现了这个问题。

库 libB 实际上的结构略有不同:

/main
 |
 +- /_3dparty
 |   |
 |   +- /lib_A/CMakeLists.txt
 |   +- /lib_B
 |   |   |
 |   |   +- /libsubdir/CMakeLists.txt
 |   |   +- /CMakeLists.txt
 |   |
 |   +- /lib_X/CMakeLists.txt
 |
 +- /CMakeLists.txt

这就是问题的原因。

/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(main_project)

set(CMAKE_BUILD_ROOT ${CMAKE_CURRENT_LIST_DIR}/_build)
set(CMAKE_LIBS_ROOT ${CMAKE_CURRENT_LIST_DIR}/_3dparty)

add_library(mainlib ${CMAKE_CURRENT_LIST_DIR}/main.cpp)

add_subdirectory(${CMAKE_LIBS_ROOT}/libA ${CMAKE_BUILD_ROOT}/_3party/libA)
add_subdirectory(${CMAKE_LIBS_ROOT}/libB ${CMAKE_BUILD_ROOT}/_3party/libB)

target_link_libraries(mainlib
  PUBLIC
    libA
    libB
)

/_3dparty/libA/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(libA_project)

add_library(libA STATIC ${CMAKE_CURRENT_LIST_DIR}/main.cpp)

add_subdirectory(${CMAKE_LIBS_ROOT}/libX ${CMAKE_BUILD_ROOT}/_3party/libX)

target_link_libraries(libA
  PUBLIC
    libX
)

/_3dparty/libB/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(libB_project)

#add_library(libB STATIC ${CMAKE_CURRENT_LIST_DIR}/libsubdir/main.cpp)

add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/libsubdir) # the root cause of the issue

#add_subdirectory(${CMAKE_LIBS_ROOT}/libX ${CMAKE_BUILD_ROOT}/_3party/libX) # would be an error if add this twice

target_link_libraries(libB # <- the issue error is here
  PUBLIC
    libX
)

/_3dparty/libB/libsubdir/CMakeLists.txt

add_library(libB STATIC main.cpp)

/_3dparty/libX/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(libX_project)

add_library(libX STATIC ${CMAKE_CURRENT_LIST_DIR}/main.cpp)

输出:

x:\_cmake_test\_out>cmake .. -G "Visual Studio 14 2015"
CMake Error at _3dparty/libB/CMakeLists.txt:11 (target_link_libraries):
  Attempt to add link library "libX" to target "libB" which is not built in
  this directory.


-- Configuring incomplete, errors occurred!
See also "X:/_cmake_test/_out/CMakeFiles/CMakeOutput.log".

如果取消注释add_library(libB ...和注释,add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/libsubdir)则问题消失。

有什么建议如何在不编辑 3dparty 库的情况下解决这个问题?

标签: cmakestatic-libraries

解决方案


不要add_subdirectory()在可能被用作子目录的 cmake-projects 中执行此操作。

而是创建一个超级项目,它add_subdirectory()在同一级别(在同一 CMakeLists.txt 中)执行所有操作。顺序并不重要,target_link_libraries()一旦处理完所有 CMakeLists.txt,CMake 就会解决目标依赖关系(通过 完成)。

这是我最终在所有项目中使用的方法。它有一些缺点,例如每个库的单元测试可能很困难,但这可以通过使用变量调节测试来解决。


推荐阅读