简体   繁体   中英

How to build static library with bundled dependencies - CMake

I am currently using CMake to create a static library which utilizes a few of the static libraries from OpenCV 4 ( core imgcodecs video highgui imgproc ). My intention is to be able to bundle all of the required OpenCV static libraries into my own library so that I can distribute it as one library. Additionally, I want for the user of my library to not have to install OpenCV 4 on their system (but do not mind if the user has to do simple installs using apt-get install). I know there are tools for bundling static libraries (such as using ar for linux). However, where I really am having the issue is with all the dependencies of OpenCV (such as libjpeg, libpng, etc). I don't necessarily mind if these libraries are bundled with mine or linked dynamically as they are relatively easy to install (can be installed with sudo apt-get install, whereas opencv4 needs to be built from source).

What is the best way to go about doing this? This is my current CMakeLists.txt It is currently working, but that is because I am using find_package(OpenCV REQUIRED) (which defeats the purpose of what I am trying to do). When I remove that line, the linker complains about not being able to find the OpenCV dependencies.

cmake_minimum_required(VERSION 2.8)
project(myproject)

set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)

find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)

set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)

list(APPEND LINKER_LIBS opencv_core opencv_highgui opencv_video opencv_imgcodecs libmxnet.so libncnn.a nlohmann_json::nlohmann_json)
file(GLOB SRC${CMAKE_CURRENT_LIST_DIR}/src/*.cpp${CMAKE_CURRENT_LIST_DIR}/main.cpp)

add_library(myproject ${SRC})
target_link_libraries(myproject ${LINKER_LIBS} ${OpenMP_CXX_FLAGS})

To elaborate on my question. I build my project which generates libmyproject.a. I then take this library and will eventually extract the symbols from the OpenCV libs (libopencv_core.a libopencv_highgui.a libopencv_imgcodecs.a libopencv_video.a) and add them to my lib (for the time being, I have not yet done this step, which is why in the below example I am linking libopencv_*). I then use my library in a new project, for which the CMakeLists.txt is shown below:

cmake_minimum_required(VERSION 2.8)
project(myproject-driver)

set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
find_package(OpenMP REQUIRED)

add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver myproject libncnn.a ${OpenMP_CXX_FLAGS} libmxnet.so libopencv_core.a  libopencv_highgui.a  libopencv_imgcodecs.a  libopencv_video.a)

Building this generates the following errors:

Linking CXX executable myproject-driver
/usr/bin/ld: /home/nchafni/Cyrus/myproject/lib/libopencv_imgcodecs.a(grfmt_jpeg.cpp.o): undefined reference to symbol 'jpeg_default_qtables@@LIBJPEG_8.0'
//usr/lib/x86_64-linux-gnu/libjpeg.so.8: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

How can I fix this. Is there some CMake command which will link all these dependencies for me? Do I need to manually track down each dependency of those libopencv_* libs and link those manually? Once again, this is assuming that the person using libmyproject.a can't use find_package(OpenCV REQUIRED) as it won't be defined as they have not installed OpenCV on their machine.

First of all, don't use the super old and outdated version 2.8 of CMake .
CMake 3.x is so much more powerful and pretty straightforward to use.
Some tips for modern CMake .

  • Don't use file(GLOB) , see here why that is.
  • Don't use directory wide instructions, rather use target instructions, eg target_include_directories vs. include_directories .
  • Don't use string variables like ${<PACKAGE_NAME>_LIBRARIES} , rather use targets , eg <Package_NAME>::lib
  • When using targets instead of string variables , all the properties (including LINK_INTERFACE ) of that target will be populated to the library/executable when calling target_link_libraries , so no more include_directories , link_directories , etc.

myproject

cmake_minimum_required(VERSION 3.14)

project(myproject)

set(CMAKE_CXX_STANDARD 14)

find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)

set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)

set(SOURCES ...) # list all the source files here

add_library(myproject ${SOURCES})
target_include_directories(myproject PUBLIC # give it a scope
                           ${CMAKE_CURRENT_LIST_DIR}/include
)
target_link_libraries(myproject PUBLIC # give it a scope
                      opencv_core # using the target, you will get all LINK_LIBRARIES
                      opencv_highgui 
                      opencv_video 
                      opencv_imgcodecs 
                      libmxnet.so  # where is this coming from?
                      libncnn.a # where is this coming from?
                      nlohmann_json::nlohmann_json 
                      OpenMP::OpenMP_CXX ## linking against a target, CXX_FLAGS will be populated automatically
)

myprojec-driver

cmake_minimum_required(VERSION 3.14)
project(myproject-driver)

set(CMAKE_CXX_STANDARD 14)

add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver PUBLIC # give it a scope
                      myproject # gets all dependencies through the LINK_INTERFACE
)

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