简体   繁体   English

Microsoft.Build.Evaluation(快进到 2021 年)的正确用法是什么?

[英]What's the correct usage of Microsoft.Build.Evaluation (fast forward to 2021)?

So the original question What's the correct usage of Microsoft.Build.Evaluation?所以最初的问题Microsoft.Build.Evaluation 的正确用法是什么? has the following accepted answer:有以下公认的答案:

project = new Project(projectPath, new Dictionary<string, string>(), "12.0", new ProjectCollection());

This does not work in 2021 with NuGet package Microsoft.Build 16.8.0.这在 2021 年不适用于 NuGet package Microsoft.Build 16.8.0。

I would like to evaluate a non SDK style project like this:我想像这样评估一个非 SDK 风格的项目:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
...
  <Import Project="..\..\..\Tools\MSBuild\Dayforce.targets" />
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

Please, observe:请注意:

Attempt 1尝试 1

new Project(projectPath, new Dictionary<string, string>(), "16.0", new ProjectCollection());

Results in:结果是:

Microsoft.Build.Exceptions.InvalidProjectFileException: The tools version "16.0" is unrecognized. Available tools versions are "Current".

Attempt 2尝试 2

new Project(projectPath, new Dictionary<string, string>(), "Current", new ProjectCollection());

Results in:结果是:

Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Current\Microsoft.Common.props" was not found. Confirm that the expression in the Import declaration "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Current\Microsoft.Common.props" is correct, and that the file exists on disk.

Attempt 3尝试 3

new Project(projFilePath, new Dictionary<string, string>
{
    ["MSBuildExtensionsPath"] = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild",
}, "Current", new ProjectCollection());

Results in:结果是:

Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Microsoft.CSharp.targets" was not found. Confirm that the expression in the Import declaration "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Microsoft.CSharp.targets" is correct, and that the file exists on disk. 

We are making progress, Microsoft.Common.props seems to have been imported and now we fail on the last import - Microsoft.CSharp.targets我们正在取得进展,Microsoft.Common.props 似乎已被导入,现在我们在最后一次导入时失败 - Microsoft.CSharp.targets

Attempt 4尝试 4

new Project(projFilePath, new Dictionary<string, string>
{
    ["MSBuildExtensionsPath"] = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild",
    ["MSBuildBinPath"] = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin",
}, "Current", new ProjectCollection());

But the result is:但结果是:

System.ArgumentException: The "MSBuildBinPath" property name is reserved.

So, what am I missing?那么,我错过了什么?

I managed to do what I wanted.我设法做我想做的事。 However, none of the Microsoft.Build NuGet packages worked as expected by me.但是, Microsoft.Build NuGet 包都没有按我的预期工作。 I checked all the published versions.我检查了所有已发布的版本。

What worked for me is reference the Microsoft.Build Dlls found inside the VS 2019 installation directory.对我有用的是参考 VS 2019 安装目录中的 Microsoft.Build Dll。 Here is my project file:这是我的项目文件:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  ...

  <ItemGroup>
    <Reference Include="Microsoft.Build">
      <HintPath>..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.Build.Framework">
      <HintPath>..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Framework.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.Build.Utilities.Core">
      <HintPath>..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll</HintPath>
    </Reference>
  </ItemGroup>

</Project>

And here is the code that works:这是有效的代码:

var project = new Project(projFilePath);
foreach (var compileItem in project.AllEvaluatedItems.Cast<ProjectItem>().Where(item => item.ItemType == "Compile"))
{
    var filePath = compileItem.EvaluatedInclude;
    ...
}

I checked the msbuild github repository - it does not use the NuGet packages either.我检查了msbuild github 存储库- 它也不使用 NuGet 包。 Instead it includes the source code for all the relevant libraries and just builds them.相反,它包含所有相关库的源代码并只是构建它们。 And these dlls work too just as the VS dlls work.这些 dll 也可以像 VS dll 一样工作。

So, what is the deal with the NuGet packages?那么,NuGet 包的处理是什么? I do not get it.我不明白这一点。 Opened https://github.com/dotnet/msbuild/issues/6147打开https://github.com/dotnet/msbuild/issues/6147

You need to reference the Microsoft.Build.Utilities.Core NuGet package and also set the MSBUILD_EXE_PATH environment variable to either MSBuild.exe or MSBuild.dll You need to reference the Microsoft.Build.Utilities.Core NuGet package and also set the MSBUILD_EXE_PATH environment variable to either MSBuild.exe or MSBuild.dll

https://web.archive.org/web/20210419051516/https://blog.rsuter.com/missing-sdk-when-using-the-microsoft-build-package-in-net-core/ https://web.archive.org/web/20210419051516/https://blog.rsuter.com/missing-sdk-when-using-the-microsoft-build-package-in-net-core/

After this just create a project:在此之后只需创建一个项目:

var project = new Project("Path\To\Your\Project");

There are couple of scenarios.有几种情况。

  • You want to use the .NET Core SDK installed under C:\Program Files\dotnet .您想使用安装在C:\Program Files\dotnet下的 .NET Core SDK 。 In this case the following code works for me:在这种情况下,以下代码适用于我:
var msbuildDllPath = Path.Combine(sdkPath, "msbuild.dll");
Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", msbuildDllPath);
Environment.SetEnvironmentVariable("MSBuildExtensionsPath32", sdkPath);
Environment.SetEnvironmentVariable("MSBuildExtensionsPath64", sdkPath);
Environment.SetEnvironmentVariable("MSBuildExtensionsPath", sdkPath);

var project = new Project(projectPath, null, "Current", new ProjectCollection(ToolsetDefinitionLocations.Local));

This is the only combination that I could find to work for this scenario.这是我能找到适用于这种情况的唯一组合。 The TargetFramework of the code itself is net5.0代码本身的TargetFrameworknet5.0

  • You want to use the build tools associated with the Visual Studio in the PATH, but it could be 2017 or 2019 or 2017, when also 2019 is installed.您想在 PATH 中使用与 Visual Studio 关联的构建工具,但它可能是 2017 或 2019 或 2017,同时还安装了 2019。 This is a real PITA and the solution is not pretty.这是一个真正的 PITA,解决方案并不漂亮。 Here is what worked for me:这对我有用:
private static (string, string) GetMostRecentMSBuildExePath()
{
    var flavors = new[]
    {
        "Professional",
        "Enterprise",
        "Community",
        "BuildTools",
    };

    string found = null;
    int maxVersion = 2017;
    foreach (var drive in DriveInfo.GetDrives().Where(o => o.DriveType == DriveType.Fixed))
    {
        foreach (var dir in Directory.GetDirectories(drive.Name + "Program Files (x86)\\Microsoft Visual Studio"))
        {
            if (!int.TryParse(dir.Substring(dir.Length - 4), out var version) || version <= maxVersion)
            {
                continue;
            }
            var msbuildExePath = flavors.Select(flavor => dir + "\\" + flavor + "\\MSBuild\\Current\\bin\\msbuild.exe").FirstOrDefault(File.Exists);
            if (msbuildExePath != null)
            {
                maxVersion = version;
                found = msbuildExePath;
            }
        }
    }

    string vsVersion = null;
    if (found != null)
    {
        foreach (var dir in Directory.GetDirectories(found + @"\..\..\..\Microsoft\VisualStudio", "v*"))
        {
            if (Directory.Exists(dir + "\\WebApplications"))
            {
                var index = dir.LastIndexOf("\\");
                vsVersion = dir.Substring(index + 2);
                break;
            }
        }
    }
    return (found, vsVersion);
}

...
// Check if VSINSTALLDIR implicates 2017.
// If not - we are good.
// If yes - search if there is VS 2019 in any of the well known locations.
// If yes - point at it, if no - leave as is.

string toolsVersion = null;
var vsInstallDir = Environment.GetEnvironmentVariable("VSINSTALLDIR");
if (vsInstallDir?.Contains("\\2017\\") == true)
{
    // Bummer. Check if 2019 or up is installed.
    var (msBuildExePath, vsVersion) = GetMostRecentMSBuildExePath();
    if (msBuildExePath == null)
    {
        // Only VS 2017
        toolsVersion = "15.0";
        Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", Path.Combine(vsInstallDir, "MSBuild\\15.0\\bin\\msbuild.exe"));
    }
    else
    {
        toolsVersion = "Current";
        Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", msBuildExePath);
        Environment.SetEnvironmentVariable("VisualStudioVersion", vsVersion);
    }
}

var project = new Project(projectFilePath, null, toolsVersion);

In this case TargetFramework of the code is net472 .在这种情况下,代码的TargetFrameworknet472 I also assume VS is installed in a standard location, albeit on any drive.我还假设 VS 安装在标准位置,尽管在任何驱动器上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法在 VS2017 中使用 Microsoft.Build.Evaluation - Can't use Microsoft.Build.Evaluation in VS2017 使用Microsoft.Build.Evaluation发布数据库项目(.sqlproj) - Using Microsoft.Build.Evaluation to publish a database project (.sqlproj) 使用 Microsoft.Build.Evaluation(而不是 Engine)以编程方式修改 csproj 文件 - Modify programatically csproj files with Microsoft.Build.Evaluation (instead of Engine) 为什么Microsoft.Build.Evaluation在64位PC上将$(ProgramFiles)评估为“ c:\\ program files”? - Why does Microsoft.Build.Evaluation evaluate $(ProgramFiles) as “c:\program files” on 64 bit PC? 如何使用 microsoft.build.evaluation 以编程方式添加新的 dll 参考 - How to add new dll reference programmatically using microsoft.build.evaluation LoadFromCacheOrDownload的正确用法是什么? - What's the correct usage for LoadFromCacheOrDownload? ConcurrentBag的正确用法是什么? - What is the correct usage of ConcurrentBag? 2021 年进行外部提供商登录的正确方法是什么? - What is the correct way to do external provider logins in 2021? 在评估之前编写 not 运算符的正确方法是什么? - What is the correct way to write the not operator preceding the evaluation? MethodInvoker的这种用法的正确语法是什么? - What is the correct syntax for this usage of MethodInvoker?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM