What is the 'soname' option for building shared libraries for? - linux

I learned the "Program Library HOWTO". It mention that using soname to manage the version like follow.
gcc -shared -fPIC -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0.0 foo.c
ln -s libfoo.so.1.0.0 libfoo.so.1
ln -s libfoo.so.1 libfoo.so
And I get the information that if the soname is not set. it will be equal to libfoo.so.1.0.0 ,see the answer from here.
And I find that it also can work without soname , like following
gcc -shared -fPIC -o libfoo.so.1.0.0 foo.c
ln -s libfoo.so.1.0.0 libfoo.so.1
ln -s libfoo.so.1 libfoo.so
So I think that the only one useful point is that the soname option can tell you the version of the shared library when you use readelf -d libfoo.so command to check it.
What else can it do?

soname is used to indicate what binary api compatibility your library support.
SONAME is used at compilation time by linker to determine from the library file what actual target library version. gcc -lNAME will seek for libNAME.so link or file then capture its SONAME that will certainly be more specific ( ex libnuke.so links to libnuke.so.0.1.4 that contains SONAME libnuke.so.0 ).
At run time it will link with this is then set into ELF dynamic section NEEDED, then a library with this name ( or a link to it ) should exists.
At Run time SONAME is disregarded, so only the link or the file existence is enough.
Remark: SONAME is enforced only at link/build time and not at run time.
'SONAME' of library can be seen with 'objdump -p file |grep SONAME'.
'NEEDED' of binaries can be seen with 'objdump -p file |grep NEEDED'.
[EDIT] WARNING Following is a general remark, not the one deployed in linux. See at the end.
Let's assume you have a library with libnuke.so.1.2 name and you develop a new libnuke library :
if your new library is a fix from previous without api change, you should just keep same soname, increase the version of filename. ie file will be libnuke.so.1.2.1 but soname will still be libnuke.so.1.2.
if you have a new library that only added new function but didn't break functionality and is still compatible with previous you would like to use same soname than previous plus a new suffix like .1. ie file and soname will be libnuke.so.1.2.1. Any program linked with libnuke.1.2 will still work with that one. New programs linked with libnuke.1.2.1 will only work with that one ( until new subversion come like libnuke.1.2.1.1 ).
if your new library is not compatible with any libnuke : libnuke.so.2
if your new library is compatible with bare old version : libnuke.so.1.3 [ ie still compatible with libnuke.so.1 ]
[EDIT] to complete : linux case.
In linux real life SONAME as a specific form :
lib[NAME][API-VERSION].so.[major-version]
major-version is only one integer value that increase at each major library change.
API-VERSION is empty by default
ex libnuke.so.0
Then real filename include minor versions and subversions ex : libnuke.so.0.1.5
I think that not providing a soname is a bad practice since renaming of file will change its behavior.

You created a dynamic library named libx.1.0.0 in naming tradition libname.{a}.{b}.{c}
{a} stand for primary version, should changes when APIs changes(which making things incompatible).
{b} stand for sub version, should changes by adding APIs.
{c} stand for mirror version, should changes by bug fixing or optimizing
Now you are releasing libx.1.2.0, and you need to declare that libx.1.2.0 is compatible with libx.1.0.0 since just adding functions and people's executable would not crashes, just link it like in the old time by:
Setting libx.1.0.0 and libx.1.2.0 to have the same soname, for example libx.1
This's what soname does.

Here is an example supporting Johann Klasek's answer.
In short, SONAME is needed at run time.
At compilation time, only a linker name or real name is needed (e.g. g++ main.cpp -L. -ladd or g++ main.cpp -L. -l:libadd.so.1.1). The definitons of linker name and real name follow Program Library HOWTO: 3. Shared Libraries.
Source tree:
├── add.cpp
├── add.h
├── main.cpp
└── Makefile
Makefile:
SOURCE_FILE=add.cpp
# main.cpp includes `add.h`, whose implementation is `add.cpp`
MAIN_FILE=main.cpp
SONAME=libadd.so.1
REAL_NAME=libadd.so.1.1
LINKER_NAME=libadd.so
OUTPUT_FILE=a.out
all:
g++ -shared -fPIC -Wl,-soname,${SONAME} -o ${REAL_NAME} ${SOURCE_FILE}
ln -s ${REAL_NAME} ${LINKER_NAME}
g++ main.cpp -I. -L. -ladd -o ${OUTPUT_FILE}
# Same as `ldconfig -n .`, creates a symbolic link
ln -s ${REAL_NAME} ${SONAME}
#./a.out: error while loading shared libraries: libadd.so.1: cannot open
# shared object file: No such file or directory
LD_LIBRARY_PATH=. ./${OUTPUT_FILE}
clean:
rm ${SONAME} ${REAL_NAME} ${LINKER_NAME} ${OUTPUT_FILE}

Let's assume libA.so depends on libB.so, and they all in a directory(of course the directory cannot be found by dynamic linker). If you didn't set soname then dlopen doesn't work:
auto pB = dlopen("./libB.so", RTLD_LAZY | RTLD_GLOBAL);
auto pA = dlopen("./libA.so", RTLD_LAZY | RTLD_GLOBAL);
Because runtime linker cannot find libB.so, so pA is set to NULL.
In this case soname will save you from hell...

Another aspect:
At least on Linux the SONAME entry provides a hint for the runtime-linker system on how to create appropriate links in /lib, /lib64 etc.
Running the command ldconfig tries to create a symbolic link named with SONAME which is also taken into the run-time linker cache. The newest one of the libraries tagging the same SONAME wins the link-race.
If some software relies on the specific SONAME and you want to renew a library you have to provide this SONAME to get ldconfig stick on this new library (if ldconfig is used to rebuild the cache and the links). E.g. libssl.so.6 and libcrypto.so.6 are such cases.

Related

Shared library name in executable is different than the filename

A cleaned up version of my compile command looks like gcc -o semantic_seg -Wl,-rpath,... -l:libnvrtc-5e8a26c9.so.10.1 ... and I have a dynamic library file named exactly libnvrtc-5e8a26c9.so.10.1 in the directory specified by the -rpath flag. The command succeeds.
When I go to run my program, it says semantic_seg: error while loading shared libraries: libnvrtc.so.10.1: cannot open shared object file: No such file or directory and when I do ldd it shows libnvrtc.so.10.1 => not found.
So the problem looks like the name of the shared library in the executable is not the same as the filename. Could that be true? Did the 5e8a26c9 part of the name somehow get stripped off?
Update: Creating a symbolic link libnvrtc-5e8a26c9.so.10.1 -> libnvrtc.so.10.1 allows the executable to run. But I'm still not sure the mechanism that causes this name modification to happen. It seems a bit magic.
Could that be true?
This is often true.
On ELF systems, the linker uses SONAME of the library (if it has one) and not its filename to record a runtime dependency.
Running readelf -d libnvrtc-5e8a26c9.so.10.1 | grep SONAME will likely show that in fact that library does have SONAME, and the value of SONAME is libnvrtc.so.10.1.
This used to be very convenient for external library versioning.
Update:
it allows you to link against a library which will be different than the one which will used at run time, but why would I ever want that?
Like I said, it's useful for external library versioning and ABI evolution.
Suppose you ship version 1.0 of libfoo.so. You provide libfoo.so as a symlink to libfoo.so.1, and you use libfoo.so.1 as SONAME.
Any program that links with gcc main.c -lfoo (note: no funny -l:libfoo.so.1 syntax required) will record libfoo.so.1 as its external dependency, and will use that name at runtime.
Time passes, and you are ready to ship version 2, which is not ABI-compatible.
You don't want to cause all your end-users to change their link line, and you don't want to break any existing binaries.
With the SONAME, this is trivial: new package will include libfoo.so.2 with SONAME of libfoo.so.2, and a symlink libfoo.so now pointing to libfoo.so.2.
Voila: both requirements are achieved: existing binaries continue to use libfoo.so.1, newly-linked binaries use libfoo.so.2, no Makefile changes required.

Creation of.so of files

There is a set with - files with extension.с: avl_tree.c, buf_read.c, db_prep.c, file_process.c, global_header.c, traverser.c. Used include files are in folder/usr/gcc/4.4/bin/include except for jni.h, and libraries are in folder/usr/gcc/4.4/bin/lib. How from them to create.so the file (if it is possible specify all options in this command)? It me interests in communication by creation of native of methods by means of JNI.
You really should read the documentation of GCC. Notably invoking GCC. The program library howto is also relevant.
Very often, some builder is used to drive the build. GNU make is often used and has a good tutorial documentation. If your Makefile-s are complex, you may also want to use GNU remake to debug them (remake is a debugging variant for make).
You usually want to compile each individual C source file into position independent code because shared objects have PIC code. You can use
gcc -Wall -fPIC -o foo.pic.o foo.c
to compile a C source foo.c into a position independent object file foo.pic.o and you may need some other compiler options (e.g. -I to add include directories, or -D to define some preprocessor symbols, -g for debugging, and -O for optimizing).
I strongly suggest to enable almost all warnings with -Wall (and to improve your code till no warnings are given; this will improve a little bit your code's quality).
Then you have to link all these *.pic.o files together into a shared object with
gcc -shared *.pic.o -o foo.so
You can link some shared libraries into a shared object.
You may want to read Levine's book on linkers and loaders
Of course if you use GNU make you'll have rules in your Makefile for all this.
You could use GNU libtool also.
Maybe dlopen(3) could interest you.
The question should probably give more information.
Most sets of sources have a Makefile, configure script or some other item to set up to make the output (the .so library you want).
gcc -dynamic -o file.so file.c
will create an so file from one of the source files, but you probably want a single so from all of them.

Compile Linux executable with specific version number [duplicate]

Following question How do applications resolve to different versions of shared libraries at run time?, I wondered how to specify on the link command line which version of the library to use?
Let's say I have
libmy.so.1.0
libmy.so.1 -> libmy.so.1.0
libmy.so.2.0
libmy.so.2 -> libmy.so.2.0
libmy.so -> libmy.so.2
The usual way to specify the library to link with the executable does not show the version to use. Furthermore, it is very likely that one wants to link with the most recent version. Thus the usual line works fine in most cases.
gcc app.o -lmy -o app
What is the command line to link app that should use version 1 of the library?
The linker is able to accept filenames too
gcc app.o -l:libmy.so.1 -o app
From man ld:
-l namespec
--library=namespec
Add the archive or object file specified by namespec to the list of files to link. This option may be used any number of times. If
namespec is of the form :filename, ld will search the library path for a file called filename, otherwise it will search the library
path for a file called libnamespec.a.
I noticed that older versions do not support it, so check man ld -l or --library option on your system.
You could also link to the file mentioning its full name
gcc app.o /mylibpath/libmy.so.1 -o app

Possible to statically link shared object libraries?

I'm building a library that needs to be dynamically linked to my project. The output is a .so file, so I think I'm on the right track. I'm concerned by the way it's being linked at compile time - by specifying the location of its makefile and depending on a bunch of macros, which I've never encountered before.
Can I assume that since I'm building a .so library (rather than a .a) that I'm in fact dynamically linking? Or is it possible for .so libs to be statically linked, in which case I need to rip apart the make/config files to better understand what's going on?
Thanks,
Andrew
I'm not familiar with internal structure of executables and shared objects, so I could only give some practical hints.
Assuming you use gcc, it should have -shared option when linking object files into library - this way ld (called by gcc) makes shared object instead of executable binary.
gcc -shared -o libabc.so *.o ...
When you link some application with this libabc.so it should link without errors and after that with ldd command you should be able to see libabc.so among its dependencies.
$ ldd app
...
libabc.so => ...............

Static link of shared library function in gcc

How can I link a shared library function statically in gcc?
Refer to:
http://www.linuxquestions.org/questions/linux-newbie-8/forcing-static-linking-of-shared-libraries-696714/
You need the static version of the library to link it.
A shared library is actually an executable in a special format
with entry points specified (and some sticky addressing issues
included). It does not have all the information needed to
link statically.
You can't statically link a shared library (or dynamically link a static one).
The flag -static will force the linker to use static libraries (.a) instead of shared (.so) ones. But static libraries aren't always installed by default, so you may have to install the static library yourself.
Another possible approach is to use statifier or Ermine. Both tools take as input a dynamically linked executable and as output create a self-contained executable with all shared libraries embedded.
If you want to link, say, libapplejuice statically, but not, say, liborangejuice, you can link like this:
gcc object1.o object2.o -Wl,-Bstatic -lapplejuice -Wl,-Bdynamic -lorangejuice -o binary
There's a caveat -- if liborangejuice uses libapplejuice, then libapplejuice will be dynamically linked too.
You'll have to link liborangejuice statically alongside with libapplejuice to get libapplejuice static.
And don't forget to keep -Wl,-Bdynamic else you'll end up linking everything static, including libc (which isn't a good thing to do).
Yeah, I know this is an 8 year-old question, but I was told that it was possible to statically link against a shared-object library and this was literally the top hit when I searched for more information about it.
To actually demonstrate that statically linking a shared-object library is not possible with ld (gcc's linker) -- as opposed to just a bunch of people insisting that it's not possible -- use the following gcc command:
gcc -o executablename objectname.o -Wl,-Bstatic -l:libnamespec.so
(Of course you'll have to compile objectname.o from sourcename.c, and you should probably make up your own shared-object library as well. If you do, use -Wl,--library-path,. so that ld can find your library in the local directory.)
The actual error you receive is:
/usr/bin/ld: attempted static link of dynamic object `libnamespec.so'
collect2: error: ld returned 1 exit status
Hope that helps.
If you have the .a file of your shared library (.so) you can simply include it with its full path as if it was an object file, like this:
This generates main.o by just compiling:
gcc -c main.c
This links that object file with the corresponding static library and creates the executable (named "main"):
gcc main.o mylibrary.a -o main
Or in a single command:
gcc main.c mylibrary.a -o main
It could also be an absolute or relative path:
gcc main.c /usr/local/mylibs/mylibrary.a -o main
A bit late but ... I found a link that I saved a couple of years ago and I thought it might be useful for you guys:
CDE: Automatically create portable Linux applications
http://www.pgbovine.net/cde.html
Just download the program
Execute the binary passing as a argument the name of the binary you want make portable, for example: nmap
./cde_2011-08-15_64bit nmap
The program will read all of libs linked to nmap and its dependencias and it will save all of them in a folder called cde-package/ (in the same directory that you are).
Finally, you can compress the folder and deploy the portable binary in whatever system.
Remember, to launch the portable program you have to exec the binary located in cde-package/nmap.cde
Best regards
In gcc, this isn't supported. In fact, this isn't supported in any existing compiler/linker i'm aware of.

Resources