应用程序中的自定义库,我是否必须包含两次库依赖项标头?

时间:2016-07-04 11:31:45

标签: c++ cmake dependencies

我试图使用cmake来安装" Skeltrack"进入共享库。这是我的项目分支:https://github.com/birgersp/Skeltrack/tree/cmake

根据我的理解,target_include_directories使包能够保存"它需要的头文件的位置,因此使用我的库的应用程序不必包含此目录以供库运行。这是对的吗?

似乎如果我的库需要一些标题,我需要在我的应用程序中包含这些标题,即使我在我的库中使用target_include_directories ...

图书馆的CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)

project(Skeltrack)

# Set output folders
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)

# Find source files
file(GLOB SOURCES src/*.c)

# Include header files
include_directories(include)

# Create shared library
add_library(${PROJECT_NAME} STATIC ${SOURCES})

# Include Glib library
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package(Glib REQUIRED)
target_link_libraries(${PROJECT_NAME} ${Glib_LIBRARIES})
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${Glib_INCLUDE_DIRS})

# Install library
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

# Install library headers
file(GLOB HEADERS include/*.h)
install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME})

我的应用程序的CMakeListst.txt

cmake_minimum_required(VERSION 2.4.0)

project(skeltrack-test)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Create executable
add_executable(${PROJECT_NAME} ${SOURCES})

# Find and link Skeltrack library
find_library(SKELTRACK Skeltrack PATH_SUFFIXES Skeltrack)
target_link_libraries(${PROJECT_NAME} ${SKELTRACK})

# Find and include Skeltrack library headers
find_path(SKELTRACK_INCDLUDE_DIRS skeltrack.h PATH_SUFFIXES Skeltrack)
target_include_directories(${PROJECT_NAME} PUBLIC ${SKELTRACK_INCDLUDE_DIRS})

输出:

[ 50%] Building CXX object CMakeFiles/skeltrack-test.dir/src/main.o
In file included from /usr/local/include/Skeltrack/skeltrack-skeleton.h:26:0,
                 from /usr/local/include/Skeltrack/skeltrack.h:26,
                 from /home/birger/Workspace/skeltrack-test/src/main.cpp:2:
/usr/local/include/Skeltrack/skeltrack-joint.h:26:18: fatal error: glib.h: No such file or directory
compilation terminated.
CMakeFiles/skeltrack-test.dir/build.make:62: recipe for target 'CMakeFiles/skeltrack-test.dir/src/main.o' failed
make[2]: *** [CMakeFiles/skeltrack-test.dir/src/main.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/skeltrack-test.dir/all' failed
make[1]: *** [CMakeFiles/skeltrack-test.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

似乎我需要在我的应用程序中包含Glib头目录,才能使库运行?如何避免两次包含标题?

1 个答案:

答案 0 :(得分:2)

让我们查看target_include_directories的手册,以便更好地了解它的工作原理:

target_include_directories(<target> [SYSTEM] [BEFORE]  
   <INTERFACE|PUBLIC|PRIVATE> [items1...]   [<INTERFACE|PUBLIC|PRIVATE>
   [items2...] ...])
     

指定编译给定目标时要使用的包含目录。该   named必须由诸如之类的命令创建   add_executable()或add_library(),不得是IMPORTED目标。

     

[...]

     

需要INTERFACEPUBLICPRIVATE关键字来指定   以下参数的范围。 PRIVATEPUBLIC件商品会   填充INCLUDE_DIRECTORIES属性。 PUBLIC和   INTERFACE项将填充INTERFACE_INCLUDE_DIRECTORIES   的财产。以下参数指定include   目录。

秘诀在于INTERFACE_INCLUDE_DIRECTORIES目标属性:

  

使用target_link_libraries()指定目标依赖项时,   CMake将从所有目标依赖项中读取此属性   确定消费者的构建属性。

因此,总结一下:当链接到目标时,CMake将继承该目标的INTERFACE_INCLUDE_DIRECTORIES属性中的所有包含目录。

为此,您需要确保两件事:首先,您的项目必须链接到CMake目标(因为没有目标意味着没有目标属性),并且其INTERFACE_INCLUDE_DIRECTORIES目标属性必须正确公开包含目录。

现在让我们来看看你在做什么:

find_library(SKELTRACK Skeltrack PATH_SUFFIXES Skeltrack)
target_link_libraries(${PROJECT_NAME} ${SKELTRACK})
嗯......那看起来不像是目标。 find_library找到文件,而不是目标。实际上,检查${SKELTRACK}的值将显示它指向文件名。支票if(TARGET ${SKELTRACK})将失败。

这是因为用于处理依赖关系的机制早于接口目标属性系统。它仅依赖于文件路径,因此需要您手动将所有相关选项传递给下游程序。

不幸的是,你无法免费获得更舒适的行为。有人必须在应用程序的构建环境中为Skeltrack创建目标,并相应地填充其目标属性。这需要CMake代码。通常依赖者有责任提供该代码(尽管没有什么可以阻止你自己编写代码;编写和维护它只是有点痛苦)。

CMake提供a convenient mechanism为您的软件包自动生成此类代码。不幸的是,Skeltrack的构建系统必须这样做,以便您的应用程序可以从中受益。

由于您已经分叉了项目,为什么不在其构建系统中添加对此项目的支持并打开拉取请求?