I'm compiling Linux libraries (for Android, using NDK's g++, but I bet my question makes sense for any Linux system). When delivering those libraries to partners, I need to mark them with a version number. I must also be able to access the version number programatically (to show it in an "About" dialog or a GetVersion
function for instance).
I first compile the libraries with an unversioned flag (version 0.0
) and need to change this version to a real one when I'm done testing just before sending it to the partner. I know it would be easier to modify the source and recompile, but we don't want to do that (because we should then test everything again if we recompile the code, we feel like it would be less error prone, see comments to this post and finally because our development environment works this way: we do this process for Windows binaries: we set a 0.0
resources version string (.rc) and we later change it by using verpatch...we'd like to work with the same kind of process when shipping Linux binaries).
What would be the best strategy here? To summarize, requirements are:
0.0
or anything else)If your answer is "rename the .so", then please provide a solution for 3.: how to retrieve version name (i.e.: file name) at runtime.
I was thinking of some solutions but have no idea if they could work and how to achieve them.
string
or 3 int
) in the code and have a way to change it in the binary file later? Using a binary sed...?Note that we use QtCreator to compile the Android .so files, but they may not rely on Qt. So using Qt resources is not an ideal solution.
Shared libraries are loaded by ld.so (or ld.so.x) and ld-linux.so (or ld-linux.so.x) programs, where x is the version. In Linux, /lib/ld-linux.so.x searches and loads all shared libraries used by a program. A program can call a library using its library name or filename, and a library path stores directories where libraries can be found in ...
Making an incompatible change in a shared library without bumping the SONAME (usually to the next integer) value is a grave error that will result in hordes of angry users descending upon your project (and rightfully so). So it doesn't really matter for the parts of the shared library that aren't part of the SONAME.
Libraries are very useful as they provide reusable functions, classes and data structures. Some examples of libraries in Linux are glibc (GNU version of standard C library), libc (the C standard library). In total we can divide the libraries in Linux in two categories.
To get a list of all shared library dependencies for a binary file, you can use the ldd utility. The output of ldd is in the form: This command shows all shared library dependencies for the ls command.
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:
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...)GetVersion
function that would clean the version
variable above (remove VERSIONSTRING:
and useless 0
). It would return:
0.0
if version
is VERSIONSTRING:00000.00000.00000.00000
2.3
if version
is VERSIONSTRING:00002.00003.00000.00000
2.3.40
if version
is VERSIONSTRING:00002.00003.00040.00000
mylib.so
GetVersion
), it returns 0.0
, no surprisestd::fstream
with std::ios_base::binary
)VERSIONSTRING:00000.00000.00000.00000
in itVERSIONSTRING
, to make it more unic...)VERSIONSTRING:00002.00003.00040.00000
if expected binary number is 2.3.40
mylib.so
using the above tool (requesting version 2.3
for instance)2.3
!No recompilation nor linking, you patched the binary version!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With