我的团队也有类似的需求,因此我编写了一个 C# Builder 库,支持多个版本的 Visual Studio。
我无法使Project.Build功能正常工作,所以我直接执行MsBuild.exe。
我是如何构建它的:
使用 Microsoft.Build.Framework 从NuGet https://www.nuget.org/packages/Microsoft.Build.Framework/
创建一个新的 Project 对象,其中包含 1 个名为 Build 的目标
定义正确的工具版本
根据 Visual Studio 版本的项目:
- 2010、2012 => 4.0
- 2013 => 12.0
- 2015 => 14.0
- 2017 => 15.0
添加类型为 MsBuild 的新任务
项目属性包含我需要构建的所有项目
定义工具版本
与项目具有相同值的 MsBuild 任务
将项目序列化到临时文件中
根据ToolsVersion找到正确的MsBuild.exe
4.0、12.0、14.0
在注册表中发现:
Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\{msBuildVersion}")
15.0
不再在注册表中,需要使用Nuget包Microsoft.VisualStudio.Setup.Configuration.Interop https://www.nuget.org/packages/Microsoft.VisualStudio.Setup.Configuration.Interop/
var query = new SetupConfiguration();
var query2 = (ISetupConfiguration2)query;
var e = query2.EnumAllInstances();
var helper = (ISetupHelper)query;
int fetched;
var instances = new ISetupInstance[1];
do
{
e.Next(1, instances, out fetched);
if (fetched > 0)
{
var instance = instances[0];
var instance2 = (ISetupInstance2)instance;
var state = instance2.GetState();
// Skip non-complete instance, I guess?
// Skip non-local instance, I guess?
// Skip unregistered products?
if (state != InstanceState.Complete
|| (state & InstanceState.Local) != InstanceState.Local
|| (state & InstanceState.Registered) != InstanceState.Registered)
{
continue;
}
var msBuildComponent =
instance2.GetPackages()
.FirstOrDefault(
p =>
p.GetId()
.Equals("Microsoft.Component.MSBuild",
StringComparison.InvariantCultureIgnoreCase));
if (msBuildComponent == null)
{
continue;
}
var instanceRootDirectory = instance2.GetInstallationPath();
var msbuildPathInInstance = Path.Combine(instanceRootDirectory, "MSBuild", msBuildVersion, "Bin", "msbuild.exe");
if (File.Exists(msbuildPathInInstance))
{
return msbuildPathInInstance;
}
}
} while (fetched > 0);
执行MsBuild.exe
并使用自定义 XML 记录器构建序列化项目 - 您可以使用由MsBuild扩展包 https://github.com/mikefourie/MSBuildExtensionPack
阅读结果摘要
从 Xml 反序列化结果摘要并使用它来确定构建是否失败、发生了哪些错误和警告等。