How can I store a version number in a static library (file.a) and later check for its version in Linux?
P.S. I need possibility to check version of file any time wit
Several times man 1 ident
has been mentioned, so here are details about using that method.
ident
is a command that comes with the RCS (Revision Control System), but might also be available if you are using CVS (Concurrent Versions System), or Subversion.
You would use it like this (cloned from the man page):
#include <stdio.h>
static char const rcsid[] =
"$Id: f.c,v 5.4 1993/11/09 17:40:15 eggert Exp $";
int main() { return printf("%s\n", rcsid) == EOF; }
and f.c is compiled into f.o, then the command
ident f.c f.o
will output
f.c:
$Id: f.c,v 5.4 1993/11/09 17:40:15 eggert Exp $
f.o:
$Id: f.c,v 5.4 1993/11/09 17:40:15 eggert Exp $
If your f.o
were added to a static library f.a
then ident f.a
should show a similar output. If you have several similarly built [a-z].o
in your az.a
you should find all their strings in the az.a
file.
CAVEAT: Just because they are in the .a file doesn't mean they will be included in your program file. Unless the program references them the linker sees no need to include them. So you usually have to have a method in each module to return the string, and the app needs to call that method. There are ways to convince most linkers that it is a required symbol without actually referencing it, but it depends on the linker, and is beyond the scope of this answer.
If instead you are familiar with the SCCS (Source Code Control System) then you would use man 1 what
instead, and it would look like this (done with macros to show the flexibility available):
#include <stdio.h>
#define VERSION_STR "5.4"
#define CONFIG "EXP"
#define AUTHOR "eggert"
static char const sccsid[] =
"@(#) " CONFIG " v " VERSION_STR " " __DATE__ " " __TIME__ " " AUTHOR;
int main() { return printf("%s\n", sccsid) == EOF; }
and f.c is compiled into f.o, then the command
what f.c f.o
will output
f.c:
@(#) EXP v 5.4 1993/11/09 17:40:15 eggert
f.o:
@(#) EXP v 5.4 1993/11/09 17:40:15 eggert
PS: both ident
and what
are commands that come with specific centralized source control systems. If you are using a distributed source control system (like git) the entire concept may not make sense. For some ideas using git
see this thread: Moving from CVS to git: $Id:$ equivalent? though the hash isn't the same as a version number. :)
If you are using gcc, you can use the #ident directive
#ident "Foo Version 1.2.3.4"
void foo(void){ /* foo code here */ }
To get the version just use one of the following:
strings -a foo.o | grep "Foo Version"
strings -a foo.a | grep "Foo Version"
strings -a foo.so | grep "Foo Version"
This will allow you to compile the version into the library with the capability of later stripping it out using strip -R .comment your_file
or completely omit it by passing -fno-ident
(This will also omit the compiler version comments from the compiled objects)
Maybe you could create a string with the version like this:
char* library_version = { "Version: 1.3.6" };
and to be able to check it from the shell just use:
strings library.a | grep Version | cut -d " " -f 2
In addition to providing a static string as mentioned by Puppe, it is common practice to provide a macro to retrieve the version check for compatibility. For example, you could have the following macros (declared in a header file to be used with your library):
#define MYLIB_MAJOR_VERSION 1
#define MYLIB_MINOR_VERSION 2
#define MYLIB_REVISION 3
#define MYLIB_VERSION "1.2.3"
#define MYLIB_VERSION_CHECK(maj, min) ((maj==MYLIB_MAJOR_VERSION) && (min<=MYLIB_MINOR_VERSION))
Notice with the MYLIB_CHECK_VERSION
macro, I'm assuming you want a specific major rev and a minor rev greater than or equal to your desired version. Change as required for your application.
Then use it from a calling application, something like:
if (! MYLIB_VERSION_CHECK(1, 2)) {
fprintf(stderr, "ERROR: incompatible library version\n");
exit(-1);
}
This approach will cause the version information to come from the included header file. Additionally, it will be optimized at compile time for the calling application. With a little more work, you can extract it from the library itself. Read on...
You can also use this information to create a static string stored inside your library, as mentioned by Puppe. Place something like this inside your library:
struct {
const char* string;
const unsigned major;
const unsigned minor;
const unsigned revision;
} mylib_version = {
MYLIB_VERSION, MYLIB_MAJOR_VERSION, MYLIB_MINOR_VERSION, MYLIB_REVISION
};
This will create a struct called mylib_version
in your library. You can use this to do further verifications by creating functions inside your library and accessing those from a calling application, etc.
Creating a new answer based on your edit... Just to avoid confusion :)
If you are looking for a non-code way to solve the problem, you could try this. It's (yet again) an alternative to the strings
approach defined by Puppe.
Maybe you could just touch a file called version_1.2.3
and add it to the archive. Then, you could determine the version by looking for the version file using the ar command:
ar t libmylib.a | grep 'version_' | sed -e 's/^version_//'
I'm not sure if that will get you what you need, but there is no standard method for embedding metadata like this in an archive. Maybe you'll find other information you want to store in this "metafile" for the archive.