How to embed version information into shared library and binary?
One way to do it if using cvs or subversion is to have a special id string formatted specially in your source file. Then add a pre-commit hook to cvs or svn that updates that special variable with the new version of the file when a change is committed. Then, when the binary is built, you can use ident to extract that indformation. For example:
Add something like this to your cpp file:
static char fileid[] = "$Id: fname.cc,v 1.124 2010/07/21 06:38:45 author Exp $";
And running ident (which you can find by installing rcs) on the program should show the info about the files that have an id string in them.
ident program
program:
$Id: fname.cc,v 1.124 2010/07/21 06:38:45 author Exp $
Note As people have mentioned in the comments this technique is archaic. Having the source control system automatically change your source code is ugly and the fact that source control has improved since the days when cvs was the only option means that you can find a better way to achieve the same goals.
How do I embed version information into a windows binary?
It looks as though the best solution (for us at least) is to use an RC file.
1 VERSIONINFO
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "File Version", "1.0.4"
VALUE "Build Number", "3452"
END
END
END
Which is compiled into a .res file
rc.exe /fo Results/version.res version.rc
Which is then linked in with the rest of the object files.
correct way to encode/embed version number in program code
Normally, for major and minor version numbers (as in, 1.2, 1 is major and 2 is minor), they are most often written in the code directly, usually as a #define
(because you might need them for conditional compilations, i.e., #if
blocks).
You would typically have a separate header that contains only those defines and nothing else (except the header-guard), to minimize dependencies.
Some people use the build system (like cmake) to pull a version number from the version control (git, svn, cvs, etc..) and then put that version number into their "version" header. Or, they put the version number into the build system configuration files and then put that onto the header, as shown on the cmake tutorial. Personally, I don't like this approach because it tends to modify your header files too often and cause frequent and pointless recompilations.
I prefer writing the version number in the header file, and then pulling out those version numbers (major, minor, ..) from the header onto the build system. This is another thing that cmake can very easily do.
If you want to embed a very day-by-day version number into your software, such as a build number or revision number, then you should not put it as a #define
in a header file, but rather as a extern const
variable that you define in one cpp file. For example, you can use cmake to pull a revision number from your version control system, tack that onto the cpp file that defines this extern const int revision;
variable (through cmake's configure_file
function), and link your programs with that cpp / object file. This way, the revision number is built into your programs automatically at every re-build, and it won't trigger full recompilations every time it's updated (which is at every commit).
The point is that major and minor version numbers are not changed frequently enough to require any kind of automatic maintenance, but you need to manually write them in one place only, and automatically propagate it everywhere else where it might be relevant (I would recommend that this place be the header file itself). It's only the revision or build numbers that need to be fully automated (generated by the version control, and propagated everywhere else automatically).
How to add library version information to elf file while linking archive files and all archive files has their version info?
All my archives have their version info but not writing this to elf except libcrt.
In order to understand this result, you need to understand
- How the
what
command works and - How the linker works.
On with the show. The what
command is very simple: it scans an arbitrary binary looking for and ASCII string starting with "special" symbol sequence @(#)
and prints any string that follows that sequence (ending with the NUL
character). Documentation.
In order for the string @(#) Lib ssh swfp version BL910291
to appear in the linked executable bos_epb.ppc.elf
, the object file containing that string must be selected from libssh.a
to become part of the executable. Which brings us to issue #2 above.
Just because such an object is present in libssh.a
, you can't assume that it will be linked into the final binary. The algorithm that the linker uses to decide whether to include an object into the final executable or not is described here or here.
You can garantee that the entire libssh.a
is included in the final binary by using -Wl,--whole-archive -lssh -Wl,--no-whole-archive
, but this is ill-advised. It may cause your binary to fail to link, and is guaranteed to make it larger than it should be.
How to embed data in shared library?
There 2 methods works for me now.
Method 1:
Use objcopy to convert data to ".o", then link to ".so".
Then link the ".so" and main code with "-fPIC".
objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o
g++ -shared -fPIC dicmap.o -o libdicmap1.so
# -fPIC is very import in the following line,
# But it is very unusual when you compile and link main code.
g++ -fPIC test_dicmap.cpp libdicmap1.so -o test_dicmap1-PIC
Method 2:
Use assmbler to wrap the data, and store the size in a different way of objcopy.
g++ -shared -fPIC dicmap3.s -o libdicmap3.so
g++ test_dicmap3.cpp libdicmap3.so -o test-dicmap3
Codes:
test_dicmap.cpp:
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
extern "C" {
extern const uint8_t _binary_dicmap_bin_start[];
extern const uint8_t _binary_dicmap_bin_end[];
extern const void* _binary_dicmap_bin_size;
}
int main()
{
size_t data_size = (size_t)&_binary_dicmap_bin_size;
printf("start=%p, end=%p\nend-start=%zd, size=%zd\n",
_binary_dicmap_bin_start,
_binary_dicmap_bin_end,
_binary_dicmap_bin_end - _binary_dicmap_bin_start,
data_size);
printf("data[0..8]=%02x %02x %02x %02x %02x %02x %02x %02x\n",
_binary_dicmap_bin_start[0], _binary_dicmap_bin_start[1],
_binary_dicmap_bin_start[2], _binary_dicmap_bin_start[3],
_binary_dicmap_bin_start[4], _binary_dicmap_bin_start[5],
_binary_dicmap_bin_start[6], _binary_dicmap_bin_start[7]);
assert(_binary_dicmap_bin_end - _binary_dicmap_bin_start == data_size);
}
test_dicmap3.cpp:
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
extern "C" {
extern const uint8_t _binary_dicmap_bin_start[];
extern const uint8_t _binary_dicmap_bin_end[];
extern const size_t _binary_dicmap_bin_size;
}
int main()
{
size_t data_size = _binary_dicmap_bin_size;
printf("start=%p, end=%p\nend-start=%zd, size=%zd\n",
_binary_dicmap_bin_start,
_binary_dicmap_bin_end,
_binary_dicmap_bin_end - _binary_dicmap_bin_start,
data_size);
printf("data[0..8]=%02x %02x %02x %02x %02x %02x %02x %02x\n",
_binary_dicmap_bin_start[0], _binary_dicmap_bin_start[1],
_binary_dicmap_bin_start[2], _binary_dicmap_bin_start[3],
_binary_dicmap_bin_start[4], _binary_dicmap_bin_start[5],
_binary_dicmap_bin_start[6], _binary_dicmap_bin_start[7]);
// _binary_dicmap_bin_end is invalid
//assert(_binary_dicmap_bin_end - _binary_dicmap_bin_start == data_size);
}
dicmap3.s:
.globl _binary_dicmap_bin_start
.globl _binary_dicmap_bin_end
.globl _binary_dicmap_bin_size
.section .rodata
.type _binary_dicmap_bin_start, @object
.align 8
_binary_dicmap_bin_start:
.incbin "dicmap.bin"
.align 1
.size _binary_dicmap_bin_end, 1
_binary_dicmap_bin_end:
.byte 0
.size _binary_dicmap_bin_start, _binary_dicmap_bin_end - _binary_dicmap_bin_start
.type _binary_dicmap_bin_size, @object
.size _binary_dicmap_bin_size, 8
.align 8
_binary_dicmap_bin_size:
.quad _binary_dicmap_bin_end - _binary_dicmap_bin_start
dicmap.bin:
helloworld
Is there a way to store the version information in a Rust compiled executable or library?
While I don't think there is an immediate way to use ELF facilities for versioning (they are not cross-platform anyway), it is possible to use version information from Cargo:
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
VERSION
will now be equal to the version specified in the manifest when cargo build
is run. Alternatively, you can use env_opt!()
if you want to build your program without Cargo:
const VERSION: Option<&'static str> = env_opt!("CARGO_PKG_VERSION");
Standard way to embed version into Python package?
Not directly an answer to your question, but you should consider naming it __version__
, not version
.
This is almost a quasi-standard. Many modules in the standard library use __version__
, and this is also used in lots of 3rd-party modules, so it's the quasi-standard.
Usually, __version__
is a string, but sometimes it's also a float or tuple.
As mentioned by S.Lott (Thank you!), PEP 8 says it explicitly:
Module Level Dunder Names
Module level "dunders" (i.e. names with two leading and two trailing
underscores) such as__all__
,__author__
,__version__
, etc.
should be placed after the module docstring but before any import
statements except from__future__
imports.
You should also make sure that the version number conforms to the format described in PEP 440 (PEP 386 a previous version of this standard).
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!
Related Topics
How to Translate Linux Keycodes from /Dev/Input/Event* to Ascii in Perl
Perf Stat Does Not Count Memory-Loads But Counts Memory-Stores
Check That There Are at Least Two Arguments Given in a Bash Script
Populate a Ms Access Database in Linux
How to Replace to Apostrophe ' Inside a File Using Sed
Nginx: [Emerg] Unknown Directive " " in /Etc/Nginx/Sites-Enabled/Example.Com:3
Ldd Says "Not Found" Even Though Library Is in My Ld_Library_Path
Where to Get Msbuild for Linux
Linux/Ubuntu Set: Illegal Option -O Pipefail
Elasticsearch Process Memory Locking Failed
Why Do I Have to 'Wait()' for Child Processes