dotnet 通过引用 msbuild 程序集实现自己定制编译器

本来我想说的是基于引用 msbuild 程序集来自己做一个编译器,但是想想好像本文做的,和造编译器没啥关系,咱自己调用 msbuild 的 API 而已。本文来告诉大家如何引用 msbuild 程序集,如何在自己的应用程序里面嵌入 msbuild 的构建代码,实现 dotnet build 的效果

大部分的代码都是采用命令行的方式去调用 dotnet build 或 msbuild 命令,然而通过命令行调用用的是跨进程的方式,如果期望做更多的定制化,最好还是放在相同的进程,此时可以更改构建的各个步骤

自己制作一个编译器最简单的方法就是引用现有的成熟的编译器作为组件,刚好 msbuild 最新版本也是使用 dotnet 框架编写的,咱的 dotnet 应用可以非常方便将 msbuild 引用进来。当然了,本文不讨论如何自己发布 msbuild 的问题,因为这又是另一个坑了。本文的方法是引用本机已安装好的 msbuild 程序集

在开始之前,请新建一个控制台项目。当然了,你要是新建一个 WPF 项目也没啥问题

编辑 csproj 文件,添加如下代码

  <ItemGroup><PackageReference Include="Microsoft.Build" Version="16.10.0" ExcludeAssets="runtime" /><PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.10.0" ExcludeAssets="runtime" /><PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" /></ItemGroup>

添加完成之后的 csproj 文件代码如下

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net6.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.Build" Version="16.10.0" ExcludeAssets="runtime" /><PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.10.0" ExcludeAssets="runtime" /><PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" /></ItemGroup>
</Project>

第一步是先获取本机已安装好的 msbuild 实例,如下代码

        static void Main(string[] args){var instances = MSBuildLocator.QueryVisualStudioInstances().ToList();}

以上代码要能运行,需要加上如下命名空间

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Locator;

以上拿到的 instances 就是本机安装的 msbuild 实例,也就是 dotnet sdk 的各个版本,可以使用如下代码输出

            for (var i = 1; i <= instances.Count; i++){var instance = instances[i - 1];var recommended = string.Empty;// The dev console is probably always the right choice because the user explicitly opened// one associated with a Visual Studio install. It will always be first in the list.if (instance.DiscoveryType == DiscoveryType.DeveloperConsole)recommended = " (Recommended!)";Console.WriteLine($"{i}) {instance.Name} - {instance.Version}{recommended}");}

下一步是有点黑科技的部分,也就是为什么我会写本文的原因。使用下面代码注册 msbuild 实例,如果没有使用下面这句代码注册,那么在后续调用 msbuild 相关类型时,将会因为找不到 msbuild 的程序集而失败

            // 必须调用 RegisterInstance 方法,否则将提示找不到 msbuild 文件MSBuildLocator.RegisterInstance(instances.First());

注册完成之后,将可以使用 msbuild 提供的各个类来实现构建,请新建一个方法用来编写调用 msbuild 各个类的构建代码。如以下代码

        private static void Build(){var projectFile = new FileInfo(@"..\..\..\RalboleaballNeeqaqiku.csproj");var projectRootElement = ProjectRootElement.Open(projectFile.FullName);var project = new Project(projectRootElement);project.Build(new Logger());}

为什么需要这部分构建代码放在另一个方法里面?原因是在碰到了 ProjectRootElement 类型的时候,就需要开始加载程序集,然而在调用 MSBuildLocator.RegisterInstance 之前,还是找不到程序集的哦。因此为了让 MSBuildLocator.RegisterInstance 能被执行,就需要让包含 MSBuildLocator.RegisterInstance 代码的方法不会在执行之前碰到还没有存在的程序集,因此就需要将碰到构建相关逻辑的代码放在独立的方法或者独立的类型里面,这样就能让包含 MSBuildLocator.RegisterInstance 的代码不会因为找不到程序集而不执行

以上代码是通过调用 ProjectRootElement.Open 方法加载了 csproj 文件,此步骤是反序列化过程。接着新建 Project 实例,在新建方法里面将会进行初始化,可以拿到输入的 csproj 将有哪些导入等信息

最后一步是通过调用 Project 的 Build 方法进行构建,此时将会执行一次构建,构建的信息通过传入的 Logger 进行输出,以下是 Logger 的代码

        private class Logger : ILogger{public void Initialize(IEventSource eventSource){eventSource.AnyEventRaised += (_, args) => { Console.WriteLine(args.Message); };}public void Shutdown(){}public LoggerVerbosity Verbosity { get; set; }public string Parameters { get; set; }}

全部代码如下

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Locator;namespace RalboleaballNeeqaqiku
{class Program{static void Main(string[] args){var instances = MSBuildLocator.QueryVisualStudioInstances().ToList();for (var i = 1; i <= instances.Count; i++){var instance = instances[i - 1];var recommended = string.Empty;// The dev console is probably always the right choice because the user explicitly opened// one associated with a Visual Studio install. It will always be first in the list.if (instance.DiscoveryType == DiscoveryType.DeveloperConsole)recommended = " (Recommended!)";Console.WriteLine($"{i}) {instance.Name} - {instance.Version}{recommended}");}// 必须调用 RegisterInstance 方法,否则将提示找不到 msbuild 文件MSBuildLocator.RegisterInstance(instances.First());// 需要将构建的代码放在另一个方法里面,否则将会因为放在相同的方法,没有加上程序集Build();}private static void Build(){var projectFile = new FileInfo(@"..\..\..\RalboleaballNeeqaqiku.csproj");var projectRootElement = ProjectRootElement.Open(projectFile.FullName);var project = new Project(projectRootElement);project.Build(new Logger());}private class Logger : ILogger{public void Initialize(IEventSource eventSource){eventSource.AnyEventRaised += (_, args) => { Console.WriteLine(args.Message); };}public void Shutdown(){}public LoggerVerbosity Verbosity { get; set; }public string Parameters { get; set; }}}
}

本文所有代码放在 github 和 gitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin b6171297d4200586d135a8c5c0d7376df7ee7c6a

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

获取代码之后,进入 RalboleaballNeeqaqiku 文件夹

更多关于 Roslyn 请看 手把手教你写 Roslyn 修改编译


本文会经常更新,请阅读原文: https://blog.lindexi.com/post/dotnet-%E9%80%9A%E8%BF%87%E5%BC%95%E7%94%A8-msbuild-%E7%A8%8B%E5%BA%8F%E9%9B%86%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%B7%B1%E5%AE%9A%E5%88%B6%E7%BC%96%E8%AF%91%E5%99%A8.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/300656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过修改注册表设定浏览器的却省值

安装NetScape后&#xff0c;点击*.htm文件&#xff0c;却是用NetScape打开的&#xff0c;有时候感觉不爽&#xff0c;怎样才能将浏览器的却省打开设定为IE呢&#xff1f;通过修改注册表的方法可以解决&#xff1a;保存如下内容为IEChn.reg&#xff0c;运行即可。REGEDIT4[HKEY_…

[转贴]犯贱报(一张浓缩大学生活的..)

1 学校门口总是有一些骗子&#xff0c; 有的开着车&#xff0c; 有的没有开车。 没有开车的&#xff0c; 骗骗我们的钱&#xff0c; 开着车的&#xff0c; 骗骗我们的人。 2 有一天&#xff0c; 校门口来了一名物理爱好者&#xff0c; 认为自己推翻了相对论。 我们去探讨请教&…

大牛逝世 = 新人上位 = 科学进步?新研究表明确实如此

全世界只有3.14 % 的人关注了青少年数学之旅学术大牛们生前为人类创造了巨大的知识财富&#xff0c;死后也以另一种形式造福了科学。一项新研究表明&#xff0c;明星科学家去世后&#xff0c;同一学科分区中从未与他们合作的科学家论文发表数量提升 8.6%&#xff0c;其他领域的…

dns的子域授权

主服务器配置&#xff1a;1.在/var/named/neo.zone里添加如下数据...前面省略... SOA部分序号加大&#xff0c;其余不变dep1.neo.com. IN NS dns.dep1.neo.com.dns.dep1.neo.com. IN A 10.3.156.45从服务器配置&#xff1a;1.修改/etc/named.rfc1912.zones&#xff0c;假设文件…

扩展mysql_扩展mysql - 手把手教你写udf

1 MySQL简介MySQL是最流行的开放源码SQL数据库管理系统&#xff0c;相对于Oracle&#xff0c;DB2等大型数据库系统&#xff0c;MySQL由于其开源性、易用性、稳定性等特点&#xff0c;受到个人使用者、中小型企业甚至一些大型企业的广泛欢迎&#xff0c;MySQL具有以下特点&#…

I want go to school

那天&#xff0c;村里来了英语老师&#xff0c;她教我们说了第一句英语&#xff1a;“I want go to school.” 你听到了吗&#xff1f;那是最震撼的呐喊&#xff01;

.NET 6 Preview 6 正式发布: 关注网络开发

微软.NET 团队的项目经理在博客上发布了.NET 6 Preview 6, 在候选发布阶段之前的倒数第二个预览版&#xff0c;也就是8月份还会发布一个Preview 7&#xff0c;9月份开始进入RC&#xff0c;两个候选版本将专注于质量修复&#xff0c;直到 11 月的最终版本。Preview 6 版本本身相…

这些肢体语言竟然是这个意思! | 今日最佳

世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源网络&#xff0c;侵权删&#xff09;

程序员的发展和境界

评论&#xff1a;在IT社区看到这篇文章&#xff0c;觉得挺有意思&#xff0c;挺激励人的&#xff0c;所以引用来大家交流&#xff0c;只要能不断付出和努力&#xff0c;总是有收获的&#xff0c;这样对自身和企业的持续发展都是很有利的&#xff01;原文&#xff1a;程序员的四…

ASP.NET MVC 上传大文件时404

前一段时间会员的上传组件改用FLASH的swfupload来上传&#xff0c;既能很友好的显示上传进度&#xff0c;又能完全满足大文件的上传。 后来服务器升级到windows 2008,改为IIS7后&#xff0c;上传文件一旦超过30M时&#xff0c;就出现404错误&#xff0c;而且是是上传进度达到10…

下午去银行办理按揭手续,不得已调休半天

可恶的银行非得在工作日才办理按揭手续&#xff0c;不是人民的银行为人民吗&#xff1f;既然存款利率要降&#xff0c;以后还打算收取存款费用&#xff0c;那银行就是[或者打算是]地道的服务行业&#xff0c;周末对公业务不开就算了&#xff0c;个人按揭也闭门&#xff0c;没有…

Scott Hanselman 喊你来看看最新的极简APII

近日&#xff0c;Scott Hanselman 在社交网络上发布了 .NET 的最新消息&#xff1a;现代的 C# 特性和 ASP.NET Core 中新的极简 API 正在 .NET 6 中开始出现。你可以在 DamianEdwards 的仓库中看到一些示例&#xff0c;并与团队分享你的想法! &#xff08;点击原文链接查看仓库…

全球孩子迷恋手机/iPad,其实罪魁祸首是父母!

全世界只有3.14 % 的人关注了青少年数学之旅我从来没有想过&#xff0c;现在孩子的童年会是这样子的。他们手上捧着的不是书籍&#xff0c;而是小手掌都握不过来的手机、iPad&#xff1b;他们嘴上谈论的不是作业&#xff0c;而是许多成年人都搞不懂的王者和吃鸡。很多父母说&am…

c#设计模式(转)

http://terrylee.cnblogs.com/archive/2006/06/01/334911.html转载于:https://www.cnblogs.com/niuniu502/archive/2007/08/17/859032.html

好资源大家分享

500 本E书下载 http://forum.blogchina.com/38652.htmlMSN7发布: http://dl.pconline.com.cn/html/1/1/dlid2461&dltypeid1&pn0&.html

oracle vm 安装虚拟机小bug

2019独角兽企业重金招聘Python工程师标准>>> 如果是iso文件是64位&#xff0c; 那么在创建虚拟电脑时选择的系统就是window7 x64。否则报错&#xff1a;0000225错误. 转载于:https://my.oschina.net/u/1174884/blog/175596

庄表伟:License之外,社区的规则与潜规则 | DEV. Together 2021 中国开发者生态峰会...

内容来源&#xff1a;2021 年 6 月 5 日&#xff0c;由 SegmentFault 思否主办的 2021 中国开发者生态峰会圆满落幕。会上&#xff0c;华为云产品专家、开源社理事长庄表伟发表了主题为《License之外&#xff0c;社区的规则与潜规则》的演讲。分享嘉宾&#xff1a;庄表伟&#…

GridView 简单扩展

usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Text;usingSystem.Web;usingSystem.Web.UI;usingSystem.Web.UI.WebControls;namespaceFanfajin.MyWebControls{ /**//// <summary> /// 增强的 GridView 控件 扩展 /// &…

mysql 1117_1117Mysql prepare预处理语句

转自http://www.jb51.net/article/81378.htm综述&#xff1a;一般用来拼凑SQL然后执行MySQL 5.1对服务器一方的预制语句提供支持。如果您使用合适的客户端编程界面&#xff0c;则这种支持可以发挥在MySQL 4.1中实施的高效客户端/服务器二进制协议的优势。候选界面包括MySQL C A…

为了偷吃东西你能有多拼?! | 今日最佳

世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源网络&#xff0c;侵权删&#xff09;