【问题标题】:Custom library in application, do I have to include the library dependency headers twice?应用程序中的自定义库,我是否必须包含两次库依赖标头?
【发布时间】:2016-07-05 21:40:25
【问题描述】:

我正在尝试使用 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 头目录才能使库运行?如何避免两次包含标题?

【问题讨论】:

  • 带有target_include_directories() 的自传播包含目录仅适用于创建的真实目标,例如find_package() 不是 find_library()
  • 我想我必须将 Skeltrack 库作为一个包安装,还是有其他方法可以解决这个问题?
  • 我不确定您到底想要完成什么。 Making cmake library accessible by other cmake packages automatically 之类的东西?
  • 我正在尝试构建我的应用程序,而不必包含库所需的标头目录。这些标头应该在我构建库时包含在内,但我不明白为什么不包含这些标头。
  • 让我尝试改写:如何构建我的库,以便它可以找到它需要在我的应用程序中运行的标头?

标签: c++ cmake dependencies


【解决方案1】:

让我们查看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 属性。 PUBLICINTERFACE 项目将填充 INTERFACE_INCLUDE_DIRECTORIES 的财产。以下参数指定包括 目录。

秘诀在于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 的构建系统必须这样做才能让您的应用程序从中受益。

既然您已经分叉了项目,为什么不向他们的构建系统添加对此的支持并打开一个拉取请求?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 2010-10-06
    相关资源
    最近更新 更多