【问题标题】:CMake: importing a static lib target and all the libs it depends onCMake:导入静态库目标及其依赖的所有库
【发布时间】:2014-06-15 16:13:19
【问题描述】:

我有一个名为“Base”的静态库,其中包含以下 CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(Base)
add_library(${PROJECT_NAME} STATIC Base.h Base.cpp )
install(FILES ${PROJECT_NAME}.h DESTINATION include )
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets DESTINATION lib)
install(EXPORT ${PROJECT_NAME}-targets DESTINATION lib)
install(FILES ${PROJECT_NAME}-config.cmake DESTINATION lib)

Base-config.cmake 的灵感来自 CMake 教程:

get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
include(${SELF_DIR}/Base-targets.cmake)
get_filename_component(Base_INCLUDE_DIRS "${SELF_DIR}/../include" ABSOLUTE)

Base的编译和安装都OK。

现在,我有另一个名为“Middle”的独特静态库,它依赖于“Base”。在其 CMakeLists.txt 中,我找到了 Base 包并定义了安装/导出步骤,如下所示:

cmake_minimum_required(VERSION 2.8)
project(Middle)
find_package(Base REQUIRED)
if ( Base_FOUND )
    message( "Base found!")
endif()
include_directories(${Base_INCLUDE_DIRS})
add_library(${PROJECT_NAME} STATIC Middle.h Middle.cpp )
target_link_libraries( ${PROJECT_NAME} Base )

install(FILES ${PROJECT_NAME}.h DESTINATION include )
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets DESTINATION lib)
install(EXPORT ${PROJECT_NAME}-targets DESTINATION lib)
install(FILES ${PROJECT_NAME}-config.cmake DESTINATION lib)

Middle-config.cmake 文件与 Base 的非常相似:

get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
include(${SELF_DIR}/Middle-targets.cmake)
get_filename_component(Middle_INCLUDE_DIRS "${SELF_DIR}/../include" ABSOLUTE)

这可以正常工作:找到 Base 并且 Middle 编译和安装正确。

最后,我有一个完全独立的“TopApp”可执行项目,它依赖于“Middle”。同样,在它的 CMakeLists.txt 文件中,我寻找“中间”包并像这样使用它:

cmake_minimum_required(VERSION 2.8)
project(TopApp)
find_package(Middle REQUIRED)
if ( Middle_FOUND )
    message( "Middle found!")
endif()
include_directories(${Middle_INCLUDE_DIRS})
add_executable(TopApp main.cpp )
target_link_libraries( ${PROJECT_NAME} Middle )

因此,TopApp 编译成功,并与 Middle 链接 OK,但无法链接到 Base。但是我可以看到 Base.lib 存在于 TopApp 项目设置中(我在 Windows/Visual Studio 上)。 Middle.lib 的路径是绝对的,并且指向它应该指向的位置,而对于 Base,它只是没有路径的“Base.lib”。

我的目标当然是 TopApp 只是声明它依赖于 Middle。感谢 CMake 导入/导出系统,希望 TopApp.exe 应该自动链接到 Middle.lib 及其所有依赖项(在我的例子中是 Base.lib)。

我这应该是可能的,我怀疑我在 Middle 的 CMakeLists.txt 或 Middle-config.cmake 中遗漏了一些东西,但我有点困惑。

(请注意,我不希望这 3 个项目位于同一棵树中(基本上使用 add_subdirectories),因为我打算将它们分别发布到一些公共存储库上)

编辑:在 wojciii 的回复之后,我重新修改了 XXX-config.cmake 文件。这是 Base-config.cmake:

# - Config file for the Base package
# It defines the following variables
#  BASE_INCLUDE_DIRS - include directories for Base
#  BASE_LIBRARIES    - libraries to link against

# Compute paths
get_filename_component(BASE_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(BASE_INCLUDE_DIRS "${BASE_CMAKE_DIR}/../include" ABSOLUTE)

# Our library dependencies (contains definitions for IMPORTED targets)
if(NOT TARGET Base AND NOT Base_BINARY_DIR)
  include("${BASE_CMAKE_DIR}/Base-targets.cmake")
endif()

# These are IMPORTED targets created by BaseTargets.cmake
set(BASE_LIBRARIES Base)

这里是 Middle-config.cmake:

# - Config file for the Base package
# It defines the following variables
#  MIDDLE_INCLUDE_DIRS - include directories for Middle
#  MIDDLE_LIBRARIES    - libraries to link against

# Compute paths
get_filename_component(MIDDLE_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(MIDDLE_INCLUDE_DIRS "${MIDDLE_CMAKE_DIR}/../include" ABSOLUTE)

# Our library dependencies (contains definitions for IMPORTED targets)
if(NOT TARGET Middle AND NOT Middle_BINARY_DIR)
  include("${MIDDLE_CMAKE_DIR}/Middle-targets.cmake")
  #include("${MIDDLE_CMAKE_DIR}/Base-targets.cmake")
endif()

# These are IMPORTED targets created by MiddleTargets.cmake
set(MIDDLE_LIBRARIES Middle Base)

这样更干净。我还按照建议将 Base 添加到 MIDDLE_LIBRARIES 变量(最后一行)。但是这并不能解决问题:Base 是 TopApp 级别的未知目标,并且链接失败。 我想我应该在 Middle 级别导出 Base-config/targets 文件,但是当我将其添加到 Middle 的 CMakeLists.txt 时,它会抱怨:

install TARGETS given target "Base" which does not exist in this directory.

Base 似乎是一个未知的安装目标,但我仍然可以在 Middle 的 CMakeLists 中做到这一点:

get_property(Base_location TARGET Base PROPERTY LOCATION)
message("Base_location == ${Base_location}")

【问题讨论】:

  • 是否为您在target_link_libraries 指令(如target_link_libraries( ${PROJECT_NAME} Middle Base))解决方案中添加Base 库名称?
  • 很遗憾没有。我希望 TopApp 将“target_link_libraries”简单地添加到 Middle,并且在后台使用 Base.lib。我还尝试将“Base”添加到 TopApp 的 target_link_libraries,正如您提到的那样只是为了检查,但它不起作用,因为那里的 Base 目标是未知的。
  • This question 看起来与您的问题有关。
  • 这确实是相关的。但是我希望 CMake 依赖系统能够帮助我解决这个问题。当所有目标都在同一棵树中时,它的效果非常好,但是对于导出/导入的目标,我无法做到这一点。
  • 啊。我想知道什么是错的。链接器不知道 CMake 目标 - 它知道库。所以它需要“-lBase -L/path/to/lib”或任何其他方式来指定链接什么而不是 CMake 目标。

标签: cmake


【解决方案1】:

我从阅读 http://www.itk.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file(或参阅 http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html 了解 v.3.x)中得到的印象是

Middle-config.cmake 应该设置以下变量:

MIDDLE_INCLUDE_DIRS - include directories for Middle MIDDLE_LIBRARIES - libraries to link against MIDDLE_EXECUTABLE - the bar executable

以便调用 find_package() 的配置文件的用户使用它们来使链接器满意。

您已经使用 Middle-config.cmake 中设置的值调用 include_directories(),所以我认为您应该使用 MIDDLE_LIBRARIES 调用 target_link_libraries()。

【讨论】:

  • 链接页面的更新版本(且不那么复杂)是available as part of the CMake 3.0 manual
  • 谢谢。我假设用户想要 cmake 2.8。我添加了一个指向 cmake 3.x 文档的链接。
  • 幸运的是,该页面上的大部分信息也适用于早期版本的 CMake。我只记得第一次阅读您链接的同一个 wiki 页面上的配置文件,我很难弄清楚它是如何工作的。希望新页面在解释系统方面做得更好。
猜你喜欢
  • 2015-03-20
  • 2012-06-21
  • 2023-03-03
  • 1970-01-01
  • 2012-12-21
  • 1970-01-01
  • 2021-11-21
  • 1970-01-01
相关资源
最近更新 更多