Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't link OpenCV statically - attempt static link of dynamic object #14825

Closed
cyrusbehr opened this issue Jun 18, 2019 · 8 comments
Closed

Can't link OpenCV statically - attempt static link of dynamic object #14825

cyrusbehr opened this issue Jun 18, 2019 · 8 comments
Labels
category: build/install invalid question (invalid tracker) ask questions and other "no action" items here: https://forum.opencv.org

Comments

@cyrusbehr
Copy link

First off, I apologize if the answer is obvious, I am still learning.
Really appreciate the help!

System information (version)
  • OpenCV => 3.2
  • Operating System / Platform => Ubuntu 18.04
Detailed description

I am trying to link opencv statically. When I link opencv dynamically, my program compiles and links fine. However, when I try to link statically, the get the following error:

====================[ Build | all | Debug ]=====================================
/snap/clion/73/bin/cmake/linux/bin/cmake --build /home/nchafni/Cyrus/OpenCVTest/cmake-build-debug --target all -- -j 2
-- Configuring done
-- Generating done
-- Build files have been written to: /home/nchafni/Cyrus/OpenCVTest/cmake-build-debug
[ 50%] Linking CXX executable OpenCVTest
/usr/bin/ld: attempted static link of dynamic object `/usr/lib/x86_64-linux-gnu/libjpeg.so'
collect2: error: ld returned 1 exit status
CMakeFiles/OpenCVTest.dir/build.make:139: recipe for target 'OpenCVTest' failed
make[2]: *** [OpenCVTest] Error 1
CMakeFiles/Makefile2:72: recipe for target 'CMakeFiles/OpenCVTest.dir/all' failed
make[1]: *** [CMakeFiles/OpenCVTest.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

When I go to the directory /usr/lib/x86_64-linux-gnu/ I can see that there is indeed a libpng.a. I am therefore confused as to why it is trying to choose the shared library instead.

Note that when compiling OpenCV, I did set the following flags cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=OFF ..

Steps to reproduce

For compiling opencv:

I started on a fresh Ubuntu 18.04 VM

sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

cd ~/<my_working_directory>
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git

cd ~/opencv
mkdir build
cd build

cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=OFF ..

make -j4 
sudo make install

main.cpp

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>

int main() {
    std::cout << "Hello, World!" << std::endl;
    cv::Mat testMat;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(OpenCVTest)
set(CMAKE_CXX_STANDARD 14)
find_package( OpenCV REQUIRED )
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(OpenCVTest main.cpp)
target_link_libraries(OpenCVTest ${OpenCV_LIBS} "-static")

To compile my program

cmake .
make

Makefile

# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.14

# Default target executed when no arguments are given to make.
default_target: all

.PHONY : default_target

# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:


#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:


# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =

.SUFFIXES: .hpux_make_needs_suffix_list


# Suppress display of executed commands.
$(VERBOSE).SILENT:


# A target that is always out of date.
cmake_force:

.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/local/bin/cmake

# The command to remove a file.
RM = /usr/local/bin/cmake -E remove -f

# Escaping for special characters.
EQUALS = =

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/nchafni/Cyrus/OpenCVTest

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/nchafni/Cyrus/OpenCVTest

#=============================================================================
# Targets provided globally by CMake.

# Special rule for the target rebuild_cache
rebuild_cache:
	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
	/usr/local/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache

# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache

.PHONY : rebuild_cache/fast

# Special rule for the target edit_cache
edit_cache:
	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
	/usr/local/bin/ccmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : edit_cache

# Special rule for the target edit_cache
edit_cache/fast: edit_cache

.PHONY : edit_cache/fast

# The main all target
all: cmake_check_build_system
	$(CMAKE_COMMAND) -E cmake_progress_start /home/nchafni/Cyrus/OpenCVTest/CMakeFiles /home/nchafni/Cyrus/OpenCVTest/CMakeFiles/progress.marks
	$(MAKE) -f CMakeFiles/Makefile2 all
	$(CMAKE_COMMAND) -E cmake_progress_start /home/nchafni/Cyrus/OpenCVTest/CMakeFiles 0
.PHONY : all

# The main clean target
clean:
	$(MAKE) -f CMakeFiles/Makefile2 clean
.PHONY : clean

# The main clean target
clean/fast: clean

.PHONY : clean/fast

# Prepare targets for installation.
preinstall: all
	$(MAKE) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall

# Prepare targets for installation.
preinstall/fast:
	$(MAKE) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall/fast

# clear depends
depend:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
.PHONY : depend

#=============================================================================
# Target rules for targets named OpenCVTest

# Build rule for target.
OpenCVTest: cmake_check_build_system
	$(MAKE) -f CMakeFiles/Makefile2 OpenCVTest
.PHONY : OpenCVTest

# fast build rule for target.
OpenCVTest/fast:
	$(MAKE) -f CMakeFiles/OpenCVTest.dir/build.make CMakeFiles/OpenCVTest.dir/build
.PHONY : OpenCVTest/fast

main.o: main.cpp.o

.PHONY : main.o

# target to build an object file
main.cpp.o:
	$(MAKE) -f CMakeFiles/OpenCVTest.dir/build.make CMakeFiles/OpenCVTest.dir/main.cpp.o
.PHONY : main.cpp.o

main.i: main.cpp.i

.PHONY : main.i

# target to preprocess a source file
main.cpp.i:
	$(MAKE) -f CMakeFiles/OpenCVTest.dir/build.make CMakeFiles/OpenCVTest.dir/main.cpp.i
.PHONY : main.cpp.i

main.s: main.cpp.s

.PHONY : main.s

# target to generate assembly for a file
main.cpp.s:
	$(MAKE) -f CMakeFiles/OpenCVTest.dir/build.make CMakeFiles/OpenCVTest.dir/main.cpp.s
.PHONY : main.cpp.s

# Help Target
help:
	@echo "The following are some of the valid targets for this Makefile:"
	@echo "... all (the default if no target is provided)"
	@echo "... clean"
	@echo "... depend"
	@echo "... rebuild_cache"
	@echo "... OpenCVTest"
	@echo "... edit_cache"
	@echo "... main.o"
	@echo "... main.i"
	@echo "... main.s"
.PHONY : help



#=============================================================================
# Special targets to cleanup operation of make.

# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
	$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system


@mshabunin
Copy link
Contributor

Why did you add -static option to linker flags?

@cyrusbehr
Copy link
Author

cyrusbehr commented Jun 18, 2019

I need to link opencv statically as I want to have to contained within my binary. It is one of the requirements for my project.

@alalek
Copy link
Member

alalek commented Jun 18, 2019

BUILD_SHARED_LIBS=OFF

is enough.

Remove -static option and try again.

@cyrusbehr
Copy link
Author

Thank you for the answer @alalek , and I would like to follow up. So I removed the -static option and the executable compiles and runs as desired. My ultimate goal is to create a static library of my own which I can share with others and makes use of opencv (without the recipient having opencv installed on their device). I am using the following CMakeLists.txt to generate the static library. Note that the source.cpp file includes the header opencv2/opencv.hpp and creates and initializes a cv::Mat (keeping it simple for the purpose of this exercise) :

cmake_minimum_required(VERSION 3.14)
project(OpenCVTest)
set(CMAKE_CXX_STANDARD 14)
find_package( OpenCV REQUIRED )
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
include_directories(${OpenCV_INCLUDE_DIRS})
add_library(OpenCVTest source.cpp)
target_link_libraries(OpenCVTest ${OpenCV_LIBS})

The issue is that when I use my libOpenCVTest.a library in another project, I get undefined reference errors to opencv functions (which are only resolved once I link in opencv into that project too). This indicates that the static opencv library was not linked correctly when I generated libOpenCVTest.a.

Do you know what could be causing this problem.

When I inspect user/local/lib I can see that the opencv static libs (.a) are indeed there, and there are no opencv shared libs (.so).

I am therefore not sure what is causing this error.

Thanks again for the help

@cyrusbehr
Copy link
Author

Just some more information for context:

source.cpp file:

#include <iostream>
#include <opencv2/opencv.hpp>

void TestClass::myTestFunc() {
    cv::Mat myMat;
    std::cout << "We were able to create the matrix\n";
}

And when I link libOpenCVTest.a from another project and try calling the myTestFunc function:

/root/test/lib/libOpenCVTest.a(source.cpp.o): In function `cv::Mat::~Mat()':
source.cpp:(.text._ZN2cv3MatD2Ev[_ZN2cv3MatD5Ev]+0x39): undefined reference to `cv::fastFree(void*)'
/root/test/lib/libOpenCVTest.a(source.cpp.o): In function `cv::Mat::release()':
source.cpp:(.text._ZN2cv3Mat7releaseEv[_ZN2cv3Mat7releaseEv]+0x4b): undefined reference to `cv::Mat::deallocate()'
collect2: error: ld returned 1 exit status
CMakeFiles/openCVTest2.dir/build.make:94: recipe for target 'openCVTest2' failed
make[2]: *** [openCVTest2] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/openCVTest2.dir/all' failed
make[1]: *** [CMakeFiles/openCVTest2.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

@alalek
Copy link
Member

alalek commented Jun 19, 2019

I use my libOpenCVTest.a library in another project, I get undefined reference errors to opencv functions

For static linkage you need all .a files including dependencies and dependencies of dependencies (with infinite recursion).
So your libOpenCVTest.a should re-distribure all OpenCV .a files at least.

Proper packaging of "static" bundles is very complex task.
Perhaps it can't be solved on library level, you need some "package manager" with tracking dependencies of static libraries.


Alternatively you can try using single CMake file (project) for both your library and your app:

...
add_library(OpenCVTest source.cpp)
target_link_libraries(OpenCVTest ${OpenCV_LIBS})
...
add_executable(OpenCVApp main.cpp)
target_link_libraries(OpenCVApp OpenCVTest)

@cyrusbehr
Copy link
Author

Ok, thank you for the help @alalek

@milinddeore
Copy link

I use my libOpenCVTest.a library in another project, I get undefined reference errors to opencv functions

For static linkage you need all .a files including dependencies and dependencies of dependencies (with infinite recursion).
So your libOpenCVTest.a should re-distribure all OpenCV .a files at least.

Proper packaging of "static" bundles is very complex task.
Perhaps it can't be solved on library level, you need some "package manager" with tracking dependencies of static libraries.

Alternatively you can try using single CMake file (project) for both your library and your app:

...
add_library(OpenCVTest source.cpp)
target_link_libraries(OpenCVTest ${OpenCV_LIBS})
...
add_executable(OpenCVApp main.cpp)
target_link_libraries(OpenCVApp OpenCVTest)

@alalek Is there a way i would need small set of libraries and want my library to by small in size?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: build/install invalid question (invalid tracker) ask questions and other "no action" items here: https://forum.opencv.org
Projects
None yet
Development

No branches or pull requests

4 participants