因此原始问题 What's the correct usage of Microsoft.Build.Evaluation? 具有以下可接受的答案:
project = new Project(projectPath, new Dictionary<string, string>(), "12.0", new ProjectCollection());
这在 2021 年不适用于 NuGet 包 Microsoft.Build 16.8.0。
我想像这样评估一个非 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>
请注意:
尝试 1
new Project(projectPath, new Dictionary<string, string>(), "16.0", new ProjectCollection());
结果:
Microsoft.Build.Exceptions.InvalidProjectFileException: The tools version "16.0" is unrecognized. Available tools versions are "Current".
尝试 2
new Project(projectPath, new Dictionary<string, string>(), "Current", new ProjectCollection());
结果:
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.
尝试 3
new Project(projFilePath, new Dictionary<string, string>
{
["MSBuildExtensionsPath"] = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild",
}, "Current", new ProjectCollection());
结果:
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.
我们正在取得进展,Microsoft.Common.props 似乎已被导入,现在我们在最后一次导入时失败 - Microsoft.CSharp.targets
尝试 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());
但结果是:
System.ArgumentException: The "MSBuildBinPath" property name is reserved.
那么,我错过了什么?
我设法做我想做的事。但是,没有一个 Microsoft.Build
NuGet 包按我的预期工作。我检查了所有已发布的版本。
对我有用的是参考在 VS 2019 安装目录中找到的 Microsoft.Build Dll。这是我的项目文件:
<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>
这是有效的代码:
var project = new Project(projFilePath);
foreach (var compileItem in project.AllEvaluatedItems.Cast<ProjectItem>().Where(item => item.ItemType == "Compile"))
{
var filePath = compileItem.EvaluatedInclude;
...
}
我检查了 msbuild github repository - 它也不使用 NuGet 包。相反,它包含所有相关库的源代码并只构建它们。这些 dll 也像 VS dll 一样工作。
那么,NuGet 包是怎么回事?我不明白。打开https://github.com/dotnet/msbuild/issues/6147
答案 0 :(得分:0)
您需要引用 Microsoft.Build.Utilities.Core
NuGet 包并将 MSBUILD_EXE_PATH
环境变量设置为 MSBuild.exe 或 MSBuild.dll
在此之后只需创建一个项目:
var project = new Project("Path\To\Your\Project");
答案 1 :(得分:0)
有几种情况。
C:\Program Files\dotnet
下的 .NET Core SDK。在这种情况下,以下代码适用于我: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));
这是我能找到的唯一适用于这种情况的组合。代码本身的 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);
在这种情况下,代码的 TargetFramework
是 net472
。我还假设 VS 安装在标准位置,尽管在任何驱动器上。