我想在编译时在 Makefile 中生成一个变量,并在运行时在我的可执行文件中使用它。
最小示例:在 Makefile 我生成变量COMMIT_ID
,其中包含最新提交的 ID:COMMIT_ID=$(git rev-parse --verify HEAD)
。
Makefile 还会生成一个可执行文件,例如executable.elf
. 生成的C
源代码executable.elf
打印COMMIT_ID
.
最好的方法是什么?
我想在编译时在 Makefile 中生成一个变量,并在运行时在我的可执行文件中使用它。
最小示例:在 Makefile 我生成变量COMMIT_ID
,其中包含最新提交的 ID:COMMIT_ID=$(git rev-parse --verify HEAD)
。
Makefile 还会生成一个可执行文件,例如executable.elf
. 生成的C
源代码executable.elf
打印COMMIT_ID
.
最好的方法是什么?
书呆子狙击手 HardcoreHenry 诱使我找到更好(或至少不同)的解决方案。想出了这个,在存储库中有一个文件,其名称表示最后一次构建存储库的提交:
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}" > $@
这取决于你的makefile是什么样的。如果您有访问它的 c 文件的专用规则,您可以-DCOMMIT_ID=$(COMMIT_ID)
像这样添加到配方中:
foo.o: foo.c
$(CC) $(CFLAGS) -DCOMMIT_ID=$(COMMIT_ID) $^ -o $@
或者,如果您使用模式规则,您可以将其添加到 CFLAGS,然后每个 .c 文件都可以访问它(当然假设模式规则使用CFLAGS
):
CFLAGS += -DCOMMIT_ID=$(COMMIT_ID)
完成此操作后,COMMIT_ID 将成为 c 文件中的宏,因此您可以使用 stringify 运算符#
访问其值:
printf("commit id is " #COMMIT_ID "\n");
- - - 编辑 - - -
请注意,这确实涉及到一个尖锐的问题——特别是,如果您构建一次,然后修改 git 存储库而不修改 foo.c,那么 make 将认为 foo.o 是最新的,并且不会重新构建它,这意味着 foo.o 将在其中包含旧的提交 ID。如果这是一个问题,我将发布第二个答案,说明你如何解决这个问题
你当然可以使用一个make
变量,像这样:
printf("%s\n", COMMIT_ID);
你会有一个类似的Makefile
东西
executable.elf: CFLAGS+=-D'COMMIT_ID="$(shell git rev-parse --verify HEAD)"'
make
(这使用了一些不可移植的GNU特性。)
但是,如果这实际上是可重现的,那可能会更好。为此,也许将值写入文件,以便您可以查看上次编译该项目时使用的内容。
executable.elf: commitid.c
.PHONY: commitid.c
commitid.c:
git rev-parse --verify HEAD \
| sed 's/.*/#define COMMIT_ID "&"/' >$@
然后显然#include "commitid.c"
来自executable.c
或调用任何 C 源文件。
.PHONY
每次都强制重建的宣言commitid.c
有点生硬;也许相反 makecommitid.c
依赖于每个版本控制的文件。
如果 git 存储库发生更改,我的第一个答案不会重建executable.elf
,但您的来源不会。如果您需要在存储库更改时始终重建它,您可以使用一些 makefile 技巧来做到这一点:(可能有更好的方法来做到这一点,如果有人能想到一个,我很想听听) :
首先在你的makefile中做:
$(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 \
)
然后在foo.c
,你只需做一个
#include commitid.h
只要您的 makefile 生成 .d 文件,那么 foo.c 将依赖于 commitid.h,并且如果该文件被更新,它将被重建。(如果没有,请将该行添加foo.c: commitid.h
到您的 makefile 中)。文件本身只会在提交 id 更改时更新,因此 foo.o 只会在必要时重建。