0

First of all, let me say that I have read quite a few questions and answers about this problem on Stackoverflow, most of them with the conclusion that it is a linking ordering problem. Nevertheless, I couldn't solve the issue so far.

My goal is to build a shared library (libdetector.so) that uses external libraries (OpenCV and others but for now let's assume it's just OpenCV) and I'd like to embed them into libdetector.so so that users just have to install libdetector.so and are good to go.

Let's say the source code for libdetector.so is detector.cc and looks like this (it doesn't do anything useful yet but it's good enough to illustrate the problem)

#include "detector.hh"
#include <string>
#include <vector>
#include "opencv2/opencv.hpp"
#include "opencv2/videoio.hpp"

namespace detector {

Detector::Detector(const std::string& filepath) : filepath(filepath) {}

std::vector<float> Detector::detect(float similarityThreshold) {
  cv::Mat new_img = cv::Mat::zeros(1, 49, CV_64FC1);
  std::vector<float> vec{1.0, 1.0, 1.0};
  return vec;
}

}  // namespace detector

detector.hh looks like this

#ifndef DETECTOR_H
#define DETECTOR_H

#include <string>
#include <vector>
#include "opencv2/opencv.hpp"
#include "opencv2/videoio.hpp"

namespace detector {
class Detector {
 private:
  std::string filepath;

 public:
  Detector(const std::string &filepath);
  std::vector<float> detect(float similarityThreshold = 0.7);
};
}  // namespace detector

#endif

I have compiled OpenCV with the cmake flag -DBUILD_SHARED_LIBS:BOOL=OFF and I got several OpenCV *.a libraries in the build/ directory. Afterwards I build libdetector.so like so:

g++ -Wall -fPIC -shared -o libdetector.so detector.cc opencv/build/lib/*.a

This doesn't return any errors and outputs libdetector.so - so far so good.

Next step is some sample code that should make use of libdetector.so, let's call it detector_use.cc:

#include <iostream>
#include <string>
#include <vector>

#include "detector.hh"

int main() {
  detector::Detector d("test/path");
  std::vector<float> vec = d.detect(0.1);
  for (auto el : vec) {
    std::cout << el << std::endl;
  }
  return 0;
}

My wish would be that users should be able to simply compile this with

g++ -o detector_use detector_use.cc ./libdetector.so

But this outputs

/tmp/ccseI2o0.o: In function `cv::String::~String()':
detector_use.cc:(.text._ZN2cv6StringD2Ev[_ZN2cv6StringD5Ev]+0x14): undefined reference to `cv::String::deallocate()'
/tmp/ccseI2o0.o: In function `cv::String::operator=(cv::String const&)':
detector_use.cc:(.text._ZN2cv6StringaSERKS0_[_ZN2cv6StringaSERKS0_]+0x28): undefined reference to `cv::String::deallocate()'
./libdetector.so: undefined reference to `ippicvsMaxEvery_32f'
./libdetector.so: undefined reference to `__itt_api_version_ptr__3_0'
./libdetector.so: undefined reference to `__itt_id_create_ptr__3_0'
./libdetector.so: undefined reference to `ippicviNormRel_L1_16u_C1R'
[...]

If I understand this correctly the linker complains that a reference in libdetector.so to ippicvsMaxEvery_32f among others can't be found. To dig into this deeper I ran

me@VI:~/C-Linux$ nm -gD libdetector.so | grep ippicvsMaxEvery_32f
    U ippicvsMaxEvery_32f

Doesn't this prove that the symbol is in there?

If I simply link against the shared OpenCV libraries I have also installed on my machine like so

g++ -g detector_use.cc detector.cc -I. -lopencv_core -lopencv_videoio -lopencv_high
gui -o detector_use

everything works as expected. But why does it fail if I go the way over my libdetector.so library?

Christian Vorhemus
  • 2,396
  • 1
  • 17
  • 29
  • 1
    You may need to add the dependency mentioned in the error namely ittnotify and ippicv. Something like -littnotify. – Knight Forked Mar 28 '21 at 06:15
  • 1
    `U` in nm output stands for `undefined`, the symbol is declared in your library but not defined. Try building your library with `-Wl,--no-undefined` to detect these problems earlier (that not being on by default when building a shared library is one of the more annoying features of gcc) – Alan Birtles Mar 28 '21 at 07:27
  • I'm guessing your issue is that you're linking the opencv libraries in whatever order they've returned by the glob, you need to link them in the correct order with libraries that depend on other libraries posted before their dependencies. See https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix/24675715#24675715 – Alan Birtles Mar 28 '21 at 07:32
  • Thank you for all your responses, they helped me to figure out what's missing. Unfortunately I can't answer to my post but here is a summary: First, I ran `for lib in $(find opencv/build/ -name \*.a) ; do echo $lib ; nm $lib | grep ippicvsMaxEvery_32f | grep -v " U " ; done` to figure out where the symbol ippicvsMaxEvery_32f is actually defined and noticed OpenCV comes with a 3rdparty/ folder in which - among others - libippicv.a is placed which contains that symbol. I added this and other libraries and now it works! – Christian Vorhemus Mar 29 '21 at 08:26

0 Answers0