How to avoid having version numbers in .so file name
What you are looking for is making a plugin
.
Add CONFIG += plugin
to your project file, and qmake will generate a Makefile that builds a libFoo.so
file, without the numbered links
Git: Any way to ignore files that have gotten version number changed only
This is not incredibly robust, but maybe good enough. In .git/config
put:
[diff "remove-rev"]
textconv=sed '/IP.Board v[0-9]*\\.[0-9]*\\.[0-9]*/d'
And then in .gitattributes
or .git/info/attributes
, put:
* diff=remove-rev
Now, whenever git-diff
is run, the sed script will be applied to the file before gitdiffcore decides which file pairs differ. You may need to tweek the sed
command to suit your needs, but this should help.
Difference between version number, minor number and release number
Each time you release the library, it should arguably have a different version number. However, some releases only make changes to the internal workings of the library without affecting users at all other than by fixing bugs. Other releases may also add new functions to the library, but the interface details of all the existing functions are the same as before, so software written to use an older version of the library will continue to work with the new version. Other changes may break backwards compatibility; a function interface changes, a structure changes size, or a function is dropped (or a global variable — perish the thought — changes, etc).
The 'bug fix only' versions might not bother with renumbering the library, but if you previously had liberror.so.1.0.2
, the new version might be liberror.so.1.0.3
, a change in the release number.
The 'additional features' versions should be given a new minor number, so the new version after liberror.so.1.0.2
might be liberror.so.1.1.0
.
If you break compatibility, then you use a new version number, so the new version after liberror.so.1.0.2
might be liberror.so.2.0.0
.
Code built to use liberror.so.1.0.2
can and will use either liberror.so.1.0.3
or liberror-1.1.0
without problem, but will not attempt to use liberror.so.2.0.0
or later versions.
What code (in a GNU binutils stack, for example) controls which versions will be linked to, and is this behavior fixed or overridable?
Good question. This is my understanding, but I might have some details wrong (in which case, someone will probably point out the error of my ways). The theory above is nice an easy; this is a little less easy.
You may have noticed that there are 'development' packages for libraries as well as the 'standard' versions of the libraries. The difference between them is part of the explanation.
If you're an ordinary end user who is not writing programs using a library but simply running programs that someone else has written, then you typically end up with one file and one symlink in the installation directory. Continuing with the hypothetical liberror.so.1.0.2
example (installed in /usr/local/lib
), you would find in the base release:
liberror.so.1.0.2 — the real shared object
liberror.so.1 — symlink to the the real shared object
If you installed the development version, you'd probably find some header files in /usr/local/include
, some man pages (perhaps in /usr/local/man
, perhaps in /usr/share
instead), and an extra symlink:
liberror.so — another symlink, either to liberror.so.1 or to liberror.so.1.0.2
When the program using it is compiled, you might specify:
gcc -I/usr/local/include usererror.c -o usererror -L/usr/local/lib -lerror
This will link with the name liberror.so
, but reading the metadata from the liberror.so.1.0.2
file, it would know that the version to use is liberror.so.1.0.2
or later (but not liberror.so.2.0.0
or later).
Now let's suppose you upgrade the installation to liberror.so.2.0.0
. You now have files:
liberror.so.1.0.2 — the real shared object
liberror.so.1 — symlink to the the real shared object
liberror.so.2.0.0 — the real shared object
liberror.so.2 — symlink to the the real shared object
liberror.so — another symlink, either to liberror.so.2 or to liberror.so.2.0.0
Old code built to use liberror.so.1
still runs using that library. New code built to use liberror.so.2
also runs using the new library. And at link time, new programs pick up liberror.so.2.0.0
via the symlink liberror.so
.
You can control it so that the default on your system is still liberror.so.1
by adjusting the liberror.so
symlink to point to liberror.so.1.0.2
. The only tricky part is making sure that the correct versions of the headers are available for compilation. It is a bad idea to build with the headers for liberror.so.2
and link with liberror.so.1
because the one thing you know for sure is that the interfaces are different!
Some raw data from a Red Hat Enterprise Linux 5 (RHEL5) x86_64 machine.
$ cd /lib64
$ ls libc*
-rwxr-xr-x 1 root root 1713088 2009-01-05 16:32 libc-2.5.so
lrwxrwxrwx 1 root root 11 2012-02-22 15:05 libcap.so -> libcap.so.1
lrwxrwxrwx 1 root root 14 2012-02-22 15:05 libcap.so.1 -> libcap.so.1.10
-rwxr-xr-x 1 root root 17384 2006-11-14 01:36 libcap.so.1.10
-rwxr-xr-x 1 root root 197744 2009-01-05 16:32 libcidn-2.5.so
lrwxrwxrwx 1 root root 14 2012-02-22 15:05 libcidn.so.1 -> libcidn-2.5.so
lrwxrwxrwx 1 root root 17 2012-02-22 15:05 libcom_err.so.2 -> libcom_err.so.2.1
-rwxr-xr-x 1 root root 10000 2008-09-30 13:27 libcom_err.so.2.1
-rwxr-xr-x 1 root root 48600 2009-01-05 16:32 libcrypt-2.5.so
-rwxr-xr-x 1 root root 1048728 2005-10-31 06:47 libcrypto.so.0.9.6b
-rwxr-xr-x 1 root root 1365504 2008-12-16 08:09 libcrypto.so.0.9.8e
lrwxrwxrwx 1 root root 19 2012-02-22 15:05 libcrypto.so.2 -> libcrypto.so.0.9.6b
lrwxrwxrwx 1 root root 19 2012-02-22 15:05 libcrypto.so.4 -> libcrypto.so.0.9.8e
lrwxrwxrwx 1 root root 19 2012-02-22 15:05 libcrypto.so.6 -> libcrypto.so.0.9.8e
lrwxrwxrwx 1 root root 15 2012-02-22 15:05 libcrypt.so.1 -> libcrypt-2.5.so
lrwxrwxrwx 1 root root 11 2012-02-22 15:05 libc.so.6 -> libc-2.5.so
$
You can see the libc.so.6
is a symlink to libc-2.5.so
. You can also a number of versions of libcrypto
, not including the link-time library libcrypto.so
. You can also see libraries with only two parts to the version number, etc. The represented libraries are libc
, libcap
, libcidn
, libcom_err
, libcrypt
and libcrypto
.
Change Linux shared library (.so file) version after it was compiled
Discussion with Slava made me realize that any const char*
was actually visible in the binary file and could then be easily patched to anything else.
So here is a nice way to fix my own problem:
- Create a library with:
- a definition of
const char version[] = "VERSIONSTRING:00000.00000.00000.00000";
(we need it long enough as we can later safely modify the binary file content but not extend it...) - a
GetVersion
function that would clean theversion
variable above (removeVERSIONSTRING:
and useless0
). It would return:0.0
ifversion
isVERSIONSTRING:00000.00000.00000.00000
2.3
ifversion
isVERSIONSTRING:00002.00003.00000.00000
2.3.40
ifversion
isVERSIONSTRING:00002.00003.00040.00000
- ...
- a definition of
- Compile the library, let's name it
mylib.so
- Load it from a program, ask its version (call
GetVersion
), it returns0.0
, no surprise - Create a little program (did it in C++, but could be done in Python or any other languauge) that will:
- load a whole binary file content in memory (using
std::fstream
withstd::ios_base::binary
) - find
VERSIONSTRING:00000.00000.00000.00000
in it - confirms it appears once only (to be sure we don't modify something we did not mean to, that's why I prefix the string with
VERSIONSTRING
, to make it more unic...) - patch it to
VERSIONSTRING:00002.00003.00040.00000
if expected binary number is2.3.40
- save the binary file back from patched content
- load a whole binary file content in memory (using
- Patch
mylib.so
using the above tool (requesting version2.3
for instance) - Run the same program as step 3., it now reports
2.3
!
No recompilation nor linking, you patched the binary version!
ld to library without version information in Linux
I was able to build the library as-desired, without the version information.
What I ended up doing was creating a dummy library with the appropriate exported symbols--without version (or soname) information--and linking to that dummy library while compiling and linking my library. At runtime, the loader loads the real library (libxul.so) without failing based on the versioning problems since my library does not contain version information for the real library. To figure out which exported symbols I needed, I first linked to the real libxul.so, then used readelf --dyn-syms
to determine dwhich symbols were actually needed.
Where ARCH is 32 or 64 (for 32-bit or 64-bit compilation):gcc -o $ARCH/libxul.so -fPIC -shared -DM$ARCH -m$ARCH xulstubs.c
xulstubs.c:
/*
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_Realloc@xul26 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_UTF16ToCString@xul26 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_CStringCloneData@xul26 (2)
13: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_GetMemoryManager@xul26 (2)
...
*/
void NS_Realloc() {}
void NS_UTF16ToCString() {}
void NS_CStringCloneData() {}
void NS_GetMemoryManager() {}
/* ... etc. ... */
Now, the imported symbols from my library do not have the version appendage:
23: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_Realloc
29: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_UTF16ToCString
33: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_CStringCloneData
37: 0000000000000000 0 FUNC GLOBAL DEFAULT UND NS_GetMemoryManager
and it runs as desired.
I would still like a more “elegant” solution, one that does not require creating a dummy library. If this is the only workaround using the standard toolchain, however, I can live with it.
Related Topics
Rtnetlink Answers: No Such File or Directory
Powershell Connecting from a Linux Client to a Windows Remote
Passing an Array as Command Line Argument for Linux Kernel Module
How to Sort Numbers in a Qtreewidget Column
Driver Ch341 Usb Adapter Serial Port or Qserialport Not Works in Linux
Sending from The Same Udp Socket in Multiple Threads
Linux: Proc/Net/Sockstat Tcp Mem More and More Larger
Linux - Run Process on Several Cores
Exit from Bash Script But Keep The Process Running
Git Post-Receive Checkout to Remote Machine
How to Remove Warning: Link.Res Contains Output Sections; Did You Forget -T
How to Install Docker 1.9+ in Centos 6.5
Tar Command Not Found in Dockerfile
Human Readable, Recursive, Sorted List of Largest Files
Increase Mongodb Maximum Number of Connections
How to Write a Bash Script That Cuts Images into Pieces Using Image Magick