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

发布于 2024-07-10 07:45:12 字数 1098 浏览 4 评论 0原文

我正在尝试将我的 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 的时间戳code> 之后查看它被 update-svnversion-h.pl 更改,因此它不会重新制作 svnversion.o。 第二次,它会检查时间戳,无论如何都会运行 update-svnversion-h.pl (这次不会执行任何操作,因为 svnversion.h 已达到date),然后重新编译 svnversion.cpp 生成 svnversion.o

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

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

I'm trying to embed my Subversion revision number in a C++ project and am having problems setting up GNU make to do so. My makefile currently looks something like this:

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

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

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

.PHONY: check-svnversion

svnversion.o depends on svnversion.cpp (via a pattern rule) and svnversion.h (listed explicitly because dependency checking isn't picking it up for some reason). svnversion.h is created and maintained by the update-svnversion-h.pl script (which basically just runs svnversion and munges the output into a C++ file).

Currently, I have to run make twice to get the file up to date. The first time, make runs update-svnversion-h.pl (since it's listed as a prerequisite) but does not check the timestamp of svnversion.h afterwards to see that it was changed by update-svnversion-h.pl, so it does not remake svnversion.o. The second time, it does check the timestamp, runs update-svnversion-h.pl anyway (which doesn't do anything this time, since svnversion.h is up to date), then recompiles svnversion.cpp to make svnversion.o.

Is there a way to tell GNU make to evaluate a single prerequisite twice or to delay checking the timestamp on a prerequisite until after that prerequisite's commands are finished?

Alternatively, is there a better way to embed a revision number in my source code? (For the sake of speed, I'm trying to avoid solutions that would require recompilation on every build.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

提赋 2024-07-17 07:45:12

这看起来类似于 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 涉及标记文件,而在您的示例中它甚至不是真正的文件。

This seems similar to what autotools does for its config.h header.

A quick look at automake's remake-hdr.am shows how it does the trick:

%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%

And config.status creates the stamp file.

The main difference between this automake example and your example seems to be that automake touches the stamp file, while in your example it is not even a real file.

穿越时光隧道 2024-07-17 07:45:12

这是我放入 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 $@

Here is a target I put in my make files. It creates a couple of functions that return various build telemetreis as strings. The nice thing being that the telemetries represent the last time linked, not when an object is built.

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

Be sure to replace the dependancy on the your object files in your final target with simply 'svn_version.c'. Ex.

final-target: svn_version.c
    $(CC) $(C_SRC:.c=.o) $(<:.c=.o) -o $@
究竟谁懂我的在乎 2024-07-17 07:45:12

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

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

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

You can use Subversion's keyword substitution to put the version number into your code.

It's detailed [in the book], but in short you will have to set the svn:keywords property for the file to include Rev and then put $Rev$ somewhere in your code. SVN will automatically replace this with $Rev: #$, where # is the revision number. You mat have to parse the resulting string to get your actual number, but it should be an easy parse (just drop the first six characters and the last character).

Note that this is the last changed revision of that file, not the repo's last changed revision. That is slightly more complex and detailed on the book page.

淡水深流 2024-07-17 07:45:12

我通过让 check-svnversion 规则删除 svnversion.o 来强制它在需要时重新编译来解决这个问题。 这不太优雅,但很有效; 它看起来类似于 CesarB 的回答。

../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

I solved this by having my check-svnversion rule delete svnversion.o to force it to be recompiled if needed. This isn't exactly elegant, but it works; it looks similar to the autotools solution described in CesarB's answer.

../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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文