.NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
原文:.NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖

我们有多种工具可以将程序集合并成为一个。比如 ILMerge、Mono.Merge。前者不可定制、运行缓慢、消耗资源(不过好消息是现在开源了);后者已被弃用、不受支持且基于旧版本的 Mono.Cecil。
而本文介绍用来替代它们的 ILRepack,使用 ILRepack 来合并程序集。
以 NuGet 包的形式使用 ILRepack
ILRepack 提供了可供你项目使用的 NuGet 包。如果你在团队项目当中安装了 ILRepack 的 NuGet 包,那么无论团队其他人是否安装了 ILRepack 的工具,都可以使用 ILRepack 工具。这可以避免要求团队所有成员安装工具或者将工具内置到项目的源代码管理中。
要以 NuGet 包的形式来使用 ILRepack,需要首先安装 ILRepack 的 NuGet 包:
或者直接在你的项目的 csproj 文件中添加 PackageReference
:
<ItemGroup>
<PackageReference Include="ILRepack" Version="2.0.17" />
</ItemGroup>
- 1
- 2
- 3
我现在有一个项目 Walterlv.Demo.AssemblyLoading,这是一个控制台程序。这个程序引用了一个 NuGet 包 Ben.Demystifier。为此带来了三个额外的依赖。
- Walterlv.Demo.AssemblyLoading.exe
- Ben.Demystifier.dll
- System.Collections.Immutable.dll
- System.Reflection.Metadata.dll
- 1
- 2
- 3
- 4
而我们可以使用 ILRepack 将这些依赖和我们生成的主程序合并成一个程序集,这样分发程序的时候只需要一个程序集即可。
那么,我们现在需要编辑我们的项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ben.Demystifier" Version="0.1.4" />
<PackageReference Include="ILRepack" Version="2.0.17" />
</ItemGroup>
++ <Target Name="ILRepack">
++ <Exec Command=""$(ILRepack)" /out:$(OutputPath)$(AssemblyName).exe $(OutputPath)$(AssemblyName).exe $(OutputPath)Ben.Demystifier.dll $(OutputPath)System.Collections.Immutable.dll $(OutputPath)System.Reflection.Metadata.dll" />
++ </Target>
</Project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
我们只增加了三行,添加了一个名称为 ILRepack 的 Target。(注意到项目文件中我有额外引用一个其他的 NuGet 包 Ben.Demystifier,这是为了演示将依赖进行合并而添加的 NuGet 包,具体是什么都没有关系,我们只是在演示依赖的合并。)在这个 Target 里面,我们使用 Exec 的 Task 来执行 ILRepack 命令。具体这个命令代表的含义我们在下一节介绍 ILRepack 工具的时候会详细介绍。如果你希望在你的项目当中进行尝试,可以把后面那些代表程序集的名称改为你自己项目中依赖程序集的名称。
现在在编译的时候使用命令 msbuild /t:ILRepack
就可以完成程序集的合并了。
注意,你普通编译的话是不会进行 IL 合并的。
如果你希望常规编译也可以进行 IL 合并,或者说希望在 Visual Studio 里面点击生成按钮的时候也能完成 IL 合并的话,那么你还需要增加一个跳板的编译目标 Target。
我将这个名为 _ProjectRemoveDependencyFiles
的 Target 增加到了下面。它的目的是在 AfterBuild
这个编译目标完成之后(AfterTargets)执行,然后执行前需要先执行(DependsOnTargets)ILRepack 这个 Target。在这个编译目标执行的时候还会将原本的三个依赖删除掉,这样在生成的目录下我们将只会看到我们最终期望的程序集 Walterlv.Demo.AssemblyLoading.exe 而没有其他依赖程序集。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ben.Demystifier" Version="0.1.4" />
<PackageReference Include="ILRepack" Version="2.0.17" />
</ItemGroup>
<Target Name="ILRepack">
<Exec Command=""$(ILRepack)" /out:$(OutputPath)$(AssemblyName).exe $(OutputPath)$(AssemblyName).exe $(OutputPath)Ben.Demystifier.dll $(OutputPath)System.Collections.Immutable.dll $(OutputPath)System.Reflection.Metadata.dll" />
</Target>
++ <Target Name="_ProjectRemoveDependencyFiles" AfterTargets="AfterBuild" DependsOnTargets="ILRepack">
++ <ItemGroup>
++ <_ProjectDependencyFile Include="$(OutputPath)Ben.Demystifier.dll" />
++ <_ProjectDependencyFile Include="$(OutputPath)System.Collections.Immutable.dll" />
++ <_ProjectDependencyFile Include="$(OutputPath)System.Reflection.Metadata.dll" />
++ </ItemGroup>
++ <Delete Files="@(_ProjectDependencyFile)" />
++ </Target>
</Project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
最终生成的输出目录下只有我们最终期望生成的程序集:
ILRepack 的命令行使用
相比于 ILMerge,ILRepack 的命令行在尽量贴近 ILMerge 的情况下做得更加简化了。
ilrepack /out:Walterlv.Demo.AssemblyLoading.exe Walterlv.Demo.AssemblyLoading.exe Ben.Demystifier.dll System.Collections.Immutable.dll System.Reflection.Metadata.dll
- 1
其中,/out
表示最终的输出程序集的名称或路径,后面没有前缀的参数都是需要合并的程序集的名称或路径。这些需要合并的参数中,第一个参数是主程序集,而后续其他的都是待合并的程序集。区别主程序集和其他程序集的原因是输出的程序集需要有名称、版本号等等信息,而这些信息将使用主程序集中的信息。
如果希望使用 ILRepack 的其他命令,可以考虑使用帮助命令:
ilrepack /help
- 1
或者直接访问 ILRepack 的 GitHub 仓库来查看用法:
如果解决合并错误?
缺少依赖
如果你在使用 ILRepack 合并程序集的过程中出现了缺少依赖的错误,例如下面这样:
Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'xxxxxxxxx'
- 1
那么你需要做以下两种事情中的任何一种:
- 将所有依赖合并;
- 将依赖加入搜索目录。
将所有依赖合并指的是将缺少的依赖也一起作为命令行参数传入要合并的程序集中。
而另一种是增加一个参数 /lib
,即添加一个被搜索的依赖程序集的目录。将这个目录指定后,则可以正确解析依赖完成合并。而且这些依赖将成为合并后的程序集的依赖,不会合并到程序集中。
ilrepack /lib:D:\Dependencies /out:Walterlv.Demo.AssemblyLoading.exe Walterlv.Demo.AssemblyLoading.exe Ben.Demystifier.dll System.Collections.Immutable.dll System.Reflection.Metadata.dll
- 1
没有生成 PDB 文件
如果使用新的基于 Sdk 的项目文件,那么默认生成的 PDB 是 Portable PDB,但是 ILRepack 暂时不支持 Portable PDB,其在内部捕获了异常以至于可以完成合并但不会生成 PDB 文件。
目前此问题在 ILRepack 中还处于打开状态,且持续两年都没关闭了。同时很早就有支持 Portable PDB 的拉取请求,但至今未合并。
以下是 GitHub 社区中的讨论:
- Mono.Cecil 0.10 support · Issue #182 · gluck/il-repack
- Migrate to vanilla 0.10 cecil by Alexx999 · Pull Request #236 · gluck/il-repack
- ERROR: Failed to load assembly while merging .NET Core assembly · Issue #230 · gluck/il-repack
- Support for portable PDBs · Issue #11 · dotnet/ILMerge
参考资料
- gluck/il-repack: Open-source alternative to ILMerge
- Is it expected that pdb files are not merged? · Issue #217 · gluck/il-repack
我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。
如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
.NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖的更多相关文章
- .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
原文:.NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖 我们有多种工具可以将程序集合并成为一个.打包成一个程序集可以避免分发程序的时候带上一堆依赖而出问题. ILMerge 可以用来 ...
- 未能加载文件或程序集“AspNetPager”或它的某一个依赖项。参数错误(转)
未能加载文件或程序集“AspNetPager”或它的某一个依赖项.参数错误. 看你的的开发框架用的是多少的2.0, 3.0, 3.5, 4.0 那么删除的框架的文件夹也相对应的变化 删除 C:\W ...
- 目标平台、活动平台 配置,出现未能加载文件或程序集“xxx”或它的某一个依赖项报错
今天在做动态加载程序集的时候,发现明明程序集存在的情况下,还是依然报“未能加载文件或程序集“xxx”或它的某一个依赖项报错”的错误,排除了程序和配置的错误后,怀疑是否是环境的问题,于是百度加msdn后 ...
- 未能加载文件或程序集“XXX”或它的某一个依赖项。试图加载格式不正确的程序。
64位系统 IIS7.0配置.net网站时报错:未能加载文件或程序集"XXX"或它的某一个依赖项.试图加载格式不正确的程序. 背景: 在64位的操作系统中, IIS7.0配置.ne ...
- 未能加载文件或程序集“XXXXXX”或它的某一个依赖项。试图加载格式不正确的程序。
在本机WIN7机器上的WebService部署到Win2008R2上发现错误 “/”应用程序中的服务器错误. 未能加载文件或程序集“XXXXXX”或它的某一个依赖项.试图加载格式不正确的程序. 说明: ...
- 未能加载文件或程序集“WcfService”或它的某一个依赖项。试图加载格式不正确的程序。
“/”应用程序中的服务器错误. 未能加载文件或程序集“WcfService”或它的某一个依赖项.试图加载格式不正确的程序. 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息, ...
- 未能载入文件或程序集“DAL”或它的某一个依赖项。系统找不到指定的文件。
这个一般出如今三层给B层与D层之间加抽象工厂-接口-映射.时候出的错.出错的地方是抽象工厂. --如图 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTA ...
- 异常:未能载入文件或程序集”DAL”或它的某一个依赖项——解决的方法
以下是我再使用抽象工厂+反射重构机房时,在Factoy中出现了以下一个问题: 去网上查了一下资料,发现这是一个非常普遍的问题,它出现的原因主要有两种: 第一种: 载入DLL路径错误.解决的方法是调整D ...
- 能加载文件或程序集“XXX”或它的某一个依赖项,系统找不到指定的文件
能加载文件或程序集“XXX”或它的某一个依赖项,系统找不到指定的文件 http://blog.csdn.net/pplcheer/article/details/7796211 做项目总是遇到各种的问 ...
随机推荐
- Windows 文件过滤驱动经验总结
Windows 文件过滤驱动经验总结作者:sinister 本文转载自驱动开发网 看了 ChuKuangRen 的第二版<文件过滤驱动开发教程>后,颇有感触.我想,交流都是建立在平等的基础 ...
- ELK(Elasticsearch + Logstash + Kibana) 日志收集
单体应用或微服务的场景下,每个服务部署在不同的服务器上,需要对日志进行集重收集,然后统一查看所以日志. ELK日志收集流程: 1.微服务器上部署Logstash,对日志文件进行数据采集,将采集到的数据 ...
- 仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表'TableName'中的标识列指定显式值
当某表的一个列为自动增长列,是无法直接通过insert语句向给字段写入指定值,解决方法: SET IDENTITY_INSERT TABLE_NAME ON; INSERT INTO TABLE_NA ...
- Kibana数据可视化
Kibana数据可视化 1,3.1使用logstash导入数据的问题 会出现错误提示: [location] is defined as an object in mapping [doc] but ...
- python gis库
apt install python3 python3-gdal gdal-bin python3-pyproj proj-bin python3-shapely fiona python3-fion ...
- TX-LCN5.0.2分布式事务框架源码分析-关键线索罗列-txc部分
1.注解TxcTransaction2.在其注解接口附近查找aop配置:TransactionAspect3.runTransaction是在执行事务业务代码时的包装逻辑4.transactionSe ...
- Fragment: 使用newInstance()来实例化fragment(转)
先说结论: 1. 当需要给Fragment传值时,使用newInstance()方式来实例化一个Fragment,能够更好的将该Fragment使用的参数捆绑起来,不必每次实例化时都写下面的代码: B ...
- springMVC:为MultipartFilte配置了上传文件解析器,报错或不能使用
一.问题描述为支持restful风格请求,并且应对可能上传文件的情况,需要在配置hiddenHttpMethodFilter过滤器之前配置MultipartFilter.目的是让MultipartFi ...
- Annotation-based argument resolution 部分2
HandlerMethodArgumentResolver的抽象實現AbstractNamedValueMethodArgumentResolver下的子类 部分1 RequestParamMapM ...
- 几个简单易用的IDEA快捷键
常见的几个Idea的代码快捷键 格式化代码: Ctrl + Alt + L Optimize Imports(优化包引用): Ctrl-Alt-O 单行注释(//): Ctrl-/ 块注释(/*... ...