Telling omake to use static version of a c library - ocaml

I'm using omake to build a native binary executable. After it links and i try to run it, it fails to run giving the following error:
error while loading shared libraries: libprotobuf-c.so.1: cannot open shared object file: No such file or directory
Is there a way, at compile time, to tell the executable to pick up the static version: libprotobuf-c.a and not the shared on?

I'm not familiar with omake but I believe flag to ocamlc you are looking for is dllpath:
-dllpath dir
Adds the directory dir to the run-time search path for shared C libraries. At link-
time, shared libraries are searched in the standard search path (the one corresponding
to the -I option). The -dllpath option simply stores dir in the produced executable
file, where ocamlrun(1) can find it and use it.
If you can configure omake to pass the appropriate -dllpath argument to ocamlc, you should be good to go.
Under the hood I believe this is using the rpath feature (runtime library search path) of ld, the GNU linker. See https://linux.die.net/man/1/ld . There is also a chrpath utility to change the rpath of an already-built executable.
Another option is running your executable with LD_LIBRARY_PATH set so that the shared library is on the load path. You could also install the shared library system wide if appropriate. A final option is to load the library manually when your application boots using dlopen.
The correct choice depends on how you will distribute this and to who you will distribute this, if at all. Keep in mind if you use rpath/dllpath the end user is unlikely to have protobuf installed in the same location you do.

There doesn't seem to be a global flag that can be passed to ld, the linker, that enforces the linker prefer static libraries to dynamic ones when available. In my case, I set the library name explicitly like so:
OCAML_LINK_FLAGS += -cclib -l:libprotobuf-c.a

Related

linux how to specify dynamic library when there're multiple

I'm developing a shared library, and on my machine there could be two copies of the same shared library:
the one I installed to the system path: /usr/lib/libmyproject.so
the one I built in my workspace during my development: /home/ziqi.liu/workspace/myproject/build/src/libmyproject.so
So during my development, there're some executables under /home/ziqi.liu/workspace/myproject/build. I want them to use the dynamic library in /home/ziqi.liu/workspace/myproject/build/src/libmyproject.so, however it turns out that they're actually using /usr/lib/libmyproject.so when I use ldd to check the link library.
Is there anyway to specify which dynamic library to use when there are multiple? It would be better if I can specify this for all executables under "this project", since it's very intuitive to link the dynamic library in the same repo I just built, instead of the one installed to the system path.
UPDATED:
I've found this post: Where do executables look for shared objects at runtime?
It seems that the dynamic library searching has something to do with
the rpath and LD_LIBRARY_PATH environment variables.
What I want is to search for rpath first, and then LD_LIBRARY_PATH.
According to rpath wiki, the rpath is named DT_RPATH, however when I objdump that executable, the only thing I can find is RUNPATH section. I'm not sure if this is a compiler-specific behavior... (I'm running g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0)
Is there anyway to specify which dynamic library to use when there are multiple?
The best way to achieve this is to use the special $ORIGIN tag in the executable.
Assuming you have $D/build/exe and you want that exe to use $D/build/src/libmyproject.so, link your exe with: -rpath '$ORIGIN/src'.
This would allow you to have several build directories (e.g. "release" and "debug" builds), and each binary will pick up the library from its own build tree.
It would also allow you to not install libmyproject.so into /usr/lib at all -- you can keep the binary and the all the required libraries in e.g. /usr/local/$project/{bin/exe,lib/libmyproject.so} and have it all just work(TM).
See also this answer.
Just modify LD_LIBRARY_PATH and put your home folder first, like
export LD_LIBRARY_PATH=/home/ziqi.liu/workspace/myproject/build/src/:${LD_LIBRARY_PATH}
Then it should be fine.

How to let Cmake Install to link my executables to my target shared libraries [duplicate]

I have a question related to how to install a built executable program with cmake when it relies on some external libraries. Suppose my executable is abc, and it relies on two external libraries: lib1.so and lib2.so. The structure of the codes are as follows:
-.........
|----bin (lib1.so lib2.so)
|----include(lib1.h lib2.h)
|----src(main.cpp)
When the executable program is installed using the following cmake commands:
INSTALL(TARGETS ${Exe_Name}
RUNTIME DESTINATION Path to bin
LIBRARY DESTINATION Path to bin)
I expect that the executable program will be in the same directory with lib1.so and lib2.so. However, when I execute the built program in the installation folder, I met the following error:
error while loading shared libraries: lib1 can not open shared object file No such file or directory
If I use ldd to check the executable, I found lib1.so and lib2.so not found. After searching for possible solutions, I found if I call the executable in this way, then it worked:
LD_LIBRARY_PATH=./ ./my_program_run
Then my question is how I can let my executable program knows the locations of the shared libraries with cmake when it is installed? Thanks.
This is best solved this with the RPATH of the final executable. RPATH is a hardcoded search path for the executable itself, and allows the use of the string $ORIGIN, which expands to the location of the executable at runtime. See this reference: http://man7.org/linux/man-pages/man8/ld.so.8.html
CMake strips the rpath of a binary at installation time, to avoid the binary picking up libraries littered around your development tree. But it also provides a simple way to modify the installation rpath for exactly this reason. Here's the short answer:
IF(UNIX)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/../bin:\$ORIGIN")
ENDIF()
This particular example appends to the existing rpath, and adds . and ../bin to the search path, all relative to the location of the binary.
Some developers claim that adjusting the RPATH of the binary is not a good idea. In the ideal world, all the libraries would live in the system library directories. But if you take this to the extreme, you end up with Windows (at least the older ones), where c:\windows\system32 is full of junk that came from who knows where, and may or may not conflict with other software, etc. Using rpath and installing everything in one place seems like a great solution.
If the application is to be cleanly installed to a standard linux distribution, then you should either install the supporting shared libraries into a standard location (/usr/lib), or you should add the libraries location to the ld.so config, by create an /etc/ld.so.conf.d/myprogram.conf file containing the name of the directory the libraries are in.
If the installation is temporary or more ad-hoc, then a script to set the LD_LIBRARY_PATH is suitable.
The libraries are searched in the predefined locations which includes standard library paths configured with ld.so.conf and LD_LIBRARY_PATH. You can also try to compile your app with -rpath, but it is not recommended by some developers. I suggest you to create a wrapper script which will set LD_LIBRARY_PATH and run the real application like that:
"theapp" script:
#!/bin/sh
dir="`dirname \"$0\"`"
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}"$dir"
exec "$dir/theapp.real" # your real application
The application, script and libraries should be in the same location (under bin/).

Linux executable can't find shared library in same folder

I am relatively new to Linux development, having been using Windows for a while now. Anyway, I am compiling a C++ game using g++ on both Windows and Linux (using mingw32 when needed), and am linking against SDL2 and SDL2_mixer. On Windows, one would only need to put the DLL files in the same folder as the executable and everything would run fine. On Linux however, although the code compiled just fine with not even a single warning, I get this at runtime :
./nKaruga: error while loading shared libraries: libSDL2_mixer-2.0.so.0: cannot open shared object file: No such file or directory
although said shared lib is in the same folder. I looked up several similar cases on Stack Overflow, all of them involving the use of LD_LIBRARY_PATH, and tried it but to no avail.
% LD_LIBRARY_PATH=pwd
% export LD_LIBRARY_PATH
% ./nKaruga
./nKaruga: error while loading shared libraries: libSDL2_mixer-2.0.so.0: cannot open shared object file: No such file or directory
I want to distribute this program on systems that do not necessarily have admin rights to install dependencies, hence why I am putting the SO in the same folder as the executable.
Thanks by advance !
LD_LIBRARY_PATH is a quick ad-hoc hack to specify alternate library loading search paths. A more permanent and cleaner solution is to specify the specific sets of paths in which libraries shall be searched specific for your particular binary. This is called the rpath (Wikipedia article on it: https://en.wikipedia.org/wiki/Rpath). There are a number of "variables" that can be specified in the binary rpath that get substituted. In your case the rpath variable ${ORIGIN} would be the most interesting for you. ${ORIGIN} tells the dynamic linker to look for libraries within the very same directory in which also the binary resides.
The rpath can be set at link time with the -rpath linker option, i.e. when invoked through GCC the option would be -Wl,-rpath='${ORIGIN}', i.e.
gcc -o program_binary -Wl,-rpath='${ORIGIN}' -lSDL2_mixer a.o b.o …
For an existing binary the rpath can be set post-hoc using the chrpath or patchelf tools; it's better to set it at link time proper, though.

Compiling with c++ and getting "ready to go" executable

Is it possible to compile a program with g++ so that shared libraries etc are "included" with the executable?
I have a c++ program that I'd like to compile and run at another location where I'm missing some libraries and don't have install access.
The main reason I couldn't find answers for this is probably that I don't know how to call it..
No, it's not possible.
Either link statically (with -static) so it doesn't use any shared libraries, or copy the shared libraries to the other location along with the executable.
Since the shared libraries will not be in the dynamic loader's usual search paths you'll need to ensure they can be found, either by setting the LD_LIBRARY_PATH environment variable when running the program, or by setting an RPATH in the executable when you build it.
(Assuming you're using the GNU linker ...) To set an RPATH in the executable link with '-Wl,-rpath,$ORIGIN' (the quotes are important, to stop $ORIGIN being expanded by the shell). That means the loader will look for shared libraries in the same directory as the executable itself.
See https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.how_to_set_paths and https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dynamic_or_shared.html#manual.intro.using.linkage.dynamic for more information.

C++ shared libraries

I am trying to get my head around the way shared libraries work in the c++ unix environment. I understand we only need header files and no shared libraries specification when compiling code. But if I want to create an executable or shared library from my compiled files, do I need to specify shared library dependencies (those are dynamic)? And do the paths of shared libraries need to match the path at runtime loading?
I am using Linux 2.6.18-164.11.1.el5 #1 SMP x86_64 GNU/Linux
I am having a problem where my code is not able to pick up a library at runtime. I have tried setting LD_LIBRARY_PATH and PATH. But at runtime when I run the executable, I get the following error:
Error: librc.so: cannot open shared object file: No such file or directory
Sam
The headers are only for the compile phase. At link time, you usually have to specify which shared libs you are going to link to. You might see -L options to set locations to where shared libraries reside, and/or -l to specify which libraries to link. There is usually also a switch on the command line to alert the linker as to whether you are using thread-safe versions of the libs or the 'regular' ones, and another switch to specify dynamic linking.
At run time, whether you are starting the program that uses the libs, or running ldd to find out what it needs, the OS has a system for locating .so files, and this can vary from one unix version to another. The LD_LIBRARY_PATH variable specifies where to look for .so files, but may not be the full story, depending on the exact unix version in question. Also, you probably don't want to fiddle around with modifying LD_LIBRARY_PATH except from a throw-away shell, since it has system wide effects. A better option is to check it the 'missing' .so files are or are not on the existing path set by LD_LIBRARY_PATH, and if not, try putting copies of them somewhere on that path.
At run time, dynamic libraries are searched:
in a path recorded in the executable (under linux with -rpath at link time, under Solaris with -R, using $ORIGIN in a directory name allows to specify a directory relative to the directory containing the executable)
in the LD_LIBRARY_PATH (or equivalent, there are sometimes 64/32 bits variant). If a path has been recorded in the executable, LD_LIBRARY_PATH may not searched (under Linux it is searched after the recorded path if the executable has been linked with the option --enable-new-dtags; I don't remember Solaris behavior for now)
in a set of system dependant directories (Linux allows to specify them in /etc/ld.so.conf and has a cache, see ldconfig)