2017-10-12 64 views
0

给定一个具有“app”和“lib”兄弟目录的项目,其中“app”根据由“lib”构建的(静态)库构建可执行文件。我想要的是普通构建过程仅构建库的情况,但如果构建“应用程序”,则构建“库”和“应用程序”。链接建立静态库,而不是使用add_subdirectory?

什么我目前做的是现在,在app,包括我libadd_subdirectory,但是由于各种原因,这是通过一种机制,我不拉在lib的间接依赖到链接线的所有意识到。我想就像是让我的应用程序只是建立libmylib.alibmylib.pc,然后app可以只从libmylib.pc(或手动指定它)计算自己的连接线,但我不知道如何完成。

这里有一个最低工作的例子,我已经有了设立现在:

的lib /的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") 

应用/的CMakeLists.txt

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") 

要得到一个工作的例子,这里是一些源文件,在libssl拉在lib(但这个乐趣ction没有在应用程序中使用) - 我把它们放在学家,因为他们只是为了保持完整性,我不想弄乱问题文本:

的问题是,当我cmake app,然后做make VERBOSE=1,产生链接器命令是:

/usr/lib/hardening-wrapper/bin/c++  CMakeFiles/myapp.dir/main.cpp.o -o myapp build/libmylib.a -lssl 

但我没有在app的任何地方指定-lssl。通常情况下,这样会很好,但是在我的实际应用中,-lssl和其他几个不必要的符号由于间接依赖性而被包含为.so文件。当我手动从链接器命令中删除它们时,任务生成并运行得很好。理想情况下,我会使用其.pc文件(本例中未生成)来构建.a,并且如果必须拉入过多依赖关系,则可以手动调整链接行,但使用此方法时,链接器标记(可能其他的东西)以某种我不明白的方式从lib范围泄漏出来。

+1

查看['target_link_libraries']的文档(https://cmake.org/cmake/help/latest/command/target_link_libraries.html);如果您不希望目标的依赖关系传播,则需要将它们指定为“PRIVATE”或“PUBLIC”以外的值,默认情况下会按照您使用的那样进行指定。 – legalize

+0

@legalize Aaaaah!这非常明确,谢谢!如果你想做出答案,那么它就像任何答案一样好。 – Paul

回答

0

链接是关于解析符号,以便最终目标(独立的可执行文件或共享对象)具有它需要启动的所有内容。事情很简单,当你只依赖单一的图书馆,或者只依赖于其他图书馆的一系列图书馆。任何中等规模或更大规模的项目都不太可能出现这种情况。根本问题是如何处理传递依赖关系,例如程序直接使用的东西的依赖关系。

CMake理解所有这一切,旨在让您在不​​理解整个依赖关系图的情况下使用库变得简单。如果您查看target_link_libraries的文档,您会看到描述的PRIVATEPUBLICINTERFACE关键字。这使您可以描述构建库时需要的库的私有需求(编译定义,编译参数,从属库等)。公共部分允许您指定库及其依赖者(消费者)需要的东西。界面部分让你指定依赖者需要的东西,而不是库本身。命令target_compile_definitionstarget_include_directories的操作类似。

所有这些的结果是,通过在CMake中正确声明的依赖关系,该依赖关系的客户端只需将其添加到其自己的target_link_libraries命令中的依赖关系列表中,并自然地获取所有编译定义,包括目录和为成功编译和链接所必需的暂时链接依赖性。

CppCon 2017演示文稿Modern CMake for modular design更详细地介绍了这一点。