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 互斥锁”前配方并在后配方中释放它。
如果需要的话,我可以修改我们的每个目标。
最佳答案
您可以将配方的所有输出记录在一个临时文件中,并在最后将其删除:
%.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 变量在列表中的所有命令中都可用。< - 命令使用
&&
运算符链接起来:如果一个失败,则整个列表失败并具有相同的退出状态,make 会告诉您。 - 我没有将所有命令放在同一行,这很快就变得难以阅读了,我在除最后一行以外的所有行尾之前添加了
\
。更具可读性,但仍被 make 解释为单行。 - 列表中的第一个命令 (
mktemp
) 自动创建一个唯一的临时文件。使用您的环境中可用的任何等效项。注意d=$$(mktemp)
中的双$
。需要通过 make 传递第一次展开,传递给 shell 时变成d=$(mktemp)
。引用 shell 变量d
的 shell 扩展时相同:$$d
在传递给 shell 之前首先被 make 扩展为$d
. - 命令输出的重定向(
>> $d 2>&1
after first expansion by make)将标准输出重定向到附加模式的临时文件(>> $ d
) 并使标准错误描述符成为标准输出描述符 (2>&1
) 的拷贝,其效果是将标准错误附加到同一个临时文件。
关于c++ - GNU make 3.81 - 如何做 '--output-sync=target',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37949528/