为 NuGet 指定检测的 MSBuild 路径或版本,解决 MSBuild auto-detection: using msbuild version 自动查找路径不合适的问题

使用 nuget restore 命令还原项目的 NuGet 包的时候,NuGet 会尝试自动检测计算机上已经安装的 MSBuild。不过,如果你同时安装了 Visual Studio 2017 和 Visual Studio 2019,那么 NuGet 有可能找到错误版本的 MSBuild。

本文介绍如何解决自动查找版本错误的问题。


问题

当我们敲下 nuget restore 命令的时候,命令行的第 2 行会输出自动检测到的 MSBuild 版本号,就像下面的输出一样:

NuGet Version: 5.0.2.5988
MSBuild auto-detection: using msbuild version ‘15.9.21.664’ from ‘C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin’. Use option -MSBuildVersion to force nuget to use a specific version of MSBuild.

实际上我计算机上同时安装了 Visual Studio 2017 和 Visual Studio 2019,我有两个不同版本的 MSBuild:

要让 NuGet 找到正确版本的 MSBuild.exe,我们有三种方法。

使用命令行参数解决

实际上前面 nuget restore 命令的输出中就已经可以看出来其中一个解决方法了,即使用 -MSBuildVersion 来指定 MSBuild 的版本号。

虽然命令行输出中推荐使用了 -MSBuildVersion 选项来指定 MSBuild 的版本,但是实际上实现同样功能的有两个不同的选项:

当同时指定上面两个选项时,-MSBuildPath 选项优先级高于 -MSBuildVersion 选项。

于是我们的 nuget restore 命令改成这样写:

> nuget restore -MSBuildPath "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin"

输出现在会使用期望的 MSBuild 了:

Using Msbuild from 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin'.

修改环境变量解决

NuGet 的命令行自动查找 MSBuild.exe 时,是通过环境变量中的 PATH 变量来找的。会找到 PATH 中第一个包含 msbuild.exe 文件的路径,将其作为自动查找到的 MSBuild 的路径。

所以,我们的解决方法是,如果找错了,我们就把期望正确的 MSBuild 所在的路径设置到不期望的 MSBuild 路径的前面。就像下图这样,我们把 2019 版本的 MSBuild 设置到了 2017 版本的前面。

设置环境变量

以下是 NuGet 项目中自动查找 MSBuild.exe 文件的方法,源代码来自 https://github.com/NuGet/NuGet.Client/blob/2b45154b8568d6cbf1469f414938f0e3e88e3704/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs#L986

private static string GetMSBuild()
{
    var exeNames = new [] { "msbuild.exe" };

    if (RuntimeEnvironmentHelper.IsMono)
    {
        exeNames = new[] { "msbuild", "xbuild" };
    }

    // Try to find msbuild or xbuild in $Path.
    var pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(new[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);

    if (pathDirs?.Length > 0)
    {
        foreach (var exeName in exeNames)
        {
            var exePath = pathDirs.Select(dir => Path.Combine(dir, exeName)).FirstOrDefault(File.Exists);
            if (exePath != null)
            {
                return exePath;
            }
        }
    }

    return null;
}

我故意在桌面上放了一个老旧的 MSBuild.exe,然后将此路径设置到环境变量 PATH 的前面,出现了编译错误。

编译错误


参考资料

blog bulletin

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/specify-msbuild-version-for-nuget-command-line.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,或者前往 CSDN 关注我的主页

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)