你如何处理CMake中的递归依赖

时间:2016-04-01 13:56:39

标签: cmake

假设我有包A,B和C.包B使用包A,包C使用包B.我创建共享库。

所以在包B中我做了类似

的事情
    find_package(A)
    ...
    if(${A_FOUND})
    target_link_libraries(B ${A_LIBRARIES})
    endif()

在包C中我做

    find_package(B)
    ...
    if(${B_FOUND})
    target_link_libraries(C ${B_LIBRARIES})
    endif()

    add_executable(main main.cpp)
    target_link_libraries(main C)

其中$ {B_LIBRARIES}仅包含B.编译器现在会抱怨

    /usr/bin/ld: cannot find -lA
    collect2: error: ld returned 1 exit status

只要A安装在不在C的link_directories中的地方。我想知道处理这个问题的正确方法是什么。对我来说,在C中使用find_package(A)(可行)似乎并不好。对我来说尤其如此,因为我事先并不知道B是否依赖于A.它可能还取决于不同的包。

3 个答案:

答案 0 :(得分:0)

删除find_package,因为您告诉编译器要查找已安装在用户计算机中的软件包。相反,首先使用add_library创建库,稍后在二进制文件中,您可以包含标题目录include_directories,其余部分已知。

答案 1 :(得分:0)

这里的问题是<div class="row"> <div class="col">1</div> <div class="col">2</div> <div class="col">3</div> </div>应该包含绝对路径。像Trilinos这样的软件包提供类似${A_LIBRARIES}的内容,您应该通过

来包含这些内容
${Trilinos_LIBRARY_DIRS}

然而,根据https://cmake.org/cmake/help/v3.0/command/link_directories.html,这是错误的。 link_directories(${Trilinos_LIBRARY_DIRS}) 应该返回库的绝对路径,所以我不应该这样做。我通过执行类似

的操作来修复此问题
find_package(Trilinos)

我在这里制作了一个包列表,所以我可以为我的所有包执行此操作,这些包都复制了Trilinos的错误行为。

回到原来的问题。我仍然必须在set(library_directories ${Trilinos_LIBRARY_DIRS}) list(APPEND library_directories ${Trilinos_TPL_LIBRARY_DIRS}) set(library_dependencies ${Trilinos_LIBRARIES}) list(APPEND library_dependencies ${Trilinos_TPL_LIBRARIES}) set(found_library_dependencies) foreach(lib ${library_dependencies}) set(found_${lib}) if(IS_ABSOLUTE ${lib}) set(found_${lib} ${lib}) else() find_library(found_${lib} ${lib} ${library_directories}) endif() list(APPEND found_library_dependencies ${found_${lib}}) message(STATUS "Using ${lib}") message(STATUS "Found in ${found_${lib}}") endforeach(lib) 中加入${A_INCLUDE_DIRS},因此${B_INCLUDE_DIRS}可以找到C的头文件中包含的A的头文件,但是我可以忍受这个。但是,B现在不必包含${B_LIBRARIES},因为它们是作为共享库构建的。而这正是我所寻找的。

答案 2 :(得分:0)

问题是您需要通过创建“适当的”配置文件使每个库导出其目标。这是有记载的here,但是基本上对于每个find_package()调用,您都应该在配置文件中添加一个相应的find_dependency()调用。执行此操作时,将以cmake包的形式递归找到目标,并应包括所有传递依赖项。

这是我的意思的示例:

项目A

CMakeLists.txt

project(liba)
add_library(a src/a.cpp)
target_link_libraries(a PUBLIC flag1 flag2)
install(TARGETS a EXPORT ${PROJECT_NAME}Targets ARCHIVE DESTINATION lib)
install(FILES ${PROJECT_NAME}Config.cmake DESTINATION lib/cmake/${PROJECT_NAME})
install(EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION lib/cmake/${PROJECT_NAME})

libaConfig.cmake

include("${CMAKE_CURRENT_LIST_DIR}/libaTargets.cmake")

项目B

CMakeLists.txt

project(libb)
add_library(b src/b.cpp)
find_package(liba CONFIG REQUIRED)
target_link_libraries(b PUBLIC a)
install(TARGETS b EXPORT ${PROJECT_NAME}Targets ARCHIVE DESTINATION lib)
install(FILES ${PROJECT_NAME}Config.cmake DESTINATION lib/cmake/${PROJECT_NAME})
install(EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION lib/cmake/${PROJECT_NAME})

libbConfig.cmake

include(CMakeFindDependencyMacro)
find_dependency(liba) # The key step for getting recursion working
include("${CMAKE_CURRENT_LIST_DIR}/libbTargets.cmake")

项目C

CMakeLists.txt

add_executable(main main.cpp)
find_package(libb CONFIG REQUIRED) # Also recursively calls find_package(liba ...)
target_link_libraries(main PRIVATE b) # should become -lb -la -lflag1 -lflag2