EEVblog Electronics Community Forum
Electronics => Microcontrollers => Topic started by: krish2487 on January 25, 2019, 08:39:10 am
-
Hello,
I have a question regarding passing shell commands to gcc compiler.
Specifically, this is the problem.
I am working on a program in C where I need to version control the main.c . For various reasons, it was agreed on that the last git commit hash would make for a good way to track the version and can be automated during the build.
The idea is that invoking gcc like so gcc (other flags) -DVERSION=(shell command with regexp to get the last commit hash) *would* work.
The VERSION variable is used elsewhere in the program to keep track of the firmware and print it for diagnostic purposes.
Is it possible to pass a shell command to the compiler flags and if so how??
Thanks in advance. :-)
-
The traditional way, which works on all Unix shells, is to use backquote command substitution.
gcc other flags... -DVERSION="`git...`"
The more modern way, which is syntactically cleaner, uses the $() syntax.
gcc other flags... -DVERSION="$(git...)"
The double quotes are important so that the shell doesn't try to expand or split the command output as if it were a file name.
-
@helius
That was fast!! :-)
Thank you for the answer. Let me try and get back with my findings.
Again, thank you very much for the help!! :-)
-
Hmm...
The $() does not seem to work..
It evaluates to a NULL value. and prints nothing
The "` `" seems to evaluate correctly and print the hash.
However, there is another snag.
make
CC -o ex1.out ex1.cpp -Wall -Werror -DVERSION="`git rev-parse --short HEAD`"
ex1.cpp:37:28: error: invalid digit 'c' in decimal constant
version_array = (char*)VERSION;
^
<command line>:1:20: note: expanded from here
#define VERSION 814cdb3
^
ex1.cpp:38:19: error: invalid digit 'c' in decimal constant
printf((char*)VERSION);
^
<command line>:1:20: note: expanded from here
#define VERSION 814cdb3
^
2 errors generated.
make: *** [all] Error 1
And this is the test C file.
#include <stdio.h>
int main()
{
printf("Hello World\n");
printf("Version Number: ");
char version_array[7];
version_array = (char*)VERSION;
printf((char*)VERSION);
printf("\n");
}
casting the hash does not seem to work. Not casting it returns the same error
Any pointers (pun intended ) :-D
-
The git output is bare hexadecimal without the prefix that C requires (0x).
gxx other options... -DVERSION="0x`git ...`"
But you have another problem because you're assuming it's a string...
You need to add quotes to the #define if you want it to be a string. The shell has special treatment for quotes, so this is often challenging.
gxx other options... -DVERSION="\"`git ...`\""
csh will throw a fit at this because it doesn't allow double quotes to be escaped. bash or zsh will probably work.
By the way, the cast (char *) is unnecessary because the macro just gets pasted in. If you define the macro as a string, the preprocessor will put a string literal in its place. You obviously can't cast a random integer to a string and expect it to work.
-
Make also has a mechanism for getting shell command output assigned to a Make variable:https://www.gnu.org/software/make/manual/html_node/Shell-Function.html(Quoting might drive you batty, though.)
-
Quote from: westfw on Today at 09:05:13 pm (https://www.eevblog.com/forum/index.php?topic=165601.msg2147809#msg2147809)Make also has a mechanism for getting shell command output assigned to a Make variable:https://www.gnu.org/software/make/manual/html_node/Shell-Function.html(Quoting might drive you batty, though.)
Thank you for the link. It looks interesting. I ll try with this as well. It might make it more verbose and understandable.
Thank you very much helius. Your suggestion worked!! :-)
Specifically this worked
Quote-DVERSION="\"`git rev-parse --short HEAD`\""
Quote from: helius on Today at 08:59:33 pm (https://www.eevblog.com/forum/index.php?topic=165601.msg2147800#msg2147800)The git output is bare hexadecimal without the prefix that C requires (0x).
Code:
[Select] (https://www.eevblog.com/forum/javascript:void(0);)gxx other options... -DVERSION="0x`git ...`"
But you have another problem because you're assuming it's a string...
You need to add quotes to the #define if you want it to be a string. The shell has special treatment for quotes, so this is often challenging.
Code: [Select] (https://www.eevblog.com/forum/javascript:void(0);)gxx other options... -DVERSION="\"`git ...`\""
csh will throw a fit at this because it doesn't allow double quotes to be escaped. bash or zsh will probably work.
By the way, the cast (char *) is unnecessary because the macro just gets pasted in. If you define the macro as a string, the preprocessor will put a string literal in its place. You obviously can't cast a random integer to a string and expect it to work.
-
I prefer having a bash script that extracts information from { git, mercurial, subversion, doors, ... } such as { commit date, revision, branch, version, author, ... } and fills a C-module created just for the purpose of propagating this information
the bash script is invoked by make, so it has a label ("touch" on my choice) in the Makefile
so make touch ---> creates info.c, it does the job, and you it's a neat job :phew:
-
shell command output
e --desel $(grep perl /var/profile/world)
This is what I usually do to pass a list of items that need to go deselected (and deleted).
Long story on the why? and what?, but it works on the bash shell, so it's OK even on Unix.
-
Interesting idea. Just out of curiosity does it not create another step that you have to keep track of, even in the makefile?
Unless, of course the "touch" target is a dependancy for the release build target..
Quote from: legacy on Yesterday at 10:05:55 pm (https://www.eevblog.com/forum/index.php?topic=165601.msg2147941#msg2147941)I prefer having a
bash script that extracts information from { git, mercurial, subversion, doors, ... } such as { commit date, revision, branch, version, author, ... } and fills a C-module created just for the purpose of propagating this information
the bash script is invoked by make, so it has a label ("touch" on my choice) in the Makefile
so make touch ---> creates info.c, it does the job, and you it's a neat job :phew:
-
as a prerequisite in the Makefile, you can assign "touch" as rule assigned to all:
all: touch
...
or something similar so it will run touch and auto-generate info.c before compiling stuff
-
I assumed as much.
Very elegant and modular! :-)
Thanks.
Lots of wonderful ideas here!! :-)
-
let whatever you do with git make a file- your git process is in charge of creating the hash (and only creates when needed)
echo "#define GITHASH \"$(git log -1 --format="%H")\"" > githash.h
//and just include the file where needed
//main.c
#include githash.h
the git process creates the info, the c files use as needed- they are separate jobs and no need to add any more options to the compiler
-
There's a better way to do this with GNU make. Basically, you generate new version information whenever the git repo itself changes.
$(OBJ)/build_info.o : $(ROOT)/.git/HEAD $(ROOT)/.git/index | $(BUILD)
@echo Creating $(BUILD)/build_info.cc
@rm -f $(BUILD)/build_info.cc
@echo "const char *GIT_VERSION = \"$(shell git describe --long --always --match or-* --dirty)\";" >> $(BUILD)/build_info.cc
@echo "const char *GIT_COMMIT = \"$(shell git rev-parse HEAD)\";" >> $(BUILD)/build_info.cc
@echo "const char *BUILD_TIME = \"$(shell date)\";" >> $(BUILD)/build_info.cc
@echo "const char *APP_AUTHOR = \"$(shell whoami)\";" >> $(BUILD)/build_info.cc
@$(CXX) $(CFLAGS) $(CXXFLAGS) -c $(BUILD)/build_info.cc -o $(OBJ)/build_info.o
This rule produces a build_info.cc and corresponding .o file whenever the HEAD or index of the repo is updated. The build_info is not under revision control itself, so it's generated as necessary for each build. The GIT_VERSION variable lets you tag releases in the repo and also makes it clear when some of the files have been modified but not committed (i.e., the "dirty" suffix).
-
We do something very similar to legacy seems to do.
We do it in python, and also have ti extract a user readable version number from git tags using git describe.
This python script then gets run at the start of every build. and it generates a version.c file.
Really useful for tracking down code versions etc.
another important thing it can do is tell you if your build was dirty or not (eg not all files/changes committed into git yet) to make sure that if you try and re-build version xxxx to reproduce a bug, you can reproduce the bin file exaclty