给出一个项目" app"和" lib"兄弟目录,其中" app"根据" lib"构建的(静态)库构建可执行文件。我喜欢的是正常构建过程只构建库的情况,但是如果我构建" app"它构建了" lib"和" app"。
我现在正在做的是,在app
中,我将lib
与add_subdirectory
包括在内,但无论出于什么原因,这都是所有 lib
通过我不知道的机制间接依赖于链接线。我喜欢的目的是让我的应用只构建libmylib.a
和libmylib.pc
,然后app
可以从{{1}计算自己的链接线(或手动指定),但我不确定它是如何完成的。
这是我现在已经设置的最低工作示例:
LIB /的CMakeLists.txt
libmylib.pc
应用/的CMakeLists.txt
cmake_minimum_required(VERSION 3.8.0)
project(mylib CXX)
find_package(PkgConfig REQUIRED)
pkg_check_modules("mylib" "libssl")
find_package(Boost REQUIRED)
set(LIBDIR "${PROJECT_SOURCE_DIR}")
set(HEADERS "${LIBDIR}/map_printer.hpp")
set(SOURCES "${LIBDIR}/map_printer.cpp")
add_library("mylib" "${SOURCES}")
target_include_directories("mylib" PUBLIC "${LIBDIR}"
"${Boost_INCLUDE_DIR}"
"${mylib_INCLUDE_DIRS}")
target_link_libraries("mylib" "${Boost_LIBRARIES}" "${mylib_LIBRARIES}")
install(TARGETS "mylib" ARCHIVE DESTINATION "lib")
install(FILES ${HEADERS} DESTINATION "include")
为了得到一个工作示例,这里有一些在lib中引入cmake_minimum_required(VERSION 3.8.0)
project(mylib CXX)
set(APPDIR "${PROJECT_SOURCE_DIR}")
set(LIBDIR "${APPDIR}/../lib")
set(SOURCES "${APPDIR}/main.cpp")
add_subdirectory("${LIBDIR}" "build")
list(APPEND LIBS "mylib")
add_executable("myapp" "${SOURCES}")
target_include_directories("myapp" PUBLIC "${LIBDIR}")
target_link_libraries("myapp" "${LIBS}")
install(TARGETS "myapp" DESTINATION "bin")
的源文件(但是这个函数没有在应用程序中使用) - 我把它们放在gists中因为它们仅用于完整性和我不想弄乱问题文本:
问题是,当我libssl
然后执行cmake app
时,生成的链接器命令是:
make VERBOSE=1
但我没有在/usr/lib/hardening-wrapper/bin/c++ CMakeFiles/myapp.dir/main.cpp.o -o myapp build/libmylib.a -lssl
中的任何位置指定-lssl
。通常情况下这很好,但在我的真正的应用程序中,由于间接依赖性,app
和其他几个不必要的符号被包含为.so文件。当我手动从链接器命令中删除它们时,任务构建并运行正常。理想情况下,我会使用-lssl
文件(在此示例中未生成)来提取已构建的.a
,如果必须提取过多的依赖项,我可以手动调整链接行,但是使用此方法,链接器标志(以及可能的其他内容)以某种我不理解的方式从.pc
范围泄漏。
答案 0 :(得分:0)
链接完全是为了解决符号,以便最终目标(独立可执行文件或共享对象)具有需要启动的所有内容。当您只依赖于单个库或者依赖于其他任何东西的库集合时,事情就变得简单了。对于任何中等或较大尺寸的程序,这种情况不太可能发生。根本问题是如何处理传递依赖,例如程序直接使用的东西的依赖关系。
CMake了解所有这些,旨在使您在不了解整个依赖关系图的情况下使用库变得简单。如果您查看target_link_libraries
的文档,则会看到所述的PRIVATE
,PUBLIC
和INTERFACE
个关键字。这允许您描述构建库时所需的库的私有要求(编译定义,编译参数,依赖库等)。公共部分允许您指定库及其依赖(消费者)所需的内容。界面部分允许您指定依赖者需要的内容,但不能指定库本身。命令target_compile_definitions
和target_include_directories
的运作方式相似。
所有这一切的结果是,在CMake中正确声明的依赖项,该依赖项的客户端只是将其添加到其自己的target_link_libraries
命令中的依赖项列表中,它自然会获取所有编译定义,包括成功编译和链接所需的目录和暂时链接依赖。
CppCon 2017演讲Modern CMake for modular design更详细地介绍了这一点。