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.