It is very valuable to have a date and time information in the binary. That way for example using a shell I can check the version of the firmware running on a device, or it can be printed on a console or UART as needed.
The C/C++ language offers to macros which represent date and time.
__DATE__ __TIME__They can be used directly or used with a pointer like below:
static const char *const FW_Date = __DATE__; static const char *const FW_Time = __TIME__;However, they match the date and time the when the file (or compilation unit) has been compiled. If that file is not recompiled, it keeps the ‘old’ date and time.
Alternatively, gcc provides the
__TIMESTAMP__
macro which could be used, see GCC macros help page.But for a firmware version I would like to have the latest date & time of it. Sure I could delete the object file or do a clean and a full build.
A more elegant solution is to ‘touch’ (or change) the file containing the date/time information. On Linux or a ‘bare’ make or cmake build I could use the ‘touch’ command for this, and that file will be recompiled.
On Windows and including Eclipse (MCUXpresso IDE in this case) it is very easy too: I can setup a pre-build step which touches the file I need to rebuild, and it gets recompiled every time I do a build: exactly what I need :-).
Go to the project settings, C/C++ Build, Settings and then edit the Pre-Build steps in the Build Steps tab:
Use the touch command to touch a file, e.g.
touch ../source/main.cπ‘ Make sure that there is line ending (CR/Return) at the end of the line!
The current directory is the build output directory, e.g. ‘Debug’.
That way I can always trigger a ‘touch & build’:
It is possible to use Eclipse Build variables too, for example if I would like to delete the ELF/Dwarf (Output binary) I could use
rm "${BuildArtifactFileName}"And then this will cause the following build at least to re-link the binary.
Happy Dating π
Links
- MCUXpresso IDE: https://www.nxp.com/mcuxpresso/ide/download
- Other usage of Build Steps: https://mcuoneclipse.com/2017/03/29/mcuxpresso-ide-s-record-intel-hex-and-binary-files/
Hi Erich,
this is a very good idea! I normally store my sw ver in the code, but for example during development, you don’t update that value for each change, while this mechanism does!
Of course also very useful the touch command! π
As always, many thanks for sharing this useful tips!
Ale
LikeLiked by 1 person
I was first not aware that I could use the Linux touch command on Windows, so this is a great thing to have. The good thing is that with the pre-build step you can pretty much do whatever you want.
LikeLike
A good read, however now I tend to prefer deterministic builds. A good article is here – https://interrupt.memfault.com/blog/reproducible-firmware-builds
LikeLiked by 1 person
Agreed, deterministic is always good. The preferred way to have the production build deterministic is using a dedicated build server, and there you will do a ‘clean’ anyway before starting a build.
The approach with the touch is just one example how to use a pre-build: you can pretty much do anything needed, depending on the development flow.
LikeLike
I prefer everyone being able to build ‘exactly’ the same binary if using the same build tools (and version) – even years later. That is why i never use these kind of preprocessor macros in source code.
LikeLiked by 2 people
Hadn’t realized the date wouldn’t change every day, I’ll have to watch for that on my one project that uses __DATE__.
Mostly we have menu files compiled from “source” created with our own “language” so I added a date function to that tool we use, along with a “once-per-day” trick to make it work. This method is easier for sure.
I guess you could “rm main.o” instead of touching main.c (does touch keep changing the last change time of the file?)
LikeLiked by 1 person
__DATE__ is supplied by the compiler using the host system date, so it will change as it changes on the host and uses what value it has at compile time.
And yes, you could remove main.o too that way. If you have release and build configurations (or other configurations), then you need to make sure it deletes the right one.
And yes, touch changes the modification date of the file, triggering a re-build. I used main.c for demo purpose here, other than that I have version information in a ‘version.h’ file which I can touch too.
LikeLiked by 1 person
I’ve been using this trick for a few years, and it’s very handy. On a recent HDD update ‘touch’ no longer works; turns out it was only working before because of some other software package that was installed, separate from CW (oh yeah, I use CW 10.7). So I had to do a few tricks, and that made it cumbersome; I couldn’t get it to just ‘work’ again, and error output is minimal for diagnosis.
The other thing I did is to add ” & time &” at the end of post-build steps, so if I forget if I’ve compiled or not, I can see the last time it actually finished.
LikeLiked by 1 person
Hi Rhys,
good suggestion to add the time to the post build step. About ‘touch’ on Windows: it is not installed anywhere on my system (I cannot use it from a cmd). The IDE has some Linux like tools installed in \ide\buildtools\bin such as cp, echo, make, mkdir, mv, rm und sh. But no touch. The IDE says that it is executing a linux-like shell but not sure if it is built into sh or not.
LikeLike
Update: ‘touch’ is indeed part of the sh in \ide\buildtools\bin. You can verify this with launching a command prompt there, type sh and it will run a linux shell which has touch implemented, along with many more commands. I get the article updates with this information π
LikeLike
Pingback: Using Linux Shell Commands on Windows with MCUXpresso Pre-/Post-Build Steps | MCU on Eclipse
I usually do a prebuild step, where I generate from my CVS (which is usually git) the commit id into a c file, which is compiled into the project.
With git this usually would be the first 8 digits of the git hash.
Also very important is to store the state of the repo, whether it has modifications or not.
This way the build is both reproducible, and trackable.
I definitely know which commit was used to build it.
As usually an IDE comes with a Debug and Release build option, it is also good practice to store this information into the binary.
This eliminates the ever occurring question: Which HW did I just test in the cryo chamber for the last 2 weeks? No worries, just read out the information which was baked into it.
If one takes these matters seriously, then the build is done with a toolchain which is versioned with conan for example.
Because even if you know which git commit you used to build, do you really remember in 5 years, which exact IDE version you used. Every update might bring a new toolchain version.
LikeLiked by 1 person
Agreed, a version control system is essential for any reproducible build. Storing the build environment is is important too. What we did in a previous company I worked with was that we stored away the build machine doing the final build: that way we had exactly the environment (host operating system, tools installed, etc) to be able to reproduce the production build for up to 15 years. The issue sometimes was that the host machine was not made to survive 15 years (capacitors on the board, etc), so in addition to that the complete image(s) were stored independently too.
LikeLike
Problem with this is, that if using CDT, the touch is after the moment that CDT has determined what to compile. So you can get the date/time of a previous build (attempt).
I solved this by making a small program which makes a file which is included in the linker ‘ld’ file.
In the prebuild phase it runs, and defines some global variables which hold build time/version information. These can then be referred in the source code.
LikeLiked by 1 person
That’s an interesting point, I have not observed that (yet). The solution with the symbols for the link phase/linker files sounds a good solution to me too, so thanks for that suggestion
LikeLike