在windows/linux上将Powershell core设置为默认GNU Make shell

在windows/linux上将Powershell core设置为默认GNU Make shell,powershell,makefile,gnu-make,Powershell,Makefile,Gnu Make,在Windows上的makefile中 使用以下make版本: 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 := pws

在Windows上的makefile中

使用以下make版本:

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:\projects\makefile_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)
运行:

此外,我还调查了:

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

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

PS C:\projects\makefile_factory> $env:SHELL
C:\Program Files\PowerShell\7\pwsh.exe
PS C:\projects\makefile_factory> $env:MAKESHELL
C:\Program Files\PowerShell\7\pwsh.exe
PS C:\projects\makefile_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指定为默认shell呢?

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

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

现在,什么是Unixy(又称Bourne兼容)外壳?嗯,这是另一个列表:
sh
bash
ksh
rksh
zsh
ash
dash
。注意此处没有
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进行测试:

> ..\make-4.1\WinRel\gnumake.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'.
..\make-4.1\WinRel\gnumake.exe-dr
GNU Make 4.1
为Windows32构建
版权所有(C)1988年至2014年自由软件基金会。
许可证GPLv3+:GNU GPL版本3或更高版本
这是自由软件:您可以自由更改和重新发布它。
在法律允许的范围内,不存在任何担保。
正在读取生成文件。。。
正在读取makefile“makefile”。。。
查找并设置shell()路径搜索设置默认值shell=C:/Program Files/PowerShell/7/pwsh.exe
正在更新生成文件。。。。
正在考虑目标文件“Makefile”。
正在查找“Makefile”的隐式规则。
找不到“Makefile”的隐式规则。
已完成目标文件“Makefile”的先决条件。
无需重新生成目标“Makefile”。
更新目标。。。。
正在考虑目标文件“get_var”。
文件“get_var”不存在。
已完成目标文件“get_var”的先决条件。
必须重新制作目标“get_var”。
CreateProcess(NULL,C:/Program Files/PowerShell/7/pwsh.exe-C“&写入输出asdf/asdf”,…)
将子项00B86400(获取变量)PID 12170424放置在链上。
活孩子00B86400(获取变量)PID 12170424
主螺纹手柄=0000016C
asdf/asdf
收获获奖儿童00B86400 PID 12170424
CreateProcess(NULL,C:/Program Files/PowerShell/7/pwsh.exe-C$PSVersionTable,…)
活孩子00B86400(获取变量)PID 12193536
名称值
----                           -----
PS7.0.0版
PSEdition核心
GitCommitId 7.0.0
操作系统Microsoft Windows 10.0.18363
Win32NT平台
PSCompatibleVersions{1.0,2.0,3.0,4.0…}
PSRemotingProtocol2.3版
序列化版本1.1.0.1
WSManStack3.0版
收获获奖儿童00B86400 PID 12193536
从链条上拆下子级00B86400 PID 12193536。
已成功重新生成目标文件“get_var”。

@raspy说的是真的,但是,我发现了一个很好的解决办法


如果你看一下,你会注意到如果
外壳标记
被设置为
-c
-ce
之外的值,它将始终使用slow选项(这意味着它将始终通过
SHELL
而不是直接通过二进制文件执行!我不太了解Windows,但我怀疑将选项放入与SHELL相同的变量中是否有效。我将尝试在
SHELL
变量中使用完全限定路径,而不仅仅是
pwsh
,并添加
-c
opt。)调用
.SHELLFLAGS
变量(请注意,您至少需要GNU make 3.82)。如果这不起作用,我不知道…@madsciient,恐怕make对SHELL变量根本没有反应。我收到任何值的输出(甚至我对它进行了注释)也就是说,它总是使用默认的cmd.exe。不幸的是,我不知道Windows。你可以试着在make上询问-w32@gnu.org邮件列表。可能有人在那里提供帮助。请确保包含您正在使用的GNU make版本。好吧,那太好了!但请允许我问一个问题:$$PSVersionTable这里所有内容都清楚,首先t美元是第二个的转义字符。但是写输出中的“&”怎么办?如果没有指定“&”,为什么make会创建子流程CreateProcess(NULL,写输出asdf/asdf,…),如果没有指定,为什么会创建CreateProcess(NULL,C:/Program Files/PowerShell/7/pwsh.exe-C“&写输出asdf/asdf”…),或者为什么会创建CreateProcess(NULL,C:/Program Files/PowerShell/7/pwsh.exe-C)(写入输出a
> ..\make-4.1\WinRel\gnumake.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'.