我的Makefile
运行程序中的一些目标,其输出(发送到stdout
)我感兴趣。出于我不知道的原因,make
的作者决定将执行的命令回显给stdout
,后者会污染后者。
建议here提出了一个涉及交换文件描述符的问题。我想知道是否有更简单的方法强制make
回显stderr
。
我查看了man
的{{1}}页面,但除了make
选项之外,没有找到任何结果。我更喜欢保留命令的回声,但是在-s
。
我也试过制作一个辅助目标(我做了所有其他目标的先决条件),我把它放在:
stderr
但是bash抱怨说3不是有效的文件描述符。我只试过exec 3>&2
exec 2>&1
exec 1>&3
,但这没有任何影响...
答案 0 :(得分:1)
make的原因显示stdout上的命令行是因为它是制作所需的POSIX标准,并且有30多年的历史预期。请参阅http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html并搜索" STDOUT"。
部分您无法在配方中修改make程序中的文件描述符,因为配方是在子shell中运行的:您对文件描述符所做的任何更改仅在子shell中生效。在UNIX中,子进程无法修改其父进程的文件描述符。
同样,make中配方中的每个行都在不同的子shell中运行。如果你想做一些奇特的事情,比如为食谱重定向输出,你必须把它全部写在一行:
exec 3>&2; exec 2>&1; exec 1>&3; <my command here>
当然,如果你打算这么做我会把它放在一个make变量中,而是使用那个变量。
没有办法让make将其输出写入stderr而不是stdout,除非你想修改GNU make的源代码并使用你自己构建的版本。只要您使用较新版本的GNU make(4.0及更高版本),就可以直接执行此操作,因为所有输出都是从一个plase(output.c
)生成的。
答案 1 :(得分:1)
如果你不想污染make产生的回声输出,你不能简单地运行
make -n >&2 && make -s
这是示例Makefile:
all:
ls
echo done
以下是make
的输出:
ls Makefile echo done done
以下是make -n >&2 && make -s
的输出:
ls echo done Makefile done
当然,任何一步的输出都可以重定向到文件。
答案 2 :(得分:1)
你可以在Makefile
中完全做到这一点:
define REDIR
@printf 1>&2 "%s\n" '$(1)'; $(1)
endef
.PHONY: all
all:
$(call REDIR,echo updating .stamp)
$(call REDIR,touch .stamp)
也就是说,控制命令通过宏回显自己。不幸的是,它涉及将您的食谱行编写为`$(call ...)语法。
REDIR
现在实现了回显命令并通过宏扩展执行它的语义。
1>&2
是特定于Bash的语法,用于将标准错误文件描述符复制到标准输出,因此该命令可以有效地打印到标准输出。
试运行:
$ make
echo updating .stamp
updating .stamp
touch .stamp
$ make 2> /dev/null
updating .stamp
正如您所看到的,updating .stamp
,它是我们明确编码的echo
行的输出,很好地转到标准输出。这些命令被隐式发送到标准错误。
答案 3 :(得分:0)
假设我们有以下Makefile
:
target-1:
target-1-body
target-2:
target-2-body
target-3:
target-3-body
我们按如下方式更改:
target-1-raw:
target-1-body
target-2-raw:
target-2-body
target-3-raw:
target-3-body
%-raw:
echo "Error: Target $@ does not exist!"
%:
@make $@-raw 3>&2 2>&1 1>&3
调用与以前相同,例如make target-1
。
我们将另外两个目标make
输出到stderr
。
仅供参考:我trying进一步开发此解决方案,以便用户无法直接调用原始目标。