msvc build powershell 环境

2022/1/27

VS2019 开始 VS 中自带 “Developer PowerShell for VS 2019” 快捷方式,通过查看该快捷方式的属性,知道它最终是执行下面的指令:

C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -noe -c "&{Import-Module """C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"""; Enter-VsDevShell cea5fbfc}"
1

很明显,微软提供了一个 powershell 组件 “Microsoft.VisualStudio.DevShell.dll” 来实现初始化VC编译环境,该组件提供了一个方法叫 “Enter-VsDevShell”,从文本的意义来看就是 “进入VS开发环境” 的意思。然而,最后面的一串 “cea5fbfc” 瞎猜可能是产品 ID 吧,先不管它。接下来我把研究对象放在 “Microsoft.VisualStudio.DevShell.dll” 这个组件上。

为了方便,我使用 PowerShell ISE 进行调试,首先,导入 “Microsoft.VisualStudio.DevShell.dll” 这个模块。

$vsPath="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"
Import-Module ("$vsPath\Common7\Tools\Microsoft.VisualStudio.DevShell.dll")
1
2

再执行 Get-Module,确认模块已经成功加载:

PS D:\Users\hugo> Get-Module

ModuleType Version    Name                                ExportedCommands                             ---------- -------    ----                                ----------------                             Script     1.0.0.0    ISE                                 {Get-IseSnippet, Import-IseSnippet, New-IseSnippet} 
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Computer, Add-Content, Checkpoint-Computer, ...
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Ob...
Binary     16.0.0.0   Microsoft.VisualStudio.DevShell     {Enter-VsDevShell, Send-VsDevShellTelemetry}  
1
2
3
4
5
6

可以看到 “Microsoft.VisualStudio.DevShell.dll” 有两个方法,分别是 “Enter-VsDevShell” 与 "Send-VsDevShellTelemetry"。

执行 help Enter-VsDevShell,看看有什么帮助:

PS D:\Users\hugo> help Enter-VsDevShell

名称
    Enter-VsDevShell
语法
    Enter-VsDevShell  [<CommonParameters>]
    Enter-VsDevShell [-VsInstanceId] <string>  [<CommonParameters>]
    Enter-VsDevShell  [<CommonParameters>]
别名
    无
备注
    无
1
2
3
4
5
6
7
8
9
10
11
12

帮助信息中有价值的就只有 -VsInstanceId ,估计就是那个 “cea5fbfc” 了。可我从哪得到这个值呢?不同的产品可能有不同的值吧。总不能把 VS 的各个版本装一遍吧?

在 PowerShell ISE中,当加载完 “Microsoft.VisualStudio.DevShell.dll” 模块后,点击右侧的“命令”辅助工具页中的“刷新”按钮。然后在“模块”下拉列表中可以找到 “Microsoft.VisualStudio.DevShell.dll” 模块,同时下面列出了两个方法。点击“Enter-VsDevShell” 方法,在下面出现了可供调用的参数。其中有一个“VsInstallPath”参数,猜测这个应该是填入VS的安装目录,于是填入"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools",然后点击下方的“运行”按钮执行,呵呵,果然进入了VC的环境了。对应的命令如下:

PS D:\Users\hugo> Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"
**********************************************************************
** Visual Studio 2022 Developer PowerShell v17.0.5
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************
1
2
3
4
5

执行 ls env: 命令,果然看到了跟执行 vcvars32.bat 后一样的环境变量。

到这里,基本有思路了。执行 Enter-VsDevShell 方法时不要用 -VsInstanceId 参数,而是使用 -VsInstallPath,这样更好理解。

问题来了,以上方法进入的是 x86 的编译环境,如果要进入 x64 位的呢?靠,微软提供的“开始菜单”中并没有 x64 位的 powershell 快捷方式!

从 PowerShell ISE 的命令帮助页中可以看到有个 DevCmdArguments 参数,猜测应该是通过这个传入,可是要传入什么值呢?

尝试执行:

Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise" -DevCmdArguments x64
1

出现如下错误信息:

**********************************************************************
** Visual Studio 2019 Developer PowerShell v16.4.5
** Copyright (c) 2019 Microsoft Corporation
**********************************************************************
Enter-VsDevShell : [ERROR:parse_cmd.bat] Invalid command line argument: 'x64'. Argument will be ignored.
[ERROR:VsDevCmd.bat] *** VsDevCmd.bat encountered errors. Environment may be incomplete and/or incorrect. ***
[ERROR:VsDevCmd.bat] In an uninitialized command prompt, please 'set VSCMD_DEBUG=[value]' and then re-run 
[ERROR:VsDevCmd.bat] vsdevcmd.bat [args] for additional details.
[ERROR:VsDevCmd.bat] Where [value] is:
[ERROR:VsDevCmd.bat]    1 : basic debug logging
[ERROR:VsDevCmd.bat]    2 : detailed debug logging
[ERROR:VsDevCmd.bat]    3 : trace level logging. Redirection of output to a file when using this level is reco
mmended.
[ERROR:VsDevCmd.bat] Example: set VSCMD_DEBUG=3
[ERROR:VsDevCmd.bat]          vsdevcmd.bat > vsdevcmd.trace.txt 2>&1
所在位置 行:1 字符: 1
+ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Vis ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Enter-VsDevShell], Exception
    + FullyQualifiedErrorId : DevCmdError,Microsoft.VisualStudio.DevShell.Commands.EnterVsDevShellCommand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

好吧。搞了半天,原来它最终也是调用 VsDevCmd.bat 这个原始的批处理脚本。我们来理一理。

首先,快捷方式 “x64 Native Tools Command Prompt for VS 2022” 执行下面的指令:

%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
1

打开 vcvars64.bat 这个文件,里面只有一句:

@call "%~dp0vcvarsall.bat" x64 %*
1

打开同目录下的 vcvarsall.bat 文件,看到其中一段代码:

call "%~dp0..\..\..\Common7\Tools\vsdevcmd.bat" %__VCVARSALL_VSDEVCMD_ARGS%
1

呵呵,它最终调用的也是 vsdevcmd.bat 这个脚本,而其中的 %__VCVARSALL_VSDEVCMD_ARGS% 就是要传入的参数。

接下来,我略为修改一下 vcvarsall.bat 这个脚本,在这一句上面打印出 %__VCVARSALL_VSDEVCMD_ARGS% 变量的值。

echo %__VCVARSALL_VSDEVCMD_ARGS%
pause
exit
call "%~dp0..\..\..\Common7\Tools\vsdevcmd.bat" %__VCVARSALL_VSDEVCMD_ARGS%
1
2
3
4

保存后,分别执行 “开始菜单” 中的 “x64 Native Tools Command Prompt for VS 2022” 与 “x86 Native Tools Command Prompt for VS 2022”,分别得到以下信息:

-arch=x64 -host_arch=x64
-arch=x86 -host_arch=x86
1
2

呵呵,这就是我们想要的参数。【记得把 vcvarsall.bat 这个脚本恢复原样!】

接下来,我们可以分别通过调用如下指令:

Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" -DevCmdArguments "-arch=x64 -host_arch=x64"
Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" -DevCmdArguments "-arch=x86 -host_arch=x86"
1
2

分别进入 x64 或 x86 版本的 VC 编译环境了。

最后,发现一个问题,执行完上面的命令后,我们的当前工作目录改变了。从 PowerShell ISE 的命令帮助页中可以看到有个 SkipAutomaticLocation 参数,用上它。

Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" -DevCmdArguments "-arch=x64 -host_arch=x64" -SkipAutomaticLocation
1

果然不会改变当前工作目录了。总结起来就是一切靠猜!!!!

Last Updated: 2023-10-29T08:26:04.000Z