Running multiple versions of OpenCV on the same computer - c++

My computer is running Ubuntu-16.04-LTS and OpenCV-2.4.13 is already installed on it. However, I would like to use the functionalities of newer versions of OpenCV, such as OpenCV-3.2.0 without removing the older version.
So far I have downloaded OpenCV-3.2.0 and compiled and installed it. I am uing CMake to compile OpenCV, so I changed my CMakeLists.txt file to:
cmake_minimum_required (VERSION 3.2)
project(io)
find_package(OpenCV REQUIRED)
include_directories("/home/ubuntu/opencv-3.2.0/include") # directory of OpenCV-3.2.0
link_directories("/home/ubuntu/opencv-3.2.0/lib") # directory of OpenCV-3.2.0
add_executable(cv_io io.cpp)
target_link_libraries(cv_io ${OpenCV_LIBS})
Now, when I run this little piece of code,
#include <iostream>
#include "opencv2/core/version.hpp"
int main(int argc, char ** argv)
{
std::cout << "OpenCV version: "
<< CV_MAJOR_VERSION << "."
<< CV_MINOR_VERSION << "."
<< CV_SUBMINOR_VERSION
<< std::endl;
return 0;
}
I get
OpenCV version: 3.2.0
instead of
OpenCV version 2.4.13
So everything seems to be in order, except when I start running some actual OpenCV functions such as:
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat img = cv::imread("ferrari.jpg");
cv::Mat dst;
cv::Sobel(img, dst, CV_32F, 1, 1);
cv::imwrite("ferrari_sobel.png", dst);
cv::VideoCapture input(0);
}
I get all these undefined reference errors:
CMakeFiles/cv_io.dir/io.cpp.o: In function main':
io.cpp:(.text+0x40): undefined reference tocv::imread(cv::String
const&, int)' io.cpp:(.text+0xd4): undefined reference to
cv::imwrite(cv::String const&, cv::_InputArray const&,
std::vector<int, std::allocator<int> > const&)'
CMakeFiles/cv_io.dir/io.cpp.o: In functioncv::String::String(char
const*)':
io.cpp:(.text._ZN2cv6StringC2EPKc[_ZN2cv6StringC5EPKc]+0x40):
undefined reference to cv::String::allocate(unsigned long)'
CMakeFiles/cv_io.dir/io.cpp.o: In functioncv::String::~String()':
io.cpp:(.text._ZN2cv6StringD2Ev[_ZN2cv6StringD5Ev]+0x10): undefined
reference to cv::String::deallocate()' CMakeFiles/cv_io.dir/io.cpp.o:
In functioncv::String::operator=(cv::String const&)':
io.cpp:(.text.ZN2cv6StringaSERKS0[ZN2cv6StringaSERKS0]+0x2c):
undefined reference to `cv::String::deallocate()' collect2: error: ld
returned 1 exit status CMakeFiles/cv_io.dir/build.make:121: recipe for
target 'cv_io' failed make2: * [cv_io] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/cv_io.dir/all'
failed make1: * [CMakeFiles/cv_io.dir/all] Error 2 Makefile:83:
recipe for target 'all' failed make: *** [all] Error 2
Does anyone know how to solve this problem? I think the problem is that I'm still not linking all the libraries properly in the CMakeLists.txt. Also, I found a comment below this article mentioning something similar to what I'm experiencing, but I do not understand the page containing the solution it is referring to. I'm very new to OpenCV and CMake, so hopefully you can provide me instructions that are as explicit as possible. I've been stuck on this for forever, so any help is highly appreciated! Thank you very much!

I have a working CMakelists.txt for almost the same configuration as you describe except that I am running a dauntingly old Ubuntu 12.04 (its not my own computer).
I believe your problem comes from this line:
find_package(OpenCV REQUIRED)
Which gives you access to your distribution's OpenCV 2.4. Then you are linking against the manually installed 3.2.x version. So problems arise as soon as the interface of a function you use has changed between the two version. Your first piece of code run by chance I think.
Here is my CMakeList.txt:
cmake_minimum_required(VERSION 2.8)
project(demo)
find_package(OpenCV 3.2 REQUIRED PATHS "/path/to/OCV3.2/install/dir/")
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(main main.cpp)
target_link_libraries(main ${OpenCV_LIBS})
If you do not want to commit to your repository the hardcoded path to your install of OpenCV 3.2 you can refine this CMakeList.txt by changing the find_package line to:
if(DEFINED ENV{OPENCV_INSTALL_DIR})
find_package(OpenCV 3.2 REQUIRED PATHS $ENV{OPENCV_INSTALL_DIR})
else()
message("OPENCV_INSTALL_DIR not set, searching in default location(s)")
find_package(OpenCV 3.2 REQUIRED)
endif(DEFINED ENV{OPENCV_INSTALL_DIR})
Then you just have to define the variable OPENCV_INSTALL_DIR before running cmake. I do that by exporting it from my .bashrc

While you are setting up the include files to use the newly installed OpenCV headers, you are linking against the opencv on your system path. The version is just stored in the headers, which is why it's outputting the expected version but failing to link. Try setting the variable "OpenCV_DIR" to the location of the OpenCVConfig.cmake file you want to use before running the find module.
See the documentation for your version of cmake here. Note the two modes that find_package can be run in (Module or Config mode).
Unless you are linking to static libraries, you will still have problems running your library / application. To fix that, you'll need to add the libraries to your LD_LIBRARY_PATH.

Indeed, you're linking against system-default version of OpenCV.
Reconfigure your project by calling CMake with right path to file OpenCVConfig.cmake.
cmake /path/to/your/sources -DOpenCV_DIR=/home/ubuntu/opencv-3.2.0
Find file CMakeCache.txt in your build directory. It contains internal CMake variables, OpenCV paths are also there.
Also, it is incorrect to hardcode paths. Use include_directories(${OPENCV_INCLUDE_DIRS})
And quotation from OpenCVConfig.cmake
- OpenCV_LIB_DIR : The directory(es) where lib files are. Calling LINK_DIRECTORIES
with this path is NOT needed.

Related

CMake 'undefined reference' error with CERN-ROOT

I'm writing a small addition to CERN ROOT and now can't get rid of 'undefined reference' errors on every function from ROOT that I use (and my classes too). Can't find a way to fix this, so looking for help here.
My OS is Linux Mint 19. I use g++ as my c++ compiler, however, I tried clang++ and there was no difference.
I downloaded sources of ROOT from their github and built it now on my computer. Output of root --version is this:
ROOT Version: 6.19/01
Built for linuxx8664gcc on Sep 29 2019, 14:25:35
From heads/master#v6-19-01-1167-gbec9f2d1f7
This is the structure of my project:
ParentFolder
--CMakeLists.txt
--General
----include/...
----source/...
----CMakeLists.txt
----LinkDef.h
--Test
----include/...
----source/...
----CMakeLists.txt
Important lines from top level CMakeLists.txt are:
find_package(ROOT REQUIRED)
list(APPEND CMAKE_PREFIX_PATH $ENV{ROOTSYS})
include(${ROOT_USE_FILE})
add_subdirectory("./General")
add_subdirectory("./Test")
From Test/CmakeLists.txt:
add_executable(Test source/test_main.cpp)
target_include_directories(Test PUBLIC "./include")
target_link_libraries(Test PUBLIC General GTest::GTest GTest::Main ${ROOT_LIBRARIES})
From General/CmakeLists.txt:
file(GLOB_RECURSE SOURCES . source/*.cpp)
ROOT_GENERATE_DICTIONARY(GeoManagerExtractor LINKDEF LinkDef.h)
add_library(General SHARED ${SOURCES} GeoManagerExtractor.cxx)
target_link_libraries(General ${ROOT_LIBRARIES})
target_include_directories(General PUBLIC "./include")
Here are first few lines produced by CMake (while using clang++)
CMakeFiles/Test.dir/source/test_main.cpp.o: In function `main':
test_main.cpp:(.text+0x37): undefined reference to `TGeoManager::Import(char const*, char const*, char const*)'
test_main.cpp:(.text+0x3f): undefined reference to `gGeoManager'
test_main.cpp:(.text+0x8c): undefined reference to `gGeoManager'
CMakeFiles/Test.dir/source/test_main.cpp.o: In function `TGeoManagerExporter::~TGeoManagerExporter()':
test_main.cpp:(.text._ZN19TGeoManagerExporterD2Ev[_ZN19TGeoManagerExporterD2Ev]+0xa): undefined reference to `vtable for TGeoManagerExporter'
../General/libGeneral.so: undefined reference to `ROOT::GenerateInitInstance(TGeoManagerExporter const*)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Here are a few lines from test_main.cpp:
TGeoManager::Import("../root_tests/geofile_full.root");
if (gGeoManager == nullptr) {
std::cerr << "Can't find TGeoManager in file" << std::endl;
return 0;
}
UPD: Forgot to mention, that in order to create my CMakeLists.txt files I used these two sources:
https://root.cern.ch/how/integrate-root-my-project-cmake
https://cliutils.gitlab.io/modern-cmake/chapters/packages/ROOT.html
I have managed to compile my project.
As it turned out, .so file that contains TGeoManager implementation was not included in ROOT_LIBRARIES(thanks, Kamil Cuk for bringing my attention to this variable) by the script provided by ROOT developers. It was hard to find as this class was working properly in Cling(c++ interpreter included with ROOT) and this class is almost the only one from ROOT that I use in the project, so I assumed, that the whole ROOT library was not linking properly. After I found this issue, I fixed my CMake files like this (this is from General/CmakeLists.txt):
file(GLOB_RECURSE SOURCES2 . $ENV{ROOTSYS}/lib/*.so)
add_library(General SHARED ${SOURCES} ${SOURCES2} GeoManagerExtractor.cxx)
This eliminates all of the "undefined reference to 'gGeoManager'" and alike, but "undefined reference to `vtable for TGeoManagerExporter'" (TGeoManagerExporter is my own class) stays. However, I figured out that this error is caused by a reflection feature, so as a temporary solution I just don't activate it. I'll post a comment here if I solve this problem.

Undefined reference to (SFML)

I am trying to link SFML with CMake, but I have some issues with make:
/home/ishidex2/Documents/QtCreator/CMakeExample/main.cpp:-1: error: undefined reference to `sf::String::String(char const*, std::locale const&)'
And some kind of errors like this.
First of all, I installed SFML by this command:
sudo apt-get install libsfml-dev
And then followed this tutorial :
https://github.com/SFML/SFML/wiki/Tutorial:-Build-your-SFML-project-with-CMake
I think this is a problem with linking, but I don't know how to fix it.
My linking order is:
find_package(SFML 2 REQUIRED graphics window main system)
find_package does not perform any linking, you need to use target_link_libraries as seen in the link that you posted yourself:
target_link_libraries(${EXECUTABLE_NAME} ${SFML_LIBRARIES} ${SFML_DEPENDENCIES})

Undefined Python references in C++ using CMake

I am trying to compile a c++ project referencing Python using CMake. I am using Cygwin and I have Python2.7 source files in Cygwin.
For example:
PyObject *l = PyList_New(0);
Online help suggested I add the -lpython2.7 linker flag. Am I not adding this correctly in CMake? Otherwise why can I still not use the Python library and how might I fix this?
The compile line:
C:\cygwin64\bin\cmake.exe --build "C:\Users\...\.clion10\system\cmake\generated\3e6845d6\3e6845d6\Release" --target projectname -- -j 4
The CMakeList.txt file:
cmake_minimum_required(VERSION 2.8.4)
project(projectname)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lpython2.7")
set(SOURCE_FILES
src/cpp/...
src/cpp/...
src/cpp/..
src/cpp/...
src/cpp/...)
add_executable(projectname ${SOURCE_FILES})
The errors...
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaeb4): undefined reference to `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaeb4): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaec4): undefined reference to `PyList_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaec4): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `PyList_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaf0d): undefined reference to `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaf0d): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaf25): undefined reference to `PyString_FromString'
...and so on....
You misunderstand CMake's way: before use something you ought to find it! I.e. make sure that everything you need to build your package is available and usable at build host. Otherwise that would be not good to waste a (compile) time (say 2 hours) and then get an error that some header/library/executable not found. So, at CMake run time you'd better to be sure that everything you need is here. To do so, CMake have a lot of tools.
Consider your particular case: you need to find Python libraries otherwise build is not possible. To do so, you ought to use find_package like this:
find_package(PythonLibs REQUIRED)
Take a look to documentation and provide other options (like version) if you need. You shouldn't use hardcoded paths in your CMakeLists.txt, otherwise your project wouldn't be really portable (and most probably you'll be the only who can build it w/o a lot of problems). Instead Python libs finder module will provide variables you need to use later, or failed w/ error if nothing has found.
If CMake ends w/o errors, you may use found Python libs. First of all you need to update #include paths:
include_directories(${PYTHON_INCLUDE_DIRS})
Then tell to linker that your executable projectname needs to be linked w/ Python libs:
add_executable(projectname ${SOURCE_FILES})
target_link_libraries(projectname ${PYTHON_LIBRARIES})
And again, try to avoid to modify CMAKE_CXX_FLAGS (and others) directly -- there are bunch of calls to do that globally and/or per target. Some of them are:
add_definitions to define/undefine macros
include_directories to update #include paths
add_compile_options to add other compiler options
link_directories to update linker search paths

Using Cuda Object Linking with Cmake

Right now I am working on a project that uses the object linking capabilities of Cuda 5. Since the project is starting to get complex, I wanted to switch to using cmake to compile the code. However I can't seem to get object linking to work correctly for me.
I ended up creating a toy version of the project which gets the same kind of errors as the original project. The toy project consists of a main file (TextureMain.cu) that calls a kernel function to run on the GPU. In each GPU thread an instance of a user-defined class (TextureFunc) is referenced, where the class exists in a separate folder from the main file. The class consists of a TextureFunc.cu and TextureFunc.h file in that folder.
Here are the CMakeList.txt files I am using:
In the project directory (contains src directory):
project(TextureMain)
cmake_minimum_required(VERSION 2.8)
find_package(CUDA REQUIRED)
#-------------------------------------------------------------------------------
set(CUDA_NVCC_FLAGS "-arch=compute_20; -code=sm_20; -rdc=true; -lcudadevrt")
include_directories(src/TextureFunc)
#-------------------------------------------------------------------------------
add_subdirectory(src/TextureFunc)
add_subdirectory(src)
In the src directory (contains TextureMain.cu and TextureFunc directory):
cuda_add_executable(TextureMain TextureMain.cu)
target_link_libraries(TextureMain TextureFunc)
install(TARGETS TextureMain DESTINATION bin)
In TextureFunc directory (contains TextureFunc.h and TextureFunc.cu):
cuda_add_library(TextureFunc TextureFunc.cu )
target_link_libraries(TextureFunc)
When I try to compile this code using the above CMakeList.txt files, I get the following error.
Linking CXX executable TextureMain
CMakeFiles/TextureMain.dir/./TextureMain_generated_TextureMain.cu.o: In function `__sti____cudaRegisterAll_46_tmpxft_00004c15_00000000_6_TextureMain_cpp1_ii_texRef':
/tmp/tmpxft_00004c15_00000000-3_TextureMain.cudafe1.stub.c:2: undefined reference to `__cudaRegisterLinkedBinary_46_tmpxft_00004c15_00000000_6_TextureMain_cpp1_ii_texRef'
TextureFunc/libTextureFunc.a(TextureFunc_generated_TextureFunc.cu.o): In function `__sti____cudaRegisterAll_46_tmpxft_00004bd8_00000000_6_TextureFunc_cpp1_ii_421ca072':
/tmp/tmpxft_00004bd8_00000000-3_TextureFunc.cudafe1.stub.c:8: undefined reference to `__cudaRegisterLinkedBinary_46_tmpxft_00004bd8_00000000_6_TextureFunc_cpp1_ii_421ca072'
collect2: ld returned 1 exit status
make[2]: *** [src/TextureMain] Error 1
make[1]: *** [src/CMakeFiles/TextureMain.dir/all] Error 2
This is obviously a linking error, and it probably has to do with the way that I compile the code using cmake. I think the flags for nvcc are right since I was able to compile this project using a Makefile with the same flags. However, I'm not really sure what else I could be doing wrong. I did notice that the error message references some non-existent .cpp files, but I don't know what to do with that.
Any advice that can be given would be greatly appreciated. I'm using cmake version 2.8.8.
How about linking${CUDA_LIBRARIES} to whatever targets using `.cu files?
For example in your src directory you could try:
cuda_add_executable(TextureMain TextureMain.cu)
target_link_libraries(TextureMain TextureFunc ${CUDA_LIBRARIES})
install(TARGETS TextureMain DESTINATION bin)

error about compiling c++ code with cmake and boost

I am trying to compile c++ software depending on boost with CMake. With the same source code and CMakeLists.txt files, I succeeded with my own laptop (ubuntu 11 with boost1.42), but I am getting the following error message with my workstation (RHEL6.2 with boost 1.41) in research group (btw, boost1.41 should be enough):
main/main.cpp: In function ‘path
make_path(const std::string&)’:
main/main.cpp:50: error: invalid
conversion from ‘bool (*)(const std::string&)’ to ‘void*’
main/main.cpp:50: error:
initializing argument 2 of ‘boost::filesystem3::path::path(const Source&,
typename
boost::enable_if<boost::filesystem3::path_traits::is_pathable<typename
boost::decay<Source>::type>, void>::type*) [with Source =
std::basic_string<char, std::char_traits<char>, std::allocator<char> >]’
main/main.cpp: In function ‘int
main(int, char**)’:
main/main.cpp:664: error: ‘class
path’ has no member named ‘native_file_string’
main/main.cpp:676: error: ‘class
path’ has no member named ‘native_file_string’
make[2]: *** [main/CMakeFiles/vina_main.dir/main.cpp.o] Error 1
make[1]: *** [main/CMakeFiles/vina_main.dir/all] Error 2
make: *** [all] Error 2
I don't quite understand the error message and don't know how to fix it. Can anyone help me?
======================= update =========================
The above error message is fixed thanks to your help, but I still get the error message indicating linking failure between my executable file and boost libraries. I did link it within CMakeLists.txt by 'target_link_libraries (vvv_main vvv ${Boost_LIBRARIES})'. The error message is like:
CMakeFiles/vvv_main.dir/main.cpp.o: In function '__static_initialization_and_destruction_0':
/usr/local/include/boost/system/error_code.hpp:214: undefined reference to `boost::system::generic_category()'
/usr/local/include/boost/system/error_code.hpp:215: undefined reference to `boost::system::generic_category()'
/usr/local/include/boost/system/error_code.hpp:216: undefined reference to `boost::system::system_category()'
.......
I read other related posts here, but still have no clue how to fix my problem. Thanks!
I would suggest, that you use the find_package routines of CMake together with the required flag and explicitly specifying the components you need. Then there is no need to manually set the libraries.
For your project
FIND_PACKAGE(Boost 1.41 COMPONENTS filesystem system REQUIRED)
MESSAGE(STATUS "** Boost Include: ${Boost_INCLUDE_DIR}")
MESSAGE(STATUS "** Boost Libraries: ${Boost_LIBRARIES}")
together with
TARGET_LINK_LIBRARIES(your_project ${Boost_LIBRARIES})
should do the trick. Specifying the version (here 1.41) makes CMake if only an older version of boost is available. Specifying the components (components = boost libraries that are not header-only) makes CMake complain if those are not available and also automatically adds those to the variable Boost_LIBRARIES. The Message statements are not necessary but I like to have some feedback...
In case you would like to manually download and install the newest version of boost (which I normally do since Linux distributions tend to be somewhat slow with respect to boost packaging) alongside the version provided by the system, then you can hint the find_package scripts for boost to the custom location via
SET(BOOST_ROOT "$ENV{HOME}/usr")
which of course goes before the find_package call (in this example boost would have been installed into the prefix $HOME/usr).
One last remark - I sometimes used to have problems with older versions of the FindBoost.cmake script (especially those from the old CMake 2.6) that does all the magic when find_package(Boost) is called. It should not be a problem for Boost 1.41, but in case there are problems finding (newer versions of) Boost even though you're absolutely sure it is correctly installed, you might want to try a more recent version of FindBoost.cmake. For example from the gitweb, it should be in the Modules tree.