Reputation: 55
I want to generate a variable at compilation time in a Makefile and using it at run time in my executable.
Minimal example: In Makefile I generate variable COMMIT_ID
, which contains the ID of the latest commit: COMMIT_ID=$(git rev-parse --verify HEAD)
.
Makefile also generates an executable, for instance executable.elf
.
The C
source code from which executable.elf
is generated prints COMMIT_ID
.
Which is the best way do to it?
Upvotes: 1
Views: 743
Reputation: 5301
Nerd sniper HardcoreHenry baited me for a better (or at least different) solution. Came up with this, having a file in the repository with its name signifying what commit the repo was last built with:
COMMIT_ID := $(shell git rev-parse --verify HEAD)
# target is made if it does not exist
$(COMMIT_ID).commit_id:
@# clean other commits than current
rm -f *.commit_id
@# placeholder for current commit
touch $@
commit_id.h: $(COMMIT_ID).commit_id
echo "#define COMMIT_ID ${COMMIT_ID}" > $@
Upvotes: 2
Reputation: 189327
You could certainly use a make
variable, something like this:
printf("%s\n", COMMIT_ID);
where you'd have a Makefile
with something like
executable.elf: CFLAGS+=-D'COMMIT_ID="$(shell git rev-parse --verify HEAD)"'
(This uses some GNU make
features which are not portable.)
However, it's probably better if this is actually reproducible. Towards that end, perhaps write the value into a file, so that you can see what was used the last time this project was compiled.
executable.elf: commitid.c
.PHONY: commitid.c
commitid.c:
git rev-parse --verify HEAD \
| sed 's/.*/#define COMMIT_ID "&"/' >$@
and then obviously #include "commitid.c"
from executable.c
or whatever the C source file is called.
The .PHONY
declaration to force commitid.c
to be rebuilt every time is a bit of a blunt instrument; perhaps instead make commitid.c
depend on every version-controlled file.
Upvotes: 0
Reputation: 6387
My first answer would not rebuild executable.elf
if the git repository changes, but your sources do not. If you need this to always be rebuilt when the repository changes, you can use some makefile trickery to do this: (There may be a better way to do this, and if anyone can think of one, I'd love to hear it):
First in your makefile do:
$(shell \
COMMIT_ID=$(git rev-parse --verify HEAD) && \
echo "#define COMMIT_ID $${COMMIT_ID}" > commitid.h.tmp; \
if [ ! -f commitid.h ] || ! cmp -s commitid.h.tmp commitid.h; then \
cp commitid.h.tmp commitid.h; \
fi; \
rm commitid.h.tmp \
)
And then in foo.c
, you simply do a
#include commitid.h
So long as your makefile generates .d files then foo.c will be dependent on commitid.h, and will be rebuilt if this file is updated. (if not, add the line foo.c: commitid.h
to your makefile). The file itself will only be updated if the commit id changes, so foo.o will only rebuilt if necessary.
Upvotes: 0
Reputation: 6387
It depends on what your makefile looks like. If you have a dedicated rule for the c file that accesses it, you could just add -DCOMMIT_ID=$(COMMIT_ID)
to the recipe as so:
foo.o: foo.c
$(CC) $(CFLAGS) -DCOMMIT_ID=$(COMMIT_ID) $^ -o $@
or, if you're using pattern rules, you could just add it to CFLAGS, and then every .c file would have access to it (assuming of course that the pattern rule makes use of CFLAGS
):
CFLAGS += -DCOMMIT_ID=$(COMMIT_ID)
After you've done this, COMMIT_ID will be a macro in the c file, so you could use the stringify operator #
to access its value:
printf("commit id is " #COMMIT_ID "\n");
----- EDIT -----
Note that this does have a sharp stick involved with it -- specifically, if you build once, and then modify the git repository without modifying foo.c, then make will consider foo.o to be up to date, and will not rebuild it, meaning that foo.o will have the old commit id in it. I'll post a second answer on how you might get around this if this is a concern
Upvotes: 0