2

我正在尝试将我的 Subversion 修订号嵌入到 C++ 项目中,并且在设置 GNU make 时遇到问题。我的 makefile 目前看起来像这样:

check-svnversion:
  ../shared/update-svnversion-h.pl

../shared/svnversion.h: check-svnversion

shared/svnversion.o: ../shared/svnversion.h

.PHONY: check-svnversion

svnversion.o取决于svnversion.cpp(通过模式规则)和svnversion.h(明确列出,因为依赖检查由于某种原因没有捡起它)。 svnversion.hupdate-svnversion-h.pl脚本创建和维护(基本上只是运行svnversion并将输出转换为 C++ 文件)。

目前,我必须运行make两次才能使文件保持最新。第一次,make运行update-svnversion-h.pl(因为它被列为先决条件)但不检查svnversion.h之后的时间戳以查看它是否被 更改update-svnversion-h.pl,因此它不会重新制作svnversion.o。第二次,它确实检查了时间戳,update-svnversion-h.pl无论如何都会运行(这次它什么都不做,因为svnversion.h它是最新的),然后重新编译svnversion.cpp为 make svnversion.o

有没有办法告诉 GNU make 两次评估单个先决条件或延迟检查先决条件的时间戳,直到该先决条件的命令完成后?

或者,有没有更好的方法在我的源代码中嵌入修订号?(为了速度,我试图避免在每次构建时都需要重新编译的解决方案。)

4

4 回答 4

2

这似乎类似于autotools对其 config.h 头文件所做的事情。

快速浏览一下 automakeremake-hdr.am就可以看出它是如何做到的:

%CONFIG_H%: %STAMP%
## Recover from removal of CONFIG_HEADER
    @if test ! -f $@; then \
      rm -f %STAMP%; \
      $(MAKE) $(AM_MAKEFLAGS) %STAMP%; \
    else :; fi


%STAMP%: %CONFIG_H_DEPS% $(top_builddir)/config.status
    @rm -f %STAMP%
    cd $(top_builddir) && $(SHELL) ./config.status %CONFIG_H_PATH%

config.status创建印章文件。

这个 automake 示例和您的示例之间的主要区别似乎是 automake 涉及戳文件,而在您的示例中它甚至不是真实文件。

于 2008-12-02T01:20:24.273 回答
2

这是我放入 make 文件中的目标。它创建了几个函数,这些函数将各种构建遥测作为字符串返回。好消息是遥测代表上次链接的时​​间,而不是构建对象的时间。

##
## on every build, record the working copy revision string
##
svn_version.c: $(C_SRC:.c=.o) Makefile
    @echo -n 'const char* build_date(void);\n'  > $@
    @echo -n 'const char* build_date(void)\n{ static const char* build_date = __DATE__ ; '  >> $@
    @echo 'return build_date; }\n'                                                          >> $@
    @echo -n 'const char* build_time(void);\n'                                              >> $@
    @echo -n 'const char* build_time(void)\n{ static const char* build_time = __TIME__ ; '  >> $@
    @echo 'return build_time; }\n'                                                          >> $@
    @echo -n 'const char* svnid_build(void);\n'                                             >> $@
    @echo -n 'const char* svnid_build(void)\n{ static const char* SVN_Version = "\\n<SVN_PID>'    >> $@
    @svnversion -cn .                                                                       >> $@
    @echo '</svn_pid>\\n"; return SVN_Version; }\n'                                         >> $@
    @echo -n 'const char* svnid_build_str_only(void);\n'                                    >> $@
    @echo -n 'const char* svnid_build_str_only(void)\n{ static const char* SVN_Version = "' >> $@
    @svnversion -cn .                                                                       >> $@
    @echo '"; return SVN_Version; }\n'                                                      >> $@
    @$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $(@:.c=.o) $@

确保用简单的“svn_version.c”替换对最终目标中目标文件的依赖。前任。

final-target: svn_version.c
    $(CC) $(C_SRC:.c=.o) $(<:.c=.o) -o $@
于 2009-09-28T14:47:07.640 回答
1

您可以使用 Subversion 的关键字替换将版本号放入您的代码中。

[在书中] 很详细,但简而言之,您必须设置svn:keywords要包含的文件的属性,Rev然后将其$Rev$放在代码中的某个位置。SVN 会自动将其替换为$Rev: #$,其中#是修订号。您必须解析结果字符串以获取您的实际数字,但它应该很容易解析(只需删除前六个字符和最后一个字符)。

请注意,这是该文件的最后更改版本,而不是 repo 的最后更改版本。这在书页上稍微复杂和详细。

于 2008-12-01T20:58:37.033 回答
1

我通过让我的 check-svnversion 规则删除 svnversion.o 来解决这个问题,以便在需要时强制重新编译它。这并不完全优雅,但它有效;它看起来类似于CesarB 的回答中描述的 autotools 解决方案。

../shared/svnversion.h: check-svnversion

check-svnversion:
    ../shared/update-svnversion-h.pl
    @#Force recreation of svnversion.o.  Otherwise, make won't notice that
    @#svnversion.h has changed until the next time it's invoked.
    @if [ ../shared/svnversion.h -nt shared/svnversion.o ] ; then rm shared/svnversion.o ; fi

shared/svnversion.o: ../shared/svnversion.h

.PHONY: check-svnversion
于 2008-12-02T20:03:52.947 回答