我正在尝试将我的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.h
由update-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两次评估一个先决条件,或者延迟检查先决条件的时间戳,直到该先决条件的命令完成为止?
或者,有没有更好的方法在我的源代码中嵌入修订号? (为了速度,我试图避免在每次构建时需要重新编译的解决方案。)
答案 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