> AFAIU, on Windows platforms, some executables contain metadata, such
> as the program's version number, date compiled, etc. This information
> is displayed as the program's "Properties", and I suppose there is an
> API to get the information.
>
> I'm working in Linux with ELF executables, and I was wondering if
> there is something equivalent?
No. At least nothing with an officially supported API.
What is the purpose of a version number anyway?
One purpose I can see is that is an extension of source code control,
in which case the version of the executable consists of the versions
of all the pieces of code that went into it, and the version numbers
of tools used to build it. Including all the OS libraries and
header files. That can add up to a lot of data. I'd want an
official API (like Windows has) to support at least up to 1,000
distinct compilation dates, as there can be at least that many
compiled pieces linked into one executable.
You can put stamps into executables merely by putting strings in
the code. There is no official API for this, and a program can
fish these out of the executable by scanning for a pattern, without
much chance for a false positive. This program does not necessarily
know much of anything about the format of an executable - it probably
doesn't have to care whether it is operating on an executable or
source code. In order to prevent the optimizer from deleting them,
provide a command-line option (like --version) to print them. There
are a couple of different patterns in common use. One, the SCCS
style starts with @(#) (and can be extracted with the "what" command.
Another, the RCS/CVS style, consists of $Keyword: ... text ...$ .
It can be extracted with the ident command. You might put code in
each module like:
static char RCSid[] = "$Header$";
which gets expanded when checked in to something like:
static char RCSid[[ = "$Header: <filename> <version> <date> <time> <user> <status> $";
Another use for a version number is to identify the version to the
public, and for the public to use in bug reports, or to figure out
if they need to upgrade. Typically the format is something like
X.Y.Z, where X, Y, and Z are integers, and especially X and Y are
likely to be heavily influenced by marketing and internal politics.
It is desirable to have another component for the development team
to use, and I think a time stamp that only nerds interpret as a
time stamp would be suitable here. For this you might put code
like this in your Makefile:
MAJOR = 4
MINOR = 12
PATCH = 3
VERSION = $(MAJOR).$(MINOR).$(PATCH).`date +'%s'`
CFLAGS = -DPRODUCTVERSION=$(VERSION)
That stuff with the date command produces the UNIX time (in decimal),
so VERSION might come out as 4.12.3.1370052376. If you can get the
time down to nanoseconds, that would be preferable. This does NOT,
however, guarantee a consistent version, as if you "make", it stops
on an error, you fix it (and properly check in the modified code)
and restart "make", you get a mixture of versions in the various pieces.
If the entire build produces one and only one executable, the final
step might be to put the version number in a short piece of source
code, compile it, and link the whole thing.
> A bit more on my use-case:
>
> In the project I'm working on, someone needs to store the program's
> version number in a plain-text file. (I don't know why.)
Invoking:
program --version
ought to output the program's version number, perhaps with some
identifying text around it, like:
$ gnurgf --version
GNU Robotic Girlfriend, Version 2.1.7
$
You might format the text so it's really easy for tools like grep
and sed to fish the version number out of the output.
> At the moment, the version number is defined in a C header file,
> with the correct definition depending on the value of several
> other macros:
>
> #if FOO1
> #define APP_VERSION (0x00010000)
> #elif FOO2
> #define APP_VERSION (0x00020000)
> #elif FOO3
> ...
> #endif
>
> Once the executable is built (with -O0 and -g) they use
> "readelf --debug-dump=macro prog" to dump every macro
> definition in the debug section (!!) and then sort and
> cut to extract the information from readelf's output o_O
> IMO, this is an awful solution for several reasons
> 1) if the compiler does not include the macro definitions, it fails
> 2) if the output format of readelf changes, it fails
> 3) we have to spawn 4 processes, and parse the entire debug section
> to get the info
(4) if this code is closed-source, all that debug info
may give away a large part of the source code when it is
released/sold to the public. Therefore, your lawyers may
refuse to let you release it that way.
> Do you see a better way?
>
> IMO, if the information is required outside of the compilation
> process, it should be defined and made easily available
> *in the general build environment* so that different tools
> (compiler, others) may have access to it. Ergo, it should be
> an environment var or a make var:
I assume that you need it way far outside of the compilation process,
as in more than 20 years after compilation finished, and in a country
that did not exist at the time of compilation, and possibly in outer
space.
>
> ifdef FOO1
> APP_VERSION := 0x00010000
> else ifdef FOO2
> APP_VERSION := 0x00020000
> else ifdef FOO3
> ...
> endif
>
> then add
> CPPFLAGS += -DAPP_VERSION=$(APP_VERSION)
>
> and writing the version to a file is as simple as
> echo $(APP_VERSION) > the_file
>
> Ideas? Opinions?
Code like the above can get out of sync with reality, especially
if the version number is demanded after the code has been compiled,
released, sold, and is in the hands of a customer trying to make a
bug report. Also, upgrade procedures should warn the customer if
he's about to downgrade.
In this case, "program --version" to get the version number is an
easy thing to tell the customer to run. If the application is
hopelessly GUI, you could stick the information on the Help | About
page, but I still think you could make "program --version" work
and have the rest of the program be hopelessly GUI.