I have Qt[4|5]
project with QMake
build configuration and several library dependencies:
OpenCV
library installed by zypper
libnf_cln.so
library installed in /some/path
I created /etc/ld.so.conf.d/nf_cln.conf
with /some/path
as a content.
I run sudo ldconfig
.
Project succeed to build with follow code:
LIBS += -L/some/path
LIBS += -lopencv_core -lnf_cln
It fails if I remove follow line:
LIBS += -L/some/path
Why it is necessary to point location for nf_cln
and isn't necessary to point it for opencv_core
?
Why it is necessary to point location for nf_cln and isn't necessary to point it for opencv_core
Because libopencv_core
is installed in one of the static linker's default search directories
and the custom shared library libnf_cln
is not: it's in /some/path
.
The ldconfig
cache, controlled through the files in /etc/ld.so.conf.d/
is - perhaps confusingly - not used by the static linker, ld
, to find libraries that are input on the linkage
commandline to make a program or shared library, but is used by the dynamic linker (a.k.a loader) ld.so
to find the shared
libraries that a program or shared library requests to be loaded at runtime.
The directories that will be searched for libraries by ld
to resolve an -lfoo
linkage
option are, in this order of priority:
-L <dir>
options, in their commandline
order (regardless of their order with respect to lfoo
or other the -lname
options)LIBRARY_PATH
(not LD_LIBRARY_PATH
). By default, when
ld
is invoked as usual by gcc/g++
on your behalf, the value that ld
will receive this way is the value that the distro's build of the compiler frontend has been
configured it to set in LIBRARY_PATH
when the frontend calls ld
.For normal linkages done with gcc/g++
you can discover all these libraries by compiling
and linking a specimen program passing the --verbose
option to both the frontend and the
linker, and grepping the stdout
+stderr
for -L
, LIBRARY_PATH
and SEARCH_DIR(
. For
example:
$ cat file.c
int main(void)
{
return 0;
}
$ gcc file.c -L $(pwd) --verbose -Wl,--verbose 2>&1 | egrep \(-L\|LIBRARY_PATH\|SEARCH_DIR\)
...
I won't actually paste the output here because without grep
colour-highlighting of the matches it's
unrewarding. You can do it yourself. You'll notice that all the directories listed in the gcc
-populated
LIBRARY_PATH
get added as -L <dir>
options to the linkage commandline. The directories enclosed by SEARCH_DIR(<dir>)
are the linker's build-configured search directories.
You do not need to change the /etc/ld.so.conf.d/
to load libnf_cln.so
The ldconfig
cache and its configuration files in /etc/ld.so.conf.d/
exist to expedite the dynamic linker's search for system libraries - shared libraries that serve any application and are owned by none.
If libnf_cln.so
is a private library of your project you do not need to change
the contents of /etc/ld.so.conf.d/
to let the dynamic linker find your library.
As a rule you should resist polluting the ldconfig
cache with your application's
private links because the fatter it gets the slower it serves the whole system.
Here is a worked illustration of how to avoid doing that.
$ tail -n +1 *.c *.h
==> app.c <==
#include <private_shared_lib.h>
int main(void)
{
private_shared_lib();
return 0;
}
==> private_shared_lib.c <==
#include <stdio.h>
void private_shared_lib(void)
{
puts(__FUNCTION__);
}
==> private_shared_lib.h <==
#pragma once
void private_shared_lib(void);
$ mkdir -p app/libs
Here is my private shared library:
$ gcc -shared -o ./app/libs/libprivate.so private_shared_lib.c
Link my app against it:
$ gcc -o ./app/app app.c -I. -L./app/libs -lprivate
Because I told the static linker -L./app/libs -lprivate
, it resolved -lprivate
to
./apps/libs/libprivate.so
. It found that shared library; the linkage was successful and
the static linker wrote the following information in the dynamic section of the output program:
$ readelf --dynamic --wide ./app/app
Dynamic section at offset 0x2db8 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libprivate.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
...[irrelevant]...
This is information for the dynamic linker to read and act on at runtime. libprivate.so
is NEEDED
because the static linker found that it defines the program's reference to
symbol private_shared_lib
. The C runtime library libc.so.6
is automatically added to
the linkage by gcc
and the static linker found it was NEEDED
because it resolves the
program's reference to symbol puts
.
Good. But:
$ ./app/app
./app/app: error while loading shared libraries: libprivate.so: cannot open shared object file: No such file or directory
My program fails to run because the dynamic linker looks for libprivate.so
by its default search and cannot find it.
So I will link the program again like this:
$ gcc -o ./app/app app.c -I. -L./app/libs -lprivate -Wl,-rpath=$(pwd)/app/libs
-Wl,<linker-option>[,linker-option,...]
tells gcc
to pass <linker-option>[,linker-option,...]
straight through to ld
. Now the dynamic section of the program contains this information:
$ readelf --dynamic --wide ./app/app
Dynamic section at offset 0x2da8 contains 29 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libprivate.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [/home/imk/develop/so/scrap/app/libs]
...[irrelevant]...
The new information:
0x000000000000001d (RUNPATH) Library runpath: [/home/imk/develop/so/scrap/app/libs]
advises the dynamic linker at runtime that /home/imk/develop/so/scrap/app/libs
is an additional directory
in which to search for NEEDED
shared libraries, and when it knows that:
$ ./app/app
private_shared_lib
my program can run.
That's better. But I would like to install my program, with its private shared library, in an arbitrary directory (likely on another computer). Let's fake that:
$ mkdir installdir
$ mv ./app ./installdir
But in the installed location:
$ ./installdir/app/app
./installdir/app/app: error while loading shared libraries: libprivate.so: cannot open shared object file: No such file or directory
Of course,
0x000000000000001d (RUNPATH) Library runpath: [/home/imk/develop/so/scrap/app/libs]
no longer enables the dynamic linker to find libprivate.so
So let's retreive our build directory:
$ cp -r ./installdir/app ./
and relink app
like:
$ gcc -o ./app/app app.c -I. -L./app/libs -lprivate -Wl,-rpath='$ORIGIN/libs'
Now its dynamic section looks like:
$ readelf --dynamic --wide ./app/app
Dynamic section at offset 0x2da8 contains 29 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libprivate.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/libs]
...[irrelevant]...
where the dynamic linker will interpret $ORIGIN
as the directory containing this file.
Now the program runs where we built it:
$ ./app/app
private_shared_lib
And also if we install it elsewhere:
$ rm -fr installdir/*
$ mv ./app ./installdir
$ ./installdir/app/app
private_shared_lib
Lastly, if you would forsee making successive versioned releases of libnf_cln.so
- libnf_cln.so.X[.Y[.Z]]
- that
you want to be automatically selected when your application is linked using -lnf_cln.so
, then investigate
linking libnf_cln.so
with the option [-soname=libnf_cln.so.X
] in conjunction with symbolic links:
libnf_cln.so.so.X -> libnf_cln.so.so.X.Y [ -> libnf_cln.so.so.X.Y.Z ]