将Powershell核心设置为默认的GNU Make shell在Windows/linux上



在Windows上的makefile中。

使用以下品牌版本:

PS C:projects> make --version
GNU Make 4.1
Built for i686-w64-mingw32
Copyright (C) 1988-2014 Free Software Foundation, Inc.

我尝试设置SHELL := pwsh/COMSPEC := pwsh并在没有明确 shell 指定的情况下运行命令:

# COMSPEC := pwsh -c
SHELL := pwsh -c
VAR=asdf/asdf
.PHONY: get_var
get_var:
@Write-Output $(VAR)

没有成功。我有一个错误:

PS C:projectsmakefile_factory> make -f .fi.makefile get_var
process_begin: CreateProcess(NULL, Write-Output asdf/asdf, ...) failed.
make (e=2): ═х єфрхЄё  эрщЄш єърчрээ√щ Їрщы.
.fi.makefile:10: recipe for target 'get_var' failed
make: *** [get_var] Error 2

如果在命令中显式指定了 shell,它将起作用:

# COMSPEC := pwsh -c
# SHELL := pwsh -c
VAR=asdf/asdf
.PHONY: get_var
get_var:
@pwsh -c Write-Output $(VAR)

跑:

PS C:projectsmakefile_factory> make -f .fi.makefile get_var
asdf/asdf

另外,我还研究了制作文档:

但是,在MS-DOS和MS-Windows上,SHELL的值在 使用环境,因为在那些系统上大多数用户不设置这个 变量,因此它很可能是专门设置为使用的 通过制造。在MS-DOS上,如果SHELL的设置不适合制作, 您可以将变量 MAKESHELL 设置为制作应该使用的 shell; 如果设置,它将用作外壳而不是外壳的值。

所以我尝试设置环境变量 SHELL/MAKESHELL,但没有结果:

PS C:projectsmakefile_factory> $env:SHELL
C:Program FilesPowerShell7pwsh.exe
PS C:projectsmakefile_factory> $env:MAKESHELL
C:Program FilesPowerShell7pwsh.exe
PS C:projectsmakefile_factory> make -f .fi.makefile get_var
Write-Output asdf/asdf
process_begin: CreateProcess(NULL, Write-Output asdf/asdf, ...) failed.
make (e=2): ═х єфрхЄё  эрщЄш єърчрээ√щ Їрщы.
.fi.makefile:9: recipe for target 'get_var' failed
make: *** [get_var] Error 2

那么,有没有办法将 pwsh 指定为默认外壳?

@raspy说的是真的,但是,我找到了一个光荣的解决方法!

如果你在这里看一下这个if语句,你会注意到,如果shellflags设置为-c-ce以外的内容,它将始终使用慢速选项(这意味着它将始终通过SHELL而不是直接二进制文件执行! 🎉🎉 幸运的是,我们可以直接设置.SHELLFLAGS,看看这些文档

无论如何,这意味着我们需要做的就是将.SHELLFLAGS设置为-c-ce以外的内容,例如,使用powershell,我们可以使用-Command,将它们捆绑在一起:

SHELL := pwsh
.SHELLFLAGS := -Command
VAR=asdf/asdf
.PHONY: get_var
get_var:
@Write-Output $(VAR)

或者,在我的示例中,我想要Windows上的PowerShell.exe和Linux上的默认shell:

ifeq ($(OS),Windows_NT)
SHELL := powershell.exe
.SHELLFLAGS := -NoProfile -Command
endif
test.txt:
echo "hello, world" > test.txt
test:
rm test.txt

干杯!

这并不像人们想象的那么容易。一般来说,GNU make 在决定它必须调用 shell 之前不会真正调用 shell,而是采用快捷方式并尝试直接调用命令(execCreateProcess取决于平台(。

make如何决定是否需要外壳?好吧,它有一个预定义的关键字列表,由特定的shell知道。对于Windows,有一个特定于cmd和Unixy-shell的关键字的单独列表。

现在,什么是Unixy(又名Bourne兼容(shell?嗯,这是另一个预定义的列表:shbashkshrkshzshashdash。请注意,这里没有pwsh

因此,为了让make实际执行 shell,该命令必须包含已知的关键字或字符之一,否则make将尝试直接运行该命令,而不调用 shell。

还有一件事要记住:设置SHELL时,它必须是要通过搜索环境变量解析的文件的完整路径或全名PATH。请注意,PowerShell 的可执行文件pwsh.exe不是pwsh,虽然后者在命令行上工作,但它是命令行解释器尝试不同的扩展,make只是简单地检查文件是否存在。

将以上所有内容相加,我能够按如下方式运行PowerShell:

> Get-Content .Makefile
SHELL := pwsh.exe
VAR=asdf/asdf
.PHONY: get_var
get_var:
@&Write-Output $(VAR)
@$$PSVersionTable

使用新编译的本机 Win32 GNU 进行测试:

> ..make-4.1WinRelgnumake.exe -dr
GNU Make 4.1
Built for Windows32
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile 'Makefile'...
find_and_set_shell() path search set default_shell = C:/Program Files/PowerShell/7/pwsh.exe
Updating makefiles....
Considering target file 'Makefile'.
Looking for an implicit rule for 'Makefile'.
No implicit rule found for 'Makefile'.
Finished prerequisites of target file 'Makefile'.
No need to remake target 'Makefile'.
Updating goal targets....
Considering target file 'get_var'.
File 'get_var' does not exist.
Finished prerequisites of target file 'get_var'.
Must remake target 'get_var'.
CreateProcess(NULL,C:/Program Files/PowerShell/7/pwsh.exe -c "&Write-Output asdf/asdf",...)
Putting child 00B86400 (get_var) PID 12170424 on the chain.
Live child 00B86400 (get_var) PID 12170424
Main thread handle = 0000016C
asdf/asdf
Reaping winning child 00B86400 PID 12170424
CreateProcess(NULL,C:/Program Files/PowerShell/7/pwsh.exe -c $PSVersionTable,...)
Live child 00B86400 (get_var) PID 12193536
Name                           Value
----                           -----
PSVersion                      7.0.0
PSEdition                      Core
GitCommitId                    7.0.0
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
Reaping winning child 00B86400 PID 12193536
Removing child 00B86400 PID 12193536 from chain.
Successfully remade target file 'get_var'.

最新更新