Dynamic library in Linux - linux

When we creating a binary using the Dynamic library we apply gcc -o binary main.o -L. -lmylib -Wl,-rpath,. where -L. indicate that linker must search library in current directory. Why without -Wl,-rpath,. we can't use the dynamic library?

There are several directories in the system where ld.so looks for libraries. If your library is not in a directory from that list, you have two alternatives:
Specify path to it in the LD_LIBRARY_PATH variable;
Write path to it in the rpath of the binary.
You can change/view rpath of the binary using chrpath.
Difference betwee -rpath and -L:
-rpath=dir
Add a directory to the runtime library search path. This is used
when linking an ELF executable with shared objects. All -rpath
arguments are concatenated and passed to the runtime linker, which
uses them to locate shared objects at runtime.
vs.
-L searchdir
--library-path=searchdir
Add path searchdir to the list of paths that ld will search for
archive libraries and ld control scripts.
( What's the difference between -rpath and -L? )

By default, ld.so searches in the directories specified by LD_LIBRARY_PATH. If your shared lib isn't in one of those, it won't be found.
The -rpath option to ld causes it to store a pathname in the executable that ld.so will look in.

Related

How to deploy a shared library?

I would like to "quickly" deploy a shared library on my Ubuntu. It is for a short term project so I don't want to use auto-tools here, but do everything manually.
So I built my library with this:
%.o: %.c
$(CC) -fPIC -c $(CFLAGS) -o $# $< -MMD -MF $(#:.o=.d)
lib%.so: %.o | dist
$(CC) -shared -o dist/$# $^
dist:
mkdir -p dist
install: lib
mkdir -p $(PREFIX)/lib/foobar
mkdir -p $(PREFIX)/include/foobar
cp dist/*.so $(PREFIX)/lib/foobar
cp dist/*.h $(PREFIX)/include/foobar
ldconfig $(PREFIX)/lib/foobar/
In another project, I would like to use libfoo.so now located in /usr/lib/foobar/libfoo.so. So I've built it with:
$(CC) test.c -lfoo
Unfortunately I have this issue:
/usr/bin/ld: cannot find -lfoo
I now that I can do -L/usr/lib/foobar/libfoo.so but this location should be known by my operating system.
Am I forced to put it directly into /usr/lib? I have the same issue with /usr/local/lib which doesn't seem to be the default route to be used with gcc ... -l...
How should I normally deploy a shared library?
The list of directories from ld.so.conf has system-wide impact; the runtime linker will search those dirs when starting any dynamic binary. Unless you actually want additional system-wide overhead, it's more efficient to privately search another dir on a custom / as-needed basis. Private-search is ideally suited for cases of 1-off or single-use or rarely-used custom libs.
For the 1 or few bins that reference those libs, bins can be rebuilt with a directive for the runtime linker to privately search 1+ custom dirs; eg:
gcc -L/usr/local/lib64 -Wl,-rpath=/usr/local/lib64 -lblah
For more details, see gcc and ld manual pages for the respective options -Wl, and -rpath.
To make a directory known to the dynamic linker (ld.so) so that it can be found at run-time without depending on LD_LIBRARY_PATH:
list it in /etc/ld.so.conf (or in an include file under /etc/ld.so.conf.d, if the main /etc/ld.so.conf file has an appropriate include statement to enable this)
then run /sbin/ldconfig
As regards the build-time linker (ld), it is normal to expect to have to specify the library location explicitly using the -L flag on the compiler, normally with the directory as argument e.g. -L/usr/lib/foobar. However, according to the manual page for the compile-time linker, ld, the search path for libraries does contain (after everything else) the directories referenced by /etc/ld.so.conf. So although ld.so.conf is primarily intended for use with the run-time linker as the name suggests, the build-time linker will in fact find your library once you have listed the directory there.

Name of dynamic linker on Linux

On Arch-Linux when linking an object file with ld to a dynamically linked ELF executable, it uses /lib/ld64.so.1 as the default dynamic linker. However, my dynamic linker is /lib/ld-2.26.so from Glibc.
I know, that I can specify the dynamic linker to ld with the --dynamic-linker option, but how can I ensure, that when compiling for other Linux distributions, the correct dynamic linker is found. In other words: how can I find the correct name of the dynamic linker on Linux?
Link with gcc -nostartfiles or gcc -nostdlib instead of using ld directly.
(With -no-pie or -pie if you want to make that choice explicit).
The system gcc knows the right path for the ELF interpreter.
Or to find out what the right path is, file /bin/ls and parse the output. On my Arch Linux system, it includes ... dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
Other programs include readelf -p /bin/ls, and ldd /bin/ls also includes the right path.
(But note that ldd includes the right path even if you use it on an ELF executable that has the wrong path; /bin/ldd is a shell script that works by running the ELF interpreter on an executable with special args, so the shell script contains paths to try, and the runtime dynamic linker doesn't look for itself because it's already running. You can use file or readelf -a to inspect executables to check for the right path, but not ldd.)

how to tell "gmake" to use another version of GCC? (Linux)

I have the usual gcc on my machine (at /usr/bin/gcc), and another one (newer) is linked when I setup the environment for a certain framework which I'm working on.
And I would like to compile with the old one I have on /usr/bin/gcc, instead of using the newer one.
I have to use "gmake" command for the compilation (custom compilation setup).
Without changing the PATH, how could I "tell" gmake to use a different gcc?
from command line:
gmake CC=/usr/bin/gcc
Use
make CC=/opt/bin/my-gcc
And make sure that for compilation you use $(CC) instead of direct gcc:
foo.o: foo.c
$(CC) -c foo.c -o foo.o
If you use default compilation patters the gmake uses CC variable by default
In your makefile, define a variable for your preferred compiler.
CC=/usr/bin/gcc
And after your target, use the variable.
a.o : a.c
$(CC) ...

How to translate the -lXi flag in a linux linker to the appropriate lib?

How does one find out what is the lib that the above flag is referring to?
How would I do it for some other one?
The -l option takes the name of the library as the argument so in this case the library would be named libXi.a (or libXi.so or something similar). To find the library look in the standard library locations (/usr/lib, /lib, /usr/local/lib, etc.) available in your distribution. There may also be additional library directories specified using the -L option to the linker.
If your program compiled successfully, or if you have another program which uses -lXi, then you can do:
ldd /path/to/that/program | grep libXi
For example:
$ ldd /usr/X11R6/bin/audacity | grep libXi
libXinerama.so.1 => /usr/lib/libXinerama.so.1 (0x00007f53faaba000)
libXi.so.6 => /usr/lib/libXi.so.6 (0x00007f53f8e2c000)
And that will most likely tell you where that library is. (It's not 100% because the build process could alter the search path but that's usually not likely for standard libraries like X11.)
From there, you can ask your distro which package has that file, if you care. For example on Ubuntu or a .deb-base distro:
$ dpkg --search /usr/lib/libXi.so.6
libxi6: /usr/lib/libXi.so.6
If you can't use LDD, then check your system's /etc/ld.so.conf which will indicate the search path for runtime shared library linking. (/lib/ and /usr/lib are included by default.)
Worst case, you could just find for it:
find / -regex '.*libXi\.\(a\|so\).*' 2> /dev/null
strace -f -e open gcc ... -lXi
Look for libXi in the output.

What is the difference between -I and -L in makefile?

What is the usage of the -I and -L flags in a makefile?
These are typically part of the linker command line, and are either supplied directly in a target action, or more commonly assigned to a make variable that will be expanded to form link command. In that case:
-L is the path to the directories containing the libraries. A search path for libraries.
-l is the name of the library you want to link to.
For instance, if you want to link to the library ~/libs/libabc.a you'd add:
-L$(HOME)/libs -labc
To take advantage of the default implicit rule for linking, add these flags to the variable LDFLAGS, as in
LDFLAGS+=-L$(HOME)/libs -labc
It's a good habit to separate LDFLAGS and LIBS, for example
# LDFLAGS contains flags passed to the compiler for use during linking
LDFLAGS = -Wl,--hash-style=both
# LIBS contains libraries to link with
LIBS = -L$(HOME)/libs -labc
program: a.o b.o c.o
$(CC) $(LDFLAGS) $^ $(LIBS) -o $#
# or if you really want to call ld directly,
# $(LD) $(LDFLAGS:-Wl,%=%) $^ $(LIBS) -o $#
Even if it may work otherwise, the -l... directives are supposed to go after the objects that reference those symbols. Some optimizations (-Wl,--as-needed is the most obvious) will fail if linking is done in the wrong order.
To really grok a makefile, you need to also have a good understanding of the command lines for all of the components of your project's toolchain. Options like -I and -L are not understood by make itself. Rather, make is attempting to create a command line that will execute a tool to transform a prerequisite file into a target file.
Often, that is a C or C++ source file being compiled to an object file, and eventually linked to get an executable file.
In that case, you need to see the manual for your compiler, and especially the bits related to the command line options it understands.
All that said in generic terms, those specific options are pretty standard among compilers and linkers. -I adds a directory to the list of places searched by the compiler for a file named on a #include line, and -L adds a directory to the list of places searched by the linker for a library named with the -l option.
The bottom line is that the "language" of a makefile is a combination of the syntax of the makefile itself, your shell as known to make (usually /bin/sh or something similar), common shell commands (such as rm, cp, install, etc.), and the commands specific to your compiler and linker (e.g. typing gcc -v --help at your shell prompt will give you a nearly complete (and extremely long) list of the options understood by gcc as one starting point).
One thing to note is that these are the options passed to the compiler/linker.
So you should be looking at the compiler man pages/documentation to know their role.

Resources