可以“制作”检查依赖项的 mtime 在运行之间是否“不同”,而不仅仅是它是否比目标新?

发布于 2024-08-10 19:53:02 字数 502 浏览 13 评论 0原文

如果 foo_user.cpp 依赖于 foo.h,则构建了 foo_user.cpp,然后将 foo.h 的修改时间设置为更早的时间,make 将不会重建 foo_user.cpp(因为 foo.cpp 是“较新的”)。我更希望 make 记录依赖项的修改时间,并且如果它们发生了根本变化(较新或较旧),则认为该依赖项的目标已过时。 GNU 可以做到这一点吗?如果没有,有没有简单的替代方案?

如果您好奇这种情况是如何发生的:foo.h 驻留在符号链接文件夹中。符号链接可能指向foolib-1.0文件夹、foolib-2.0文件夹等。当符号链接指向库的不同版本(甚至是旧版本)时,应该重新构建foo_user.cpp。如果我只是将 symlinkfolder/foo.h 指定为 foo_user.cpp 的依赖项,则 make 仅关注 foo.h 的时间戳,而不是访问 foo.h 的符号链接目录的时间戳。我无法将符号链接本身添加为依赖项,因为 make 规则是由编译器生成的(GCC 有一个特殊的标志,给定该标志后,它会为源文件依赖的所有标头输出 make 规则)。

If foo_user.cpp depends on foo.h, then foo_user.cpp is built, and then foo.h's modification time is set to further in the past, make will not rebuild foo_user.cpp (because foo.cpp is 'newer'). I'd prefer it if make recorded the modification times of dependencies, and if they changed at all (newer or older), to consider targets of that dependency to be out of date. Can GNU make do this? If not, is there an easy alternative?

In case you're curious how this situation arises: foo.h resides in a symlinked folder. The symlink may point to the foolib-1.0 folder, the foolib-2.0 folder, etc. When the symlink points at a different version of the library, even an older version, foo_user.cpp should be rebuilt. If I simply specifiy symlinkfolder/foo.h as a dependency of foo_user.cpp, make only pays attention to the timestamp of foo.h, not the timestamp of the symlink'd directory through which foo.h is accessed. I can't add the symlink itself as a dependency, because the make rule is generated by the compiler (GCC has a special flag that when given causes it to output a make rule for all the headers a source file depends on).

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

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

发布评论

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

评论(4

瑶笙 2024-08-17 19:53:02

我试图理解为什么你不能只添加符号链接作为依赖项。我想你的自动依赖关系在一行上,但你可以有任意多的依赖关系。

x.o: a.h b.h    
x.o: c.h    
x.o: d.h

但话虽如此,make 似乎会统计符号链接的目标,而不是符号链接本身,因此可能不是 DTRT。我想每当您创建符号链接时您都可以触摸某个文件,但我也想您已经想到了...

您可以有一个运行 ls -id link/ 的规则。 > test,会将链接目标目录的inode号放入test中。然后,您可以cmp test save,其中save来自上次运行。然后你可以让 make 规则执行 make clean &&如果它们不同,则创建目标

targetwrapper: 
    ls -id link/. > test
    cmp test save || make clean
    make realtarget
    cp test save

clean:
    echo cleaned

realtarget:
    echo made

I'm trying to understand why you can't just add the symlink as a dependency. I imagine your automatic dependencies are on one line, but you can have as many as you want.

x.o: a.h b.h    
x.o: c.h    
x.o: d.h

But having said that, it seems likely that make will stat the symlink's target, and not the symlink itself, so that may not DTRT. I suppose you could just touch a file somewhere whenever you make the symlink, but I also suppose you've already thought of that...

You could have a rule that runs ls -id link/. > test, which will put the inode number of the link target directory in test. You could then cmp test save, where save is from the last run. You could then have that make rule do make clean && make target if they are different.

targetwrapper: 
    ls -id link/. > test
    cmp test save || make clean
    make realtarget
    cp test save

clean:
    echo cleaned

realtarget:
    echo made
唐婉 2024-08-17 19:53:02

不,Make 不支持这一点。您可能希望考虑使用其他构建系统,例如 SCons,它不仅仅依赖于时间戳,而且实际上计算 MD5源文件的哈希值并根据哈希值做出决策。

来自“什么让 SCons 变得更好?”在其网站上:

  • 使用 MD5 签名可靠地检测构建更改;对传统时间戳的可选、可配置支持。

No, Make does not support this. You may wish to consider using another build system such as SCons, which does not rely solely on the timestamp but actually computes the MD5 hash of source files and bases its decisions on the hashes.

From "What makes SCons better?" on its web site:

  • Reliable detection of build changes using MD5 signatures; optional, configurable support for traditional timestamps.
慕巷 2024-08-17 19:53:02

虽然 make 不支持开箱即用,但您可以对其进行编程。

include more_deps

ifneq ($(MAKE_RESTARTS),)

more_deps:
  if (foolink.old differs from what foolink points to) ; then \
    readlink foolink > foolink.old ; \
    echo "foo_user: foolink_trigger" > more_deps ; \
    touch foolink_trigger ; \
  else \
    echo "" > more_deps ;\
  fi

endif

foo_user: foo_user.cpp
  g++ $^ -o $@

这里包含 makefile more_deps,其中有时将包含对符号链接触发器的依赖。触发器是一种特殊的中间体,所有有意义的信息都是它的时间戳。当符号链接更改时,触发器的时间戳会更新为当前时间(请参阅touch),从而使 foo_user 过时并重新构建。

计算上述依赖关系后,需要 includeMAKE_RESTARTS 来重新启动 make。如果包含的 makefile 本身就是目标,则认为该目标已重建,重建后 make 重新启动并重新读取 makefile。但是当它第二次读取 makefile 时,它​​不会将 more_deps 视为目标,因为 MAKE_RESTARTS 变量扩展为非空字符串。

事实上,if 语句听起来像这样:

more_deps:
  if (any condition you want with $(VARIABLES) possible!) ; then \
     update a file that holds the previous state ;\ 
     ...

While make doesn't support it out of the box, you can program it.

include more_deps

ifneq ($(MAKE_RESTARTS),)

more_deps:
  if (foolink.old differs from what foolink points to) ; then \
    readlink foolink > foolink.old ; \
    echo "foo_user: foolink_trigger" > more_deps ; \
    touch foolink_trigger ; \
  else \
    echo "" > more_deps ;\
  fi

endif

foo_user: foo_user.cpp
  g++ $^ -o $@

Here you include makefile more_deps which sometimes will include the dependency on the symlink's trigger. Trigger is a special intermediate flie, all the meaningful informaion in which is its timestamp. When the symlink changes, the timestamp of the trigger is updated to current time (see touch), thus making foo_user outdated and it is the rebuilt.

include and MAKE_RESTARTS are needed to restart make after calculating the dependency described above. If the makefile being included is a target itself, the target is considered to be rebuilt, is rebuilt and then make restarts and re-reads makefile. But when it reads makefile for the second time, it doesn't see more_deps as a target, because MAKE_RESTARTS variable expands to non-empty string.

In fact, the line with if can sound like this:

more_deps:
  if (any condition you want with $(VARIABLES) possible!) ; then \
     update a file that holds the previous state ;\ 
     ...
束缚m 2024-08-17 19:53:02

您通过哪个过程更改符号链接?您可以将 make clean 类型的操作添加到更改符号链接的脚本中。

您还可以在其中设置一个“标头工作文件夹”,让 make 复制您的头文件,其中复制的头文件依赖于其原始文件和符号链接。 GCC 生成的依赖项仅考虑工作标头,不会与 Makefile 的将标头复制到工作文件夹部分发生冲突。

Through which process do you change the symlink? You could add a make clean type of action to the script that changes the symlink.

You could also set up a "header working folder" in with you let make copy your header files, where the copied header files are dependent on their original and the symlink. The dependencies generated by GCC only take the working headers into account and won't clash with your copy headers into the working folder part of your Makefile.

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