【问题标题】:GNU make 3.81 - how to do '--output-sync=target'GNU make 3.81 - 如何做'--output-sync = target'
【发布时间】:2016-10-23 07:16:41
【问题描述】:

最新版本的make 有一个选项--output-sync 可以使每个目标的STDOUT 原子化,这样在使用make --jobs=N 时来自多个目标的语句不会交错

很遗憾,我必须使用make v 3.81,因为这是我们的 SDK 附带的。

为了确定我是否需要--output-sync,我在我的目标周围添加了一些“保护声明”

all: $(patsubst %.cpp, %.o, $(wildcard *.cpp))


%.o: %.cpp  
    @echo BEFORE
    @echo MAKEFLAGS=$(MAKEFLAGS)
    qcc.exe $(CC_FLAGS) $@ $< 
    @echo AFTER

输出非常交错。

AFTER
BEFOREAFTER
AFTER
AFTER

有没有办法模拟--output-sync 功能?

我知道构建速度可能会受到影响,例如,如果有一种方法可以“锁定 STDOUT 互斥体”预配方并在配方后释放它。

如果需要,我可以修改我们的每个目标。

【问题讨论】:

  • 不使用-j 选项?这将避免交错,并且在不修改 makefile 的情况下很容易做到,并且大致相当于您计划做的任何事情,只是更容易。该功能仅在 GNU Make 4.2 中吗? GNU Make 4.2.1 是否解决了您在 4.2 中遇到的问题?
  • @JonathanLeffler 我必须使用-j 来获得并行构建。我会更新关于make 版本的帖子。

标签: c++ makefile gnu-make


【解决方案1】:

您可以将配方的所有输出记录在一个临时文件中,并在最后删除它:

%.o: %.cpp
    @d=$$(mktemp) && \
    echo BEFORE >> $$d 2>&1 && \
    echo MAKEFLAGS=$(MAKEFLAGS) >> $$d 2>&1 && \
    qcc.exe $(CC_FLAGS) $@ $< >> $$d 2>&1 && \
    echo AFTER >> $$d 2>&1 && \
    cat $$d && \
    rm $$d

这不会完全防止交错,因为如果您有多个 CPU,则可以并行运行多个 cat 命令,但应该会显着降低这种可能性。如果你真的想完全避免交错,你将不得不在cat 命令周围添加一个自旋锁。在 GNU/Linux 操作系统下,您可以查看 flock,例如:

%.o: %.cpp
    @d=$$(mktemp) && \
    echo BEFORE >> $$d 2>&1 && \
    echo MAKEFLAGS=$(MAKEFLAGS) >> $$d 2>&1 && \
    qcc.exe $(CC_FLAGS) $@ $< >> $$d 2>&1 && \
    echo AFTER >> $$d 2>&1 && \
    flock /tmp/my-lock-file cat $$d && \
    rm $$d

说明:

  • 我在一次 shell 调用中转换了您的配方(make 配方中的每一行都在不同的 shell 中执行),这样d shell 变量在列表中的所有命令中都可用。
  • 这些命令使用&amp;&amp; 运算符链接起来:如果一个失败,整个列表都会失败,退出状态相同,make 会告诉你。
  • 我没有将所有命令放在同一行,这很快就会变得不可读,而是在除最后一行之外的所有行尾之前添加了\。更具可读性,但仍被 make 解释为单行。
  • 列表中的第一个命令 (mktemp) 自动创建一个唯一的临时文件。使用您的环境中可用的任何等效项。注意d=$$(mktemp) 中的双$。需要通过 make 传递第一个扩展,并在传递到 shell 时变为 d=$(mktemp)。引用 shell 变量 d 的 shell 扩展时相同:$$d 在传递给 shell 之前首先由 make 扩展为 $d
  • 命令输出的重定向(&gt;&gt; $d 2&gt;&amp;1在第一次被make扩展后)将标准输出重定向到附加模式的临时文件(&gt;&gt; $d),并使标准错误描述符成为标准输出描述符的副本(2&gt;&amp;1) 的效果是将标准错误也附加到同一个临时文件中。

【讨论】:

  • 为了避免混淆配方,我会创建一个脚本来处理输出序列化,并在生成文件中使用该脚本作为SHELL。同样在某些情况下,.ONESHELL 可能会有所帮助。
  • 我不敢相信这个问题如此受欢迎,因为gnu make 3.81 真的很老了!这么多开发者还在使用它吗?
  • @Adrian 是的,它在我正在使用的集群系统上,我对此无能为力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 2015-11-01
  • 2023-03-24
  • 1970-01-01
  • 2023-04-09
  • 2021-02-16
相关资源
最近更新 更多