linking to a shared library that has soft-links to it - c

gcc c89
I am just looking to link against the below shared library.
I am wondering why the programmer has created so many soft-links. The programmer has left the company and I am just wondering what is the purpose.
lrwxrwxrwx. 1 24 Jan 11 11:23 libsofia-sip-ua.so -> libsofia-sip-ua.so.0.6.0
lrwxrwxrwx. 1 24 Jan 11 11:23 libsofia-sip-ua.so.0 -> libsofia-sip-ua.so.0.6.0
-rwxrwxr-x. 1 4728304 Jan 11 11:19 libsofia-sip-ua.so.0.6.0
For what I can understand if the library was to get updated to a newer version you could just soft-link it with the updated version.
But why create libsofia-sip.so.0?
Many thanks for any suggestions,

The filename ending in .so is the one used by the linker (not dynamic linker) when you use the -l option to specify a library you want to search/link. The linker is unaware of other suffixes and won't find them. When the linker opens this file, it finds a different name in the DT_SONAME field of the library's header, usually the name with a single-number suffix. This is the name it will store in the DT_NEEDED field of the new program's dynamic linking header.
The filename ending in .so.N (e.g. N=0 in your case) is the one corresponding to the DT_SONAME in the library file, and it represents a series of library versions which all have a compatible ABI.
The filename ending in .so.N.X.Y is the actual file for the currently installed library version. It's possible for more than one of these to exist, and normally the other symlinks will be setup to point to the most recent version. But old versions are not automatically overwritten this way, so you could manually load an old one with LD_PRELOAD or replace the symlinks if there's a reason you need to downgrade.

Most likely, the library's "real name" is libsofia-sip-ua.so.0. This is encoded into the shared object. The libsofia-sip-ua.0.6.0 name is probably just a name it was installed under.
It was probably the ldconfig program that made the links. I believe it always makes a link for the embedded name if the library file has some other name.
So it probably was not the programmer who wanted these extra links. He, or his library build tool, named the library file a different name than what is embedded inside the library file.

Related

Linking with .dylib library from the command line using clang

I'm trying to write a C program using a library. The library has provided a include/ and lib/ directory with header files and .dylib files, respectively.
My file is in the same directory as include/ and lib/. I'm trying to compile it with the following command:
clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window test.c
However, when I go to run my program, I get the following error:
% ./a.out
dyld: Library not loaded: #rpath/libcsfml-graphics.2.4.dylib
Referenced from: ~/src/CSFML-2.4-osx-clang/./a.out
Reason: image not found
zsh: abort ./a.out
What is the correct way to compile using these libraries? I'd prefer to simply use the command line as I'm writing a small program, without having to set up Xcode, etc.
% ls -l lib/
-rwxr-xr-x# 1 staff 50296 Mar 1 2017 libcsfml-audio.2.4.0.dylib*
lrwxr-xr-x# 1 staff 26 Mar 1 2017 libcsfml-audio.2.4.dylib# -> libcsfml-audio.2.4.0.dylib
lrwxr-xr-x# 1 staff 24 Mar 1 2017 libcsfml-audio.dylib# -> libcsfml-audio.2.4.dylib
-rwxr-xr-x# 1 staff 163680 Mar 1 2017 libcsfml-graphics.2.4.0.dylib*
lrwxr-xr-x# 1 staff 29 Mar 1 2017 libcsfml-graphics.2.4.dylib# -> libcsfml-graphics.2.4.0.dylib
lrwxr-xr-x# 1 staff 27 Mar 1 2017 libcsfml-graphics.dylib# -> libcsfml-graphics.2.4.dylib
-rwxr-xr-x# 1 staff 67272 Mar 1 2017 libcsfml-network.2.4.0.dylib*
lrwxr-xr-x# 1 staff 28 Mar 1 2017 libcsfml-network.2.4.dylib# -> libcsfml-network.2.4.0.dylib
lrwxr-xr-x# 1 staff 26 Mar 1 2017 libcsfml-network.dylib# -> libcsfml-network.2.4.dylib
It seems that after fixing rpath with clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window -Wl,-rpath,"#executable_path/lib" test.c you're still missing SFML libraries. I've just checked that CSFML depends on SFML, and based on your ls -l lib/ listing, SFML is clearly absent in lib/. My guess is that after fixing rpath you may not have noticed that the absent dependency has changed to #rpath/libsfml-graphics.2.4.dylib instead of #rpath/libcsfml-graphics.2.4.dylib. Please, download SFML libraries and put them into lib/.
Now to your question, how to build on macOS from the command line. Your building steps are correct, so I suppose the difficult part is how the dependencies are searched by dyld, not how they're linked with ld.
A short theory.
There are 4 ways a binary (an executable or a dynamic library) references its dependencies:
by an absolute or relative path (the latter is relative to your working directory);
by #executable_path, expanding to the path of the executable which is the root of the dependency tree (in case you have recursive dependencies);
by #loader_path, expanding to the path of the executable or a library for which the dependency is searched, i.e. it's the path of the direct parent in the dependency tree;
by #rpath, which is substituted in turn by each rpath found in your binary, and this is the most flexible way as you can search in several directories by having multiple rpaths.
Now the question is how to ensure the dependencies are correctly referenced. As #mattmilten pointed out, there are 2 methods for that:
make your build system/build script/manual build commands ensure the references are correct;
use install_name_tool to correct the broken references.
Making it automatic during the build.
In order for the first method to work you need to make sure the identification names of the dependency libraries are correct. Suppose you're linking a binary against some library libA.dylib. The identification name of libA.dylib is the default reference which will be used by the linker (ld) when building your binary. You can find it by looking at the first line of otool -L libA.dylib (or alternatively at the LC_ID_DYLIB section of otool -l libA.dylib). In case of libcsfml-graphics.2.4.dylib it's #rpath/libcsfml-graphics.2.4.dylib and it was passed to a.out on linking, that's why you're seeing it in the error message when dyld fails to meet it.
Setting a correct identification name is a responsibility of the libA.dylib authors. It is set according to their expectations as to where libA.dylib could be placed (using #rpath is a good choice) as well as their versioning scheme (in case of CSFML version 2.4.0 could be replaced with 2.4.x without losing binary compatibility). If you're building libA.dylib yourself you can set it with -install_name param (e.g. clang -Wl,-dylib -Wl,-install_name,#executable_path/libA.dylib -o libA.dylib liba.c). If it's a 3rd party library you can change it with install_name_tool -id #rpath/libA.dylib libA.dylib.
Identification name, to the best of my knowledge, is only used during linking and not used when loading a binary, so if you prefer the second method of fixing incorrect references with install_name_tool you can ignore it.
Manual fixing.
Fixing the references with install_name_tool is simple but tedious. You'll probably need a script when there are a lot of incorrect references. All you need is the following set of commands (the binary placeholder should obviously be replaced with an actual binary name):
install_name_tool -change #executable_path/libA.dylib #rpath/libA.dylib binary to change reference #executable_path/libA.dylib -> #rpath/libA.dylib;
install_name_tool -add_rpath #executable_path/lib binary to add #executable_path/lib to rpaths;
install_name_tool -delete_rpath #executable_path/lib binary to remove #executable_path/lib from rpaths;
otool -l binary to check existing rpaths (just look at the LC_RPATH sections).
You should check the environment variable DYLD_LIBRARY_PATH. It should contain the path to libcsfml-graphics.2.4.dylib. Another solution might be to add this path to your PATH variable.
You can inspect the paths of your binary with otool -L and modify them with install_name_tool -change. Ideally, though, you should build your binary to contain the correct rpath to its dependencies using -R when linking/compiling.

Suspicious static-linked executable file size

I have a BB 10/QNX app in which I need to use more recent version of SQLite than is default on BB 10. I thought I could do that by linking my own SQLite code with my app. I realized that in my qmake-generated Makefile the option -lsqlite3 is passed to qcc. In the library location (/opt/bbndk/target_10_2_0_1155/qnx6/armle-v7/usr/lib) I found the following files:
size filename
559386 libsqlite3.a
560662 libsqlite3S.a
15 libsqlite3.so -> libsqlite3.so.1
496503 libsqlite3.so.1
I thought that I can replace libsqlite3.a with my own file compiled from latest sqlite3.c (amalgamation). What confuses me is that the size of my application executable is just 180 kB, so the code from libsqlite3.a doesn't seem to be present in it. If SQLite is dynamically linked, I'd expect the application archive (.bar) to contain libsqlite3.so, which also isn't true, because the archive is just 130 kB big. How is it possible that the application uses SQLite (via Qt database classes), but SQLite code never makes it to the application archive?
Static version
When linking an executable to a static library, the compiler know you're building a "finished product": nothing will depend on your executable. It allows the compiler to not include unused code. Let's say you're using only one function from the library, which itself is not using anything else from the library. The compiler will pick only the machine code corresponding to this specific function and gently ignore the rest.
Dynamic version
Regarding the size of the bar archive and the dynamic library, it goes down to what really is a bar archive. It's simply a zip archive (maybe with some metadata added, don't know in details). Two possibilities: either the .so file is greatly compressed, or the compiler relies on the system library and doesn't bundle it in the bar archive.

shared library file size

On creating a shared library the ./sl file size is coming out to be greater than 60KB.
There are 2 .o files whose total size is over 20KB.
Checked the utlities : ldd and elfdump to determine libraries being referenced.
Apart from the original files used I see references of :/usr/ccs/lib/pa20_64/lddstub and
SOURCE FILE INFO: movelr1 PA-RISC 2.0 Assembler.
What are the possible reasons for shared lib file size increase ?.
[(Novice in C) : Working on OS : HP Unix 11i V2 PA RISC-64]
I am not an HP-UX expert but my best guess is that the HP-UX vendor linker is adding some additional stuff to dynamic library it is creating in addition to the 20kB of object files.
You could use the strip(1) utility to make the shared library smaller.
Thanks Sean!, However using the strip utility did effect the file size, ~7KB , but in a small way.
Another option we found was: elfdump -dc TestProg.sl
On doing that we found that system file is included and also the date/time of compilation of the source files. One probability is that the earlier version of the sl file had older version of prog/os system file included and this could be a possible cause in size difference.
The sys file included in shared lib:
[movelr1.o]: in the path /usr/lib/pa20_64/milli.a influences the size of the ./sl file created.

Any way to change linking to avoid the LD_PRELOAD on HPUX?

I think I understand why I need LD_PRELOAD set when loading a multithreaded applicatoin that loads a single threaded library that loads libcl.2 but I was wondering if I could use some linker setting to avoid this. Any help appreciated.
Update:
Perl loads
dynamic /usr/lib/libc.2
Perl loads DB2.sl
DB2 Attempts to load
dynamic /usr/lib/libcl.2
Could it be the fact that something with that shared object name is already loaded it then fails.
/usr/lib>pwd
/usr/lib
/usr/lib>ls -lt | grep libcl.2
-r-xr-xr-x 1 bin bin 1261568 Feb 14 2003 libcl.2
lrwxr-xr-x 1 root sys 9 Nov 21 2002 libcl.sl -> ./libcl.2
Now the reason refuses to go looking for something of this same name might be explained by the chattr output:
Both have the disable fields set so they won't look in the environment nor use the alternate name
chatr on perl
perl:
shared executable
shared library dynamic path search:
SHLIB_PATH disabled second
embedded path disabled first Not Defined
shared library list:
dynamic /usr/lib/libnsl.1
dynamic /usr/lib/libnm.sl
dynamic /usr/lib/libdld.2
dynamic /usr/lib/libm.2
dynamic /usr/lib/libsec.2
dynamic /usr/lib/libpthread.1
dynamic /usr/lib/libc.2
chatr on DB2.sl
DB2.sl:
shared library
shared library dynamic path search:
SHLIB_PATH disabled second
embedded path disabled first Not Defined
shared library list:
dynamic /opt/IBM/db2/V8.1/lib/libdb2.sl
dynamic /usr/lib/libcl.2
Could maybe the chatr settings of one of the libraries be adjusted?
Update: why not just make them use the same name for the library.
Depending on your compiler/linker (thinking of the HPUX machines I logged onto more than a decade ago makes me shudder), --rpath might help: from what I understand, in your case the rtld is looking in the wrong place first, so that's why you want to preload some other version of the lib, right? In that case, rpath will embed an additional search location into the compiled binary, which you can use to point it to the directory where your preferred version is coming from.
Hope this helps. -V
I wrote an article about shared libraries on HP-UX and tried to make it clear and comprehensive. I found myself having to debug why programs couldn't find their libraries and so I documented it.
The three main locations that will affect the library search are 1) /etc/SHLIBPATH; 2) environment variables; and 3) the embedded library search path.
Unfortunately, this is a drastic oversimplification: the best reference I have to offer is that article that brings everything together (in my opinion, any way).
There are not linker flags to avoid this.

What exactly does "ar" utility do?

I don't really understand what ar utility does on Unix systems.
I know it can be somehow used for creating c libraries, but all that man page tells me is that it is used to make archives from files, which sounds similar to, for example, tar....
The primary purpose is to take individual object files (*.o) and bundle them together into a static library file (*.a). The .a file contains an index that allows the linker to quickly locate symbols in the library.
Tar doesn't create files that linkers understand.
ar is a general purpose archiver, just like tar. It just "happens" to be used mostly for creating static library archives, one of its traditional uses, but you can still use it for general purpose archiving, though tar would probably be a better choice. ar is also used for Debian .deb packages.
Exactly, ar is an archiver. It simply takes a set of object files (*.o) and put them in an archive that you call a static library.
It takes code in the form of object files (.obj, .o, etc) and makes a static library (archive). The library can then be included when linking with ld to include the object code into your executable.
Take a look at the example usage in the Wikipedia article.
You might want to run man ar to get the full picture. Here's a copy of that on the web.
To quote:
The GNU ar program creates, modifies, and extracts from archives. An
archive is a single file holding a collection of other files in a
structure that makes it possible to retrieve the original individual
files (called members of the archive).
ar is considered a binary utility because archives of this sort are
most often used as libraries holding commonly needed subroutines.
ar is specifically for archives (or libraries) of object code; tar is for archives of arbitrary files. Anybody's guess why GNU refers to these as 'archives', in other environments this utility is called the 'librarian', and the resulting files just libraries.

Resources