简体   繁体   中英

Cmake link path error when linking static lib

I have a cmake project which consists of my own static library and executable. The simplified project structure is:

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

Basically the path for project direct dependencies - tesseract and opencv and their dependencies.

Cmake file for static library(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}
)

So far everything is working great. teststaticlib.lib is building fine, without any errors. But as soon as I add any executable to the project and link teststaticlib to it:

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
)

I get this error when building:

ninja: error: 'C:/tesseract41_x64-static/leptonica_x64-windows-static/debug/lib/gif.lib', needed by 'debug/mainproject/testexe.exe', missing and no known rule to make it

Why do I get this error and how do I fix it? Why is cmake looking for my direct dependencies' sub-dependencies ( gif in this case is a dependency of either tesseract of leptonica ) inside leptonica folder when their path is different as you can see from LibsPath.cmake ? I know that this is not tess or leptonica specific problem, because if I change those libraries to any other, the pattern remains and I still get the same error but with other libs. So there must be something wrong in my cmake files, but I can't figure where the error is.

Edit: Tried to change my library linking to PUBLIC and adding same dependencies to exe. Even tries linking sub-dependency gif to exe - still get the same error.

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
)

Following might be helpful, Quote from "mastering cmake by kitware":

CMAKE_PREFIX_PATH: This specifies a path that will be used by the FIND_XXX() commands. It contains the "base" directories for the FIND_XXX() commands to append appropriate sub-directories to. FIND_PROGRAM() adds /bin to each of the directories in the path; FIND_LIBRARY() appends /lib to each of the directories in the path

Because of this I generally simply make an library import script of some kind and use PATHS/HINTS to find_library() command to point into the correct directory. To my best of knowledge most robust way to import library targets is to not use find_library() as-is but use cmake INSTALL() command generated import scripts from that library if available. See find_library() docs .

Also linking static libs is bit weird. They get compiled but nothing actually gets linked to them until final binary is produced. PRIVATE libs are meant that the linked symbols are sealed inside the static lib and the dependency won't be carried over any further. PUBLIC then simply adds the lib to LINK_INTERFACE_LIBRARIES/LINK_LIBRARIES target property and the dependencies are carried over until final binary is produced. (shared lib or executable)

Note that I have *nix background and I have might gotten few details wrong if building on windows.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM