Integrating shared object in an application, ldd and readelf show different outputs - c++

I am trying to integrate OpenCV into an application and facing some issues below.
error while loading shared libraries: libopencv_imgproc.so.4.1: cannot open shared object file: No such file or directory
However, when I check the output of ldd and readelf, below are the differences.
$readelf -d <app name>
0x0000000000000001 (NEEDED) Shared library: [libopencv_imgcodecs.so.4.1]
0x0000000000000001 (NEEDED) Shared library: [libopencv_core.so.4.1]
$ldd <app name>
libopencv_imgcodecs.so.4.1 => <path to opencv>/opencv/lib/libopencv_imgcodecs.so.4.1 (0x00007f04555b2000)
libopencv_imgproc.so.4.1 => <path to opencv>/opencv/lib/libopencv_imgproc.so.4.1 (0x00007f0453e8f000)
libopencv_core.so.4.1 => <path to opencv>/opencv/lib/libopencv_core.so.4.1 (0x00007f0452774000)
As shown above, libopencv_imgproc is missing from readelf output. Can someone point out what causes such behavior?

Related

Integrate OpenCV using cmake - cannot open shared object file

I am trying to integrate OpenCV (v4.1.2) into an existing project and I made below changes for that:
CMakeLists.txt
find_package(OpenCV REQUIRED core imgcodecs imgproc PATHS <path to all opencv shared object files>)
target_link_libraries(<exec name> ${OpenCV_LIBS})
Also added below to the config file:
#cmakedefine HAVE_LIBOPENCV 1
#cmakedefine HAVE_OPENCV_H 1
Copy the output executable at:
/usr/bin
Run the below command to set rpath:
patchelf --set-rpath path-to-opencv/opencv/lib:$ORIGIN /usr/bin/executablename
Below are the changes I added in the source code:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
cv::Mat img = cv::imread("sample.jpg", ZM_MAX_IMAGE_COLOURS);
cv::imwrite("sample-opencv.jpg", img);
However, when I run the the code, I see below message in logs:
error while loading shared libraries: libopencv_imgproc.so.4.1: cannot open shared object file: No such file or directory
Below are some sanity checks I performed on the executable file:
$readelf -d <executable name>
0x0000000000000001 (NEEDED) Shared library: [libopencv_imgcodecs.so.4.1]
0x0000000000000001 (NEEDED) Shared library: [libopencv_core.so.4.1]
0x000000000000001d (RUNPATH) Library runpath: [<path to opencv>/opencv/lib:]
$ ldd <executable name>
libopencv_imgcodecs.so.4.1 => <path to opencv>/opencv/lib/libopencv_imgcodecs.so.4.1 (0x00007f49cf6f9000)
libopencv_core.so.4.1 => <path to opencv>/opencv/lib/libopencv_core.so.4.1 (0x00007f49ce4fc000)
libopencv_imgproc.so.4.1 => <path to opencv>/opencv/lib/libopencv_imgproc.so.4.1 (0x00007f49c3b12000)
Even though there is a valid link in ldd output, libopencv_imgproc.so doesn't exist in readelf output. My assumption is that since there is no source code directly consuming imgproc, it doesn't show up in readelf output.
Can someone point out what is causing the "cannot open shared object file" error?
EDIT:
I changed my above code to include imgproc header and declare a class below as shown below:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
cv::Subdiv2D div; // comes from imgproc
cv::Mat img = cv::imread("sample.jpg", ZM_MAX_IMAGE_COLOURS);
cv::imwrite("sample-opencv.jpg", img);
It worked after this change. Also, below is the new readelf output:
$ readelf -d <executable name>
0x0000000000000001 (NEEDED) Shared library: [libopencv_imgcodecs.so.4.1]
0x0000000000000001 (NEEDED) Shared library: [libopencv_imgproc.so.4.1]
0x0000000000000001 (NEEDED) Shared library: [libopencv_core.so.4.1]
0x000000000000001d (RUNPATH) Library runpath: [<path to opencv>/opencv/lib:]
However, it is just a workaround. One shouldn't need to write a placeholder code like this. Can someone help figure out a clean solution to include shared objects correctly?
FYI - Here are the internal dependecies between these opencv shared objects:
libopencv_core --> no dependency
libopencv_imgproc --> libopencv_core
libopencv_imcodecs --> libopencv_core and libopencv_imgproc

Linking shared library dependency not being listing in ldd

There is library which is compiled against -lyaml. But libyaml.so is not getting listed as dependency by ldd. Build is happening successfully using autoconf tool chain.
$ nm libxxxx.so | grep -i yaml
U yaml_document_delete
U yaml_document_get_node
U yaml_parser_delete
U yaml_parser_initialize
U yaml_parser_load
U yaml_parser_set_input_file
$ readelf -d libxxxx.so
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libxxxx.so.0]
There is another shared library which depends depend upon libxxxx.so.
$ ldd lib/libxxxx1.so
libzmq.so.5 => /usr/lib/x86_64-linux-gnu/libzmq.so.5 (0x00007fd45e072000)
libxmaapi.so.0 =>
When I am linking my executable with libxxxx1.so, it is giving undefined symbols error. The question is how do I link against library not found in dependency tree?
This question provides approaches to ignore the problem.
Linking with dynamic library with dependencies
The one approach which I found is disabling optimization using the gcc flag -Wl,--no-as-needed. Since I am already linking using -lyaml, symbols are getting resolved. It works but not efficient.

clang, linux, is there an option to change shared library name at linking?

I'm testing a somewhat non-conventional project layout and rake as make utility. There is a rule to compile binaries from source files in different directories and link them with a shared library. This rule is run from the root directory of the project. For instance the rule does this:
clang -I libs/ -o tests/sourcefile2 tests/sourcefile2.c shared_libs/libFoo.so
And as a result I get the full path shared_libs/libFoo.so in the binary:
readelf -d tests/sourcefile2
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [shared_libs/libFoo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
...
I would like to change it to just 'libFoo.so' like this:
readelf -d tests/sourcefile2
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libFoo.so]
...
Then I could set RPATH for dynamic linker as I want and it would give some flexibility. But I cannot find the corresponding option or similar example. Could you suggest how to handle this? Should I just use a temporary directory for the build, copy everything and compile there?
Not sure if it will help you. But when I try compile some shit and I don't know what flags. I use pkg-config.
For example, to compile a program which uses Xlib
pkg-config -cflags -libs x11
and the output is the following
-I/usr/X11R7/include -D_REENTRANT -Wl,-rpath,/usr/X11R7/lib -L/usr/X11R7/lib -lX11
Note this vary on systems, for example NetBSD forces me to link it with rpath, and there are optional arguments in this output.
So I copy the output of pkg-config and it compiles.
if If you use 'ld' as your linker you should be able to use "-Wl,-soname ".

FMOD Debian libfmod.so.8: cannot open shared object file: No such file or directory

I'm trying to install and validate fmod on my raspberry pi 1 model b with debian by running the provided example program play_stream. The compilation works fine however when I try to run the built executable it fails with the error
error while loading shared libraries: libfmod.so.8: cannot open shared object file: No such file or directory
I'm unsure of what i'm doing wrong. Any help or advice you can provide would be great
My set up:
~/fmodstudioapi10813linux/api/lowlevel/examples/make $ make --file play_stream.makefile CONFIG=Debug CPU=arm
~/fmodstudioapi10813linux/api/lowlevel/examples/make $ ./play_stream
./play_stream: error while loading shared libraries: libfmodL.so.8: cannot open shared object file: No such file or directory
~/fmodstudioapi10813linux/api/lowlevel/lib/arm $ ls /usr/local/lib/
libfmodL.so libfmodL.so.8 libfmodL.so.8.13 libfmod.so libfmod.so.8 libfmod.so.8.13
~ $ ls /usr/local/include/
fmod_codec.h fmod_common.h fmod_dsp_effects.h fmod_dsp.h fmod_errors.h fmod.h fmod.hpp fmod_output.h node
~ $ env | grep '^LD_LIBRARY_PATH'
LD_LIBRARY_PATH=:/usr/local/lib:/home/pi/fmodstudioapi10813linux/api/lowlevel/lib/arm
~/fmodstudioapi10813linux/api/lowlevel/examples/make $ ldd play_stream
/usr/lib/arm-linux-gnueabihf/libarmmem.so (0xb6faf000)
libfmod.so.8 => not found
libstdc++.so.6 => /usr/lib/arm-linux-gnueabihf/libstdc++.so.6 (0xb6ec0000)
libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6e45000)
libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6e18000)
libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6df0000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6caf000)
/lib/ld-linux-armhf.so.3 (0x7f56d000)
~/fmodstudioapi10813linux/api/lowlevel/examples/make $ echo $LD_LIBRARY_PATH
:/usr/local/lib:/home/pi/fmodstudioapi10813linux/api/lowlevel/lib/arm
**~/fmodstudioapi10813linux/api/lowlevel/examples/make $** readelf -d play_stream
Dynamic section at offset 0x420c contains 30 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libfmod.so.8]
0x00000001 (NEEDED) Shared library: [libstdc++.so.6]
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libpthread.so.0]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000f (RPATH) Library rpath: [$ORIGIN/../../../lowlevel/lib/arm/]
Run ldd play_stream and echo $LD_LIBRARY_PATH.

Valid ARM executable doesn't find libraries

I cross-compiled a small Hello World program for an ARM embedded device (an Asus RT-AC68U router running DD-WRT):
# arm-linux-gnueabi-g++ hello.cpp -mcpu=cortex-a9 -s -o hello
The file seems fine:
# file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.32,
BuildID[sha1]=5099693c31154cdd7f04c16ced5b80b1e35e625b, stripped
It depends on a few libraries:
# readelf -d hello
Dynamic section at offset 0xf08 contains 26 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libstdc++.so.6]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.6]
(...)
When I try to execute the file on the target system, I get the following:
# ./hello
-sh: ./hello: not found
If I launch execution from ld-linux.so.3 without any other parameters, everything works:
# /opt/lib/ld-linux.so.3 ./hello
Hello, world.
When listing the libraries, the file seems to be searching for libraries in the /lib folder (they are not there, they are in /opt/lib):
# /opt/lib/ld-linux.so.3 --list ./hello
libstdc++.so.6 => /lib/libstdc++.so.6 (0x76dfb000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x76de0000)
libc.so.6 => /opt/lib/libc.so.6 (0x76cb2000)
libc.so => /lib/libc.so (0x76c35000)
/lib/ld-linux.so.3 => /opt/lib/ld-linux.so.3 (0x76f20000)
I'm guessing the error is due to the fact that the executable when launched on its own is not finding the required shared libraries. All the required libraries are present in the /opt/lib folder and this folder is included in LD_LIBRARY_PATH environment variable:
# echo $LD_LIBRARY_PATH
/lib:/usr/lib:/jffs/lib:/jffs/usr/lib:/jffs/usr/local/lib
:/mmc/lib:/mmc/usr/lib:/opt/lib:/opt/usr/lib
How do I get the executable to find the libraries in the right place?
Edit: I tried linking the libraries statically in the executable and the program runs fine on the target platform. However that is not a workable solution for what I want to do.
Your ld-linux.so.3 appears to be in a nonstandard location (/opt/lib), and it's possible that your gcc is specifying a different program interpreter. You can use readelf -l <program> to check what program interpreter your binary is expecting (under PT_INTERP, "Requesting program interpreter").
If the binary's program interpreter is wrong for your platform, you can specify it manually by passing -Wl,--dynamic-linker=/opt/lib/ld-linux.so.3 to gcc.