延迟或重复GNU make中的先决条件

时间:2008-12-01 20:39:40

标签: svn makefile

我正在尝试将我的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以使svnversion.o 1}}。

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

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

4 个答案:

答案 0 :(得分:2)

这似乎与autotools为其config.h标题所做的类似。

快速浏览一下automake的remake-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触及了戳文件,而在您的示例中它甚至不是真正的文件。

答案 1 :(得分:2)

这是我放入make文件的目标。它创建了一些函数,将各种构建的telemetreis作为字符串返回。好处是遥测代表最后一次链接,而不是建立一个对象。

##
## 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 $@

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

我通过使用check-svnversion规则删除svnversion.o以强制在需要时重新编译它来解决这个问题。这不是很优雅,但它有效;它看起来类似于CesarB's answer中描述的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