Change Linux shared library (.so file) version after it was compiled
I am afraid you started to solve your problem from the end. First of all SONAME is provided at link time as a parameter of linker, so in the beginning you need to find a way to get version from source and pass to the linker. One of the possible solutions - use ident
utility and supply a version string in your binary, for example:
const char version[] = "$Revision:1.2$"
this string should appear in binary and ident
utility will detect it. Or you can parse source file directly with grep
or something alike instead. If there is possibility of conflicts put additional marker, that you can use later to detect this string, for example:
const char version[] = "VERSION_1.2_VERSION"
So you detect version number either from source file or from .o file and just pass it to linker. This should work.
As for debug version to have version 0.0 it is easy - just avoid detection when you build debug and just use 0.0 as version unconditionally.
For 3rd party build system I would recommend to use cmake
, but this is just my personal preference. Solution can be easily implemented in standard Makefile as well. I am not sure about qmake
though.
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!