运行 makefile 中的命令并将 STDERR / STDOUT 打印到终端和文本文件
Run a command in a makefile and print STDERR / STDOUT to both the terminal and a text file
首先,我在 Windows10 上使用 GNU Make 4.3。我之前尝试过 GNU Make 4.2.1,结果与 4.3 完全相同。
无论如何,我有一个非常简单的 makefile,它只做(或至少打算做)一个简单的命令 运行 并将该命令的输出(stderr 和 stdout)打印到终端和文本文件。
$(info $$(MAKECMDGOALS) is "$(MAKECMDGOALS)". $$(SHELL) is \
"$(SHELL)". $$(MAKESHELL) is "$(MAKESHELL)". $$(COMSPEC) is "$(COMSPEC)". $$(OS) is "$(OS)".)
TEE := C:\tools\UnixTools\usr\local\wbin\tee.exe
LOG_FILE := C:\Temp\loggy__.txt
.PHONY : meep
all : meep
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
$(shell dir 2>&1 | $(TEE) $(LOG_FILE))
最后一行给我带来了麻烦。有两件事 运行 与我的预期相反:
虽然 $(shell ...)
调用确实将 dir
命令的输出打印到我的文本文件和终端,但终端上的输出格式很奇怪。通常情况下,dir
每行打印一个元素,这里我将整个输出放在一行中,所以 GNU Make(或其他东西)似乎在显示之前以某种方式从输出中删除了换行符航站楼 window.
此外,我收到一条 The system cannot find the file specified.
错误消息(和往常一样,Windows 不够好,无法告诉我它找不到哪个文件). 运行 echo %errorlevel%
在同一个 CMD shell 中,我 运行 GNU Make 确认 Make 调用出错(退出状态为 2)。
奇怪的是,如果我直接在 CMD window 中 运行 命令 dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt
,一切都完全按照预期运行,没有任何错误,所以我在想GNU Make 的 $(shell ...)
功能有问题,或者我使用错误。有没有人发现我尝试使用 $(shell ...)
函数的方式有些愚蠢?
我刚刚在我的 make 调用中添加了 --debug=a 以获得额外的调试输出,我在输出中发现了以下内容:
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Batch file contents:
@echo off
dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,...)
Main thread handle = 00000000000000B4
Cleaning up temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat
Batch file contents:
@echo off
Volume in drive C is Windows Volume Serial Number is 045A-E422 Directory of C:\tools\UnixTools\usr\local\wbin (... the rest of the output)
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,...)
所以 GNU Make 的 $(shell ...)
函数似乎以某种方式将 dir
调用产生的输出解释为它需要 运行 的附加命令,当然这是无稽之谈。
使用 $(shell)
在这里是废话。 make
完全按照您的指示行事。
正确的解决方案是不在没有意义的地方添加 $(shell ...)
函数调用。
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
dir 2>&1 | $(TEE) $(LOG_FILE)
当然,在食谱中使用 $(info ...)
可能是假的。在每个食谱中,您 运行 正在 shell;使用 shell 的语法打印诊断消息。
meep:
@echo Making meep. >&2
@echo Running command '{dir 2>&1 | $(TEE) $(LOG_FILE)}.' >&2
dir 2>&1 | $(TEE) $(LOG_FILE)
更好的是,不要 运行 make -s
并让 make
自己打印它是什么命令 运行ning,就像默认情况下那样(如果你不在你的 Makefile 中添加 @
之前的所有命令,以使其更难调试)。
首先,我在 Windows10 上使用 GNU Make 4.3。我之前尝试过 GNU Make 4.2.1,结果与 4.3 完全相同。
无论如何,我有一个非常简单的 makefile,它只做(或至少打算做)一个简单的命令 运行 并将该命令的输出(stderr 和 stdout)打印到终端和文本文件。
$(info $$(MAKECMDGOALS) is "$(MAKECMDGOALS)". $$(SHELL) is \
"$(SHELL)". $$(MAKESHELL) is "$(MAKESHELL)". $$(COMSPEC) is "$(COMSPEC)". $$(OS) is "$(OS)".)
TEE := C:\tools\UnixTools\usr\local\wbin\tee.exe
LOG_FILE := C:\Temp\loggy__.txt
.PHONY : meep
all : meep
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
$(shell dir 2>&1 | $(TEE) $(LOG_FILE))
最后一行给我带来了麻烦。有两件事 运行 与我的预期相反:
虽然
$(shell ...)
调用确实将dir
命令的输出打印到我的文本文件和终端,但终端上的输出格式很奇怪。通常情况下,dir
每行打印一个元素,这里我将整个输出放在一行中,所以 GNU Make(或其他东西)似乎在显示之前以某种方式从输出中删除了换行符航站楼 window.此外,我收到一条
The system cannot find the file specified.
错误消息(和往常一样,Windows 不够好,无法告诉我它找不到哪个文件). 运行echo %errorlevel%
在同一个 CMD shell 中,我 运行 GNU Make 确认 Make 调用出错(退出状态为 2)。
奇怪的是,如果我直接在 CMD window 中 运行 命令 dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt
,一切都完全按照预期运行,没有任何错误,所以我在想GNU Make 的 $(shell ...)
功能有问题,或者我使用错误。有没有人发现我尝试使用 $(shell ...)
函数的方式有些愚蠢?
我刚刚在我的 make 调用中添加了 --debug=a 以获得额外的调试输出,我在输出中发现了以下内容:
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Batch file contents:
@echo off
dir 2>&1 | C:\tools\UnixTools\usr\local\wbin\tee.exe C:\Temp\loggy__.txt
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat,...)
Main thread handle = 00000000000000B4
Cleaning up temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-1.bat
Creating temporary batch file C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat
Batch file contents:
@echo off
Volume in drive C is Windows Volume Serial Number is 045A-E422 Directory of C:\tools\UnixTools\usr\local\wbin (... the rest of the output)
CreateProcess(C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,C:\Users\mkemp\AppData\Local\Temp\make23400-2.bat,...)
所以 GNU Make 的 $(shell ...)
函数似乎以某种方式将 dir
调用产生的输出解释为它需要 运行 的附加命令,当然这是无稽之谈。
使用 $(shell)
在这里是废话。 make
完全按照您的指示行事。
正确的解决方案是不在没有意义的地方添加 $(shell ...)
函数调用。
meep :
$(info Making meep.)
$(info Running command {dir 2>&1 | $(TEE) $(LOG_FILE)}.)
dir 2>&1 | $(TEE) $(LOG_FILE)
当然,在食谱中使用 $(info ...)
可能是假的。在每个食谱中,您 运行 正在 shell;使用 shell 的语法打印诊断消息。
meep:
@echo Making meep. >&2
@echo Running command '{dir 2>&1 | $(TEE) $(LOG_FILE)}.' >&2
dir 2>&1 | $(TEE) $(LOG_FILE)
更好的是,不要 运行 make -s
并让 make
自己打印它是什么命令 运行ning,就像默认情况下那样(如果你不在你的 Makefile 中添加 @
之前的所有命令,以使其更难调试)。