[英]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.有几种情况。
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
代码本身的
TargetFramework
是net5.0
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
.在这种情况下,代码的
TargetFramework
是net472
。 I also assume VS is installed in a standard location, albeit on any drive.我还假设 VS 安装在标准位置,尽管在任何驱动器上。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.