ParisHilton
ParisHilton

Reputation: 55

Which is the best way to pass a variable from a Makefile to an executable?

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

Answers (4)

Andreas
Andreas

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

tripleee
tripleee

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

HardcoreHenry
HardcoreHenry

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

HardcoreHenry
HardcoreHenry

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

Related Questions