How can I override shared library in LD_LIBRARY_PATH with clang++? - c++

I'm trying to compile a shared library I wrote in C++ to use a specific version of another shared library in the current directory, however it seems to be ignoring that and it uses the (older and incompatible) .so file in my LD_LIBRARY_PATH at runtime. How would I go about overriding the .so file it uses to use my own? I also need to retain the older version for another use on the same system.
Here's my command I'm using to compile: clang++ /data/openpilot/selfdrive/df/libs/libSNPE.so -lsymphony-cpu -lsymphonypower -I/data/openpilot/phonelibs/snpe/include -std=c++14 -lstdc++ -fPIC -o d_f.so dynamic_follow.cc -shared
/data/openpilot/selfdrive/df/libs/libSNPE.so being the library I want to use.
I also tried to use the -l flag before my library file, however it returns cannot find -l/data/openpilot/selfdrive/df/libs/libSNPE.so
Confirmed to still use the library in LD_LIBRARY_PATH with this command as well: clang++ -Wl,-rpath,/data/openpilot/selfdrive/df/libs -L/data/openpilot/selfdrive/df/libs -lSNPE -lsymphony-cpu -lsymphonypower -I/data/openpilot/phonelibs/snpe/include -std=c++14 -stdlib=libc++ -fPIC -o d_f.so dynamic_follow.cc -shared

The -L flag tells where to look for libraries at link time, while LD_LIBRARY_PATH tells where to look for libraries at run-time. So whatever path you set at link-time, this will be ignored when running the executable.
You need to have LD_LIBRARY_PATH include the directory of your dynamic library at run-time for your executable to find it. So you may run your executable like this:
LD_LIBRARY_PATH=/data/openpilot/selfdrive/df/libs:"$LD_LIBRARY_PATH" ./your-exec

Related

How to link to shared object library in msys2?

I have some c++ code in msys2 that I am trying to link dynamically to show how a dynamic link library works.
In linux, showing the call is no problem. stepping in gdb, we can watch the call go through the jump vector, eventually landing in the desired function.
But in msys2, they wanted to eliminated dlls and all the libraries I can find are .dll.a, I think they are really static libraries.
I build a trivial little function like this:
#include <cstdint>
extern "C" {
uint64_t f(uint64_t a, uint64_t b) {
return a + b;
}
}
compiling in the makefile with:
g++ -g -fPIC -c lib1.cc
g++ -g -shared lib1.o -o libtest1.so
When I run the file utility, it says that:
libtest1.so: PE32+ executable (DLL) (console) x86-64, for MS Windows
When I compile the code using it:
g++ -g main.cc -ltest1 -o prog
The error is -ltest1 no such file or directory.
MinGW uses the .dll extension for shared libraries, not .so.
lib??.dll.a is an import library, a shim that will load the corresponding lib??.dll at runtime.
At some point in time, you couldn't link .dlls directly, and had to link .dll.as instead. The modern MinGW can link .dlls directly, so you shouldn't need to use import libraries anymore.
-ltest1 no such file or directory
Wouldn't you get the same error on Linux? You have to specify the library search path with -L. -ltest1 needs either libtest1.a or libtest1.dll.a or libtest1.dll (perhaps some other variants are checked too).
The reason your linker cannot find the library is because your current working directory is not in the search path for libraries. Add -L. to your linking command.
It is untrue that MSYS2 "wanted to eliminate DLLs". Just run ls /mingw64/bin/*.dll and you will see plenty of DLLs (assuming you have some MINGW64 packages installed). The .dll.a files used for linking are called import libraries.

C++ using functions from shared library

I have the following problem:
I have two separate c++ projects, and want to use certain functions from one of them in the other. I am compiling using g++, on Linux.
I decided to do this by creating a shared library out of the project from which to use the functions. I added -fPIC to the compiler flags in the Makefile and then created a shared library like this:
g++ -shared -Wl,-soname,libmyproject.so.1 -o libmyproject.so a.o b.o c.o -lc
Then I simply copied the .so file and the header files into the (parent) directory of the new project and added the following to its Makefile:
To LIBS:
-L/../external_proj/libmyproject.so
To CXXFLAGS:
-I/../external_proj
Then I #include the appropriate header file in the destination project code and try to call certain functions from the original project. However, when I compile the destination project I get an error "undefined reference" for the imported function.
My question is then: is there something I'm missing in this setup? Is there perhaps something that needs to be added to the headers in the original project in order to export the functions I want to use?
I should note this is the first time I have attempted to use a shared library in this way. Thanks.
The -L option only specifies the directory where the linker will search for libraries to link with. Then you will need to use the -l option to specify the base name of the shared library (without the "lib" prefix and the ".so" suffix).
But even that will unlikely to be enough. The runtime loader needs to find the shared library, when you attempt to try to execute it. -L and -l will be sufficient to successfully link, but the runtime loader only searches /usr/lib(64)?, and a few other places by default. It does NOT search the current directory, and the ELF binary only records the names of the shared libraries that must be loaded, and not their full pathnames. You have to explicitly record any extra directories to search for any shared libraries, which is the -rpath option.
To finish the job you will also need to pass -rpath to the linker, but g++ does not support this option directory, you will have to use -W to do that.
The full set of options you will likely need are:
-L/../external_proj -lmyproject -Wl,-rpath -Wl,`cd ../external_proj && pwd`
See gcc documentation for more information on the -W option.
Absolute pathnames should be used with -rpath, hence the need to obtain the full pathname to the directory where the shared library is.
The -L flag is to add a path to search libraries in. The -l (lower-case L) is for linking with a library in the search path.
Or you can skip the flags and link with the library directly, almost like you do now (but without the -L option).
If you use the -l option, then remember that for a file libname.so you use only name as the library name. As in -lname. The linker will search for the correct files with the added prefix and suffix.
And lastly an important note about the paths used when linking: If you use -L and -l to link with a shared library, it's only the linker which will find the library. The OS runtime-loader will not be able to see the path used and will not find the library, if it's in a non-standard location. For that you must also set the runtime-path using the special linker option -rpath.
Unfortunately the GCC frontend program g++ doesn't recognize that option, you have to use -Wl to tell g++ to pass on an option to the actual linker. As in -Wl,-rpath,/path/to/libraries.
To summarize, here are the different variants you can use:
Link directly with the library: g++ your_source.cpp ../external_proj/libmyproject.so
Use the -L and -l options: g++ your_source.cpp -L../external_proj -lmyproject
To set the runtime linker path: g++ your_source.cpp -L../external_proj -lmyproject -Wl,-rpath,../external_proj

Executing cross-compiled C++ program using Boost on Raspberry Pi

I have built a GCC cross toolchain for the RPi and can cross-compile C++ source and successfully run it after copying the executable to the RPi.
Next I built the Boost libraries targeting ARM, using the cross toolchain. I can successfully build and link C++ source to those Boost libraries using the cross toolchain on my PC.
I then copied the program, dynamically linked to Boost, to the RPi and copied all built libraries into /usr/local/lib on the Pi. However, executing fails:
$ ./my_program
./my_program: error while loading shared libraries: libboost_system.so.1.60.0: cannot open shared object file: No such file or directory
Again, this library, libboost_system.so.1.60.0, exists in /usr/local/lib.
I also tried
export LD_LIBRARY_PATH='/usr/local/lib'
but that doesn't change anything. What am I doing wrong?
EDIT:
I build all source files like this (rpi-g++ is a symlink to my cross-compiler):
rpi-g++ -c -std=c++1y -Wall -Wextra -pedantic -O2 -I /path/to/cross/boost/include *.cpp
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -lboost_system -pthread
EDIT 2:
When linked with
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -rdynamic -lboost_system -pthread
the problem remains the same. I have checked and verified everything suggested by Technaton as well. Strangely, ldd insists that the created executable is "not a dynamic executable" (checked that on my PC and on the RPi), which doesn't make sense to me.
There are several things you can check. I've posted a complete check list here, but judging from your linker command line, number 5 is probably the culprit.
Check that your library and your program are correctly build for the target architecture. You can verify that by using file ./myprog and file libboost_system.so.1.60.0.
Make sure that you have copied the actual shared object, and not a link to it.
Ensure that the shared object file's permissions are sane (0755).
Run ldconfig -v and check that your shared object file is picked up. Normally, /usr/local/lib is in the standard library search path, and LD_LIBRARY_PATH is not required.
Make sure that your program is actually dynamically linked by running ldd ./myprog. Judging from your linker command line, that is the problem: You're missing -rdynamic.
Check the paths returned from ldd: If you have linked with rpath, the library search path might be screwed up. Try again without -rpath.

Autotools - passing optional profiling library to configure script

I have built and installed a shared library to do some profiling of my projects via code instrumentation, specifically with the -finstrument-functions switch of gcc.
It is possible to turn the instrumentation on and off with the compiler switch, and hence I'd like to be able to turn the dependency to the profiling library on and off just by reconfiguring.
I can pass -finstrument-functions to gcc via configure's CFLAGS, but when I try to pass -lmylib via LDFLAGS configure fails with
configure:2796: checking whether we are cross compiling
configure:2804: gcc -o conftest -g -Wall -Wextra -Werror -lmylib conftest.c >&5
configure:2808: $? = 0
configure:2815: ./conftest
./conftest: error while loading shared libraries: libmylib.so.0: cannot open shared object file: No such file or directory
The file exists, I have double checked and compiling and linking a dummy example works as expected.
Interestingly, when I pass the full path to the shared library instead of -lmylib, the error persists, but when I pass the full path to the corresponding static library, configure runs smoothly, and everything is built as expected.
My question in a nutshell: Is there a possibility to pass optional shared libraries to autotools-generated configure scripts, without changing configure.ac?
Thanks,
Andy
It looks like your library is not in the compiler's default library search path.
You may also pass library search path through LDFLAGS with the -L switch:
CFLAGS=-finstrument-functions LDFLAGS="-lmylib -L/path/to/mylib" ./configure ....
fixed by running sudo ldconfig
I'll leave this here in case someone else has the same problem.

Clang linker does not look into LD_LIBRARY_PATH

I am trying to build and link a C++, cmake-based project with clang (3.0). This project links to several libraries that are installed in a custom directory /my/dir/. This directory is included in the LD_LIBRARY_PATH and LIBRARY_PATH environment variables. Project builds and links fine with g++.
The link command generated and executed by cmake looks like the following:
/usr/bin/clang++ -O3 stuff.cpp.o -o stuff -rdynamic -lmylib
ld then complains with the following message:
/usr/bin/ld: cannot find -lmylib
The link command above runs fine whenever I manually add -L/my/dir/. Is there a way to link without specifying the -L flag?
The $LD_LIBRARY_PATH environment variable (and its various alternatives on other UNIX-based platforms) is used at runtime, not link time, to find libraries.
Using -L is the correct approach and cannot be avoided.
Note: A better approach under Linux (you don't specify your platform so I'm guessing) is to correctly configure a file in /etc/ld.so.conf.d/ and avoid using $LD_LIBRARY_PATH altogether.