假设我有包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.它可能还取决于不同的包。
答案 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}
,因为它们是作为共享库构建的。而这正是我所寻找的。 p>
答案 2 :(得分:0)
问题是您需要通过创建“适当的”配置文件使每个库导出其目标。这是有记载的here,但是基本上对于每个find_package()
调用,您都应该在配置文件中添加一个相应的find_dependency()
调用。执行此操作时,将以cmake包的形式递归找到目标,并应包括所有传递依赖项。
这是我的意思的示例:
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")
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")
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