1

我想在编译时在 Makefile 中生成一个变量,并在运行时在我的可执行文件中使用它。

最小示例:在 Makefile 我生成变量COMMIT_ID,其中包含最新提交的 ID:COMMIT_ID=$(git rev-parse --verify HEAD)

Makefile 还会生成一个可执行文件,例如executable.elf. 生成的C源代码executable.elf打印COMMIT_ID.

最好的方法是什么?

4

4 回答 4

2

书呆子狙击手 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}" > $@
于 2021-09-01T18:35:05.937 回答
0

这取决于你的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。如果这是一个问题,我将发布第二个答案,说明你如何解决这个问题

于 2021-09-01T14:49:07.737 回答
0

你当然可以使用一个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依赖于每个版本控制的文件。

于 2021-09-01T15:52:40.807 回答
0

如果 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 只会在必要时重建。

于 2021-09-01T16:00:38.683 回答