Author Topic: Passing shell commands to gcc compiler flags  (Read 741 times)

0 Members and 1 Guest are viewing this topic.

Offline krish2487

  • Frequent Contributor
  • **
  • Posts: 428
  • Country: dk
Passing shell commands to gcc compiler flags
« 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. :-)
If god made us in his image,
and we are this stupid
then....
 
The following users thanked this post: cdev

Offline helius

  • Super Contributor
  • ***
  • Posts: 2859
  • Country: us
Re: Passing shell commands to gcc compiler flags
« Reply #1 on: January 25, 2019, 08:49:16 am »
The traditional way, which works on all Unix shells, is to use backquote command substitution.
Code: [Select]
gcc other flags... -DVERSION="`git...`"

The more modern way, which is syntactically cleaner, uses the $() syntax.
Code: [Select]
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.
 
The following users thanked this post: krish2487

Offline krish2487

  • Frequent Contributor
  • **
  • Posts: 428
  • Country: dk
Re: Passing shell commands to gcc compiler flags
« Reply #2 on: January 25, 2019, 09:02:11 am »
@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!! :-)
If god made us in his image,
and we are this stupid
then....
 

Offline krish2487

  • Frequent Contributor
  • **
  • Posts: 428
  • Country: dk
Re: Passing shell commands to gcc compiler flags
« Reply #3 on: January 25, 2019, 09:32:28 am »
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.


Code: [Select]
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.


Code: [Select]
#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
If god made us in his image,
and we are this stupid
then....
 

Offline helius

  • Super Contributor
  • ***
  • Posts: 2859
  • Country: us
Re: Passing shell commands to gcc compiler flags
« Reply #4 on: January 25, 2019, 09:59:33 am »
The git output is bare hexadecimal without the prefix that C requires (0x).
Code: [Select]
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]
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.
« Last Edit: January 25, 2019, 10:06:11 am by helius »
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 3065
  • Country: us
Re: Passing shell commands to gcc compiler flags
« Reply #5 on: January 25, 2019, 10:05:13 am »
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.)
 
The following users thanked this post: krish2487

Offline krish2487

  • Frequent Contributor
  • **
  • Posts: 428
  • Country: dk
Re: Passing shell commands to gcc compiler flags
« Reply #6 on: January 25, 2019, 11:00:04 am »



Quote from: westfw on Today at 09:05:13 pm
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
The git output is bare hexadecimal without the prefix that C requires (0x).
Code:
[Select]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]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.
If god made us in his image,
and we are this stupid
then....
 

Online legacy

  • Super Contributor
  • ***
  • Posts: 4335
  • Country: ch
Re: Passing shell commands to gcc compiler flags
« Reply #7 on: January 25, 2019, 11:05:55 am »
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:

 

Online legacy

  • Super Contributor
  • ***
  • Posts: 4335
  • Country: ch
Re: Passing shell commands to gcc compiler flags
« Reply #8 on: January 25, 2019, 11:14:47 am »
shell command output

Code: [Select]
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.
 

Offline krish2487

  • Frequent Contributor
  • **
  • Posts: 428
  • Country: dk
Re: Passing shell commands to gcc compiler flags
« Reply #9 on: January 25, 2019, 01:08:25 pm »


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
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:


If god made us in his image,
and we are this stupid
then....
 

Online legacy

  • Super Contributor
  • ***
  • Posts: 4335
  • Country: ch
Re: Passing shell commands to gcc compiler flags
« Reply #10 on: January 25, 2019, 01:14:13 pm »
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
 

Offline krish2487

  • Frequent Contributor
  • **
  • Posts: 428
  • Country: dk
Re: Passing shell commands to gcc compiler flags
« Reply #11 on: January 25, 2019, 01:16:32 pm »
I assumed as much.


Very elegant and modular! :-)
Thanks.


Lots of wonderful ideas here!! :-)
If god made us in his image,
and we are this stupid
then....
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 472
Re: Passing shell commands to gcc compiler flags
« Reply #12 on: January 25, 2019, 04:56:44 pm »
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
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 892
  • Country: us
Re: Passing shell commands to gcc compiler flags
« Reply #13 on: January 25, 2019, 09:41:48 pm »
There's a better way to do this with GNU make. Basically, you generate new version information whenever the git repo itself changes.

Code: [Select]
$(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).
 

Offline lucazader

  • Regular Contributor
  • *
  • Posts: 127
  • Country: nz
Re: Passing shell commands to gcc compiler flags
« Reply #14 on: January 26, 2019, 12:58:55 am »
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
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf