This article discusses a way to use a C++ static initializer in a dynamically generated C++ source file to inject build information into a structure.
IMO, there are better ways. Some of the ways I’ve toyed with in the past include:
Defines on the compiler command line (something like BUILD_INFO := $(shell git rev-parse ...) followed by gcc '-DBUILD_INFO="$(BUILD_INFO)"' ... in a Makefile
The same, but generating a simple buildinfo.h header file which #defines various macros with information
“incbin” solutions:
C++ has std::embed now
C23 has #embed
bin2obj-type solutions convert an arbitrary binary file to an .o file (objcopy can also do this): objcopy -I binary -O elf32-i686 -B i386 file.bin file.o
xxd can convert an arbitrary binary file to a C initializer list, if that’s not an option
In GAS assembly, there is the .incbin directive which is useful. You can actually use this from GNU C (ipxe does this):
Windows only: Using Windows resource files. There is actually a section intended for version information strings.
There is probably something you can do with linker scripts, if you really want to.
I imagine there are tools which could add a section to an ELF file after the fact, which might be reasonably practical. This isn’t too far off from the GNU build ID section, etc.
It’s also worth noting that all of this completely breaks reproducible builds if it’s actually embedding the build time. Most of the time, you want to do this the other way around: have a build environment that, from a given toolchain version and commit hash, is guaranteed to generate an identical binary. Then separately publish a signed attestation that the hash of the binary corresponds to a particular source revision and toolchain.
Agreed. In the past, I’ve found it useful to embed the (hash and) timestamp of the git commit from which you’re building. The commit timestamp, like the build timestamp, gives you an idea of how old the binary is - and does allow reproducibility.
This is much simpler in Go.
This article discusses a way to use a C++ static initializer in a dynamically generated C++ source file to inject build information into a structure.
IMO, there are better ways. Some of the ways I’ve toyed with in the past include:
BUILD_INFO := $(shell git rev-parse ...)followed bygcc '-DBUILD_INFO="$(BUILD_INFO)"' ...in a Makefilebuildinfo.hheader file which#defines various macros with informationobjcopy -I binary -O elf32-i686 -B i386 file.bin file.o.incbindirective which is useful. You can actually use this from GNU C (ipxe does this):It’s also worth noting that all of this completely breaks reproducible builds if it’s actually embedding the build time. Most of the time, you want to do this the other way around: have a build environment that, from a given toolchain version and commit hash, is guaranteed to generate an identical binary. Then separately publish a signed attestation that the hash of the binary corresponds to a particular source revision and toolchain.
Agreed: embedding the build time is a bad idea.
Most of the time I tend to generate a Git commit hash and/or tag name, with a “+” appended if the tree appears dirty.
Agreed. In the past, I’ve found it useful to embed the (hash and) timestamp of the git commit from which you’re building. The commit timestamp, like the build timestamp, gives you an idea of how old the binary is - and does allow reproducibility.
I too spent most of this article thinking “neat but why not -D?”