【问题标题】:Cmake link path error when linking static lib链接静态库时Cmake链接路径错误
【发布时间】:2020-04-14 12:39:27
【问题描述】:

我有一个由我自己的静态库和可执行文件组成的 cmake 项目。简化的项目结构为:

顶级cmake:

cmake_minimum_required(VERSION 3.16)

project(mainproject 
    VERSION 0.0.1 
    DESCRIPTION ""
    LANGUAGES CXX
)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")

#include libs
include(LibsPath)

add_subdirectory(teststaticlib)
add_subdirectory(testexe)

cmake/LibsPath.cmake:

        set(CMAKE_PREFIX_PATH
            "C:/tesseract41_x64-static/leptonica_x64-windows-static"
            "C:/tesseract41_x64-static/tiff_x64-windows-static"
            "C:/tesseract41_x64-static/tesseract_x64-windows-static"
            "C:/tesseract41_x64-static/libpng_x64-windows-static"
            "C:/tesseract41_x64-static/libjpeg-turbo_x64-windows-static"
            "C:/tesseract41_x64-static/giflib_x64-windows-static"
            "C:/tesseract41_x64-static/libwebp_x64-windows-static"
            "C:/opencv4_x64-windows-static"
            "C:/protobuf_x64-windows-static"
            "C:/hdf5_x64-windows-static"
            "C:/szip_x64-windows-static"
    )

基本上是项目直接依赖项的路径 - tesseractopencv 及其依赖项。

静态库的Cmake文件(teststaticlib/CMakeLists.txt):

cmake_minimum_required(VERSION 3.16)

project(teststaticlib)

set(CMAKE_GENERATOR "Ninja")
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")

#enable unicode
add_definitions(-DUNICODE -D_UNICODE)

set(SOURCE_FILES
    #...source files
)
set(PRIVATE_HEADER_FILES 
    #... header files
)
set(PUBLIC_HEADER_FILES
    #... header files
)
add_library(teststaticlib STATIC ${SOURCE_FILES} ${PRIVATE_HEADER_FILES} ${PUBLIC_HEADER_FILES})
add_library(teststaticlib::teststaticlib ALIAS teststaticlib)
set_target_properties(teststaticlib PROPERTIES OUTPUT_NAME teststaticlib)
target_include_directories(teststaticlib 
    PRIVATE 
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/include
)

#precompiled headers
target_precompile_headers(teststaticlib PRIVATE src/pch.h)

#link libs
find_package(tesseract CONFIG REQUIRED)
find_package(opencv CONFIG REQUIRED core imgproc highgui)

include_directories(${Tesseract_INCLUDE_DIRS})
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(teststaticlib 
    PRIVATE 
        ${Tesseract_LIBRARIES}
        ${OpenCV_LIBS}
)

到目前为止,一切都很好。 teststaticlib.lib 构建良好,没有任何错误。 但只要我将任何可执行文件添加到项目并将teststaticlib 链接到它:

testexe/CMakeLists.txt

cmake_minimum_required(VERSION 3.16)

project(testexe)

set(SOURCE_FILES
    main.cpp
)
add_executable(testexe ${SOURCE_FILES})

target_link_libraries(testexe 
    PRIVATE 
        teststaticlib::teststaticlib
)

构建时出现此错误:

ninja:错误:'C:/tesseract41_x64-static/leptonica_x64-windows-static/debug/lib/gif.lib','debug/mainproject/testexe.exe'需要,缺少并且没有已知的规则来制作它

为什么会出现此错误,如何解决? 为什么 cmake 会在 leptonica 文件夹中查找我的直接依赖项的子依赖项(在这种情况下,giftesseractleptonica 的依赖项),而它们的路径与 LibsPath.cmake 中的不同? 我知道这不是tessleptonica 特定的问题,因为如果我将这些库更改为任何其他库,模式仍然存在,但我仍然会遇到相同的错误,但使用其他库。 所以我的cmake文件一定有问题,但我不知道错误在哪里。

编辑: 试图更改链接到PUBLIC 的库并将相同的依赖项添加到exe。甚至尝试将子依赖项 gif 链接到 exe - 仍然得到相同的错误。

teststaticlib/CMakeLists.txt:

target_link_libraries(teststaticlib 
PUBLIC 
    ${Tesseract_LIBRARIES}
    ${OpenCV_LIBS}
)

testexe/CMakeLists.txt

    cmake_minimum_required(VERSION 3.16) 
project(testexe)

set(SOURCE_FILES
    main.cpp
)
add_executable(testexe ${SOURCE_FILES})

    find_package(tesseract CONFIG REQUIRED)
    find_package(opencv CONFIG REQUIRED core imgproc highgui)
    find_package(gif REQUIRED)
    include_directories(${Tesseract_INCLUDE_DIRS})
    include_directories(${OpenCV_INCLUDE_DIRS})
    include_directories(${GIF_INCLUDE_DIRS})

target_link_libraries(testexe 
    PRIVATE 
        ${GIF_LIBRARIES}
        ${Tesseract_LIBRARIES}
        ${OpenCV_LIBS}
        basicemul::basicemul
)

【问题讨论】:

  • 因为您正在构建一个 static 库,所以它不会“链接”依赖项。如果可执行文件需要使用它们,您还需要为可执行文件显式列出它们。一种解决方法可能很简单,只需将您的 target_link_libraries(teststaticlib PRIVATE ${Tesseract_LIBRARIES} ${OpenCV_LIBS}) 调用更改为 PUBLIC
  • @squareskittles 我试过了,没有帮助。编辑了主帖。在这种情况下,我的可执行文件也是一个简单的 main.cpp 文件,主函数为空,不使用 teststaticlib 中的任何函数。
  • 错误本身说这个库“丢失”,你检查C:/tesseract41_x64-static/leptonica_x64-windows-static/debug/lib/gif.lib是否真的存在?
  • @squareskittles 我做了,不,它不存在。我的问题是,当添加到 CMAKE_PREFIX_PATH 的 GIF lib 的路径是“C:/tesseract41_x64-static/giflib_x64-windows-static”时,为什么 cmake 会在该特定路径上寻找 gif。为什么它只在将 teststaticlib 链接到 exe 时而不是在构建 teststaticlib 本身时才在那里寻找 GIF lib。
  • @estw272 看来您已经找到了问题所在。你的 Cmake 文件没问题,这很正常,建议 debug 和 release 使用不同的链接,并且 debug build 尝试找到相应的 debug 库。安装 lib 的调试版本,或者手动破解 lib 附带的 cmake 文件。另外,我个人更喜欢直接设置 Tesseract_DIR 而不是使用 CMAKE_PREFIX_PATH。您还可以创建 Tesseract_DIR 作为系统环境变量。

标签: c++ cmake static lib


【解决方案1】:

以下内容可能会有所帮助,引自“mastering cmake by kitware”:

CMAKE_PREFIX_PATH:指定 FIND_XXX() 命令将使用的路径。它包含 FIND_XXX() 命令的“基本”目录,以附加适当的子目录。 FIND_PROGRAM() 将 /bin 添加到路径中的每个目录; FIND_LIBRARY() 将 /lib 附加到路径中的每个目录

因此,我通常只是简单地制作某种库导入脚本并使用 PATHS/HINTS to find_library() 命令指向正确的目录。 据我所知,导入库目标的最可靠方法是不按原样使用 find_library() ,而是使用 cmake INSTALL() 命令从该库生成导入脚本(如果可用)。 请参阅 find_library() docs

另外链接静态库有点奇怪。它们被编译,但在生成最终二进制文件之前,实际上没有任何东西链接到它们。 PRIVATE 库意味着链接的符号被密封在静态库中,并且依赖项不会被进一步传递。然后,PUBLIC 只需将 lib 添加到 LINK_INTERFACE_LIBRARIES/LINK_LIBRARIES 目标属性,并且依赖关系会一直延续到生成最终二进制文件。 (共享库或可执行文件)

请注意,我有 *nix 背景,如果在 Windows 上构建,我可能会弄错一些细节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-11
    • 2013-12-24
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多