原文:.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="&quot;$(ILRepack)&quot; /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="&quot;$(ILRepack)&quot; /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

那么你需要做以下两种事情中的任何一种:

  1. 将所有依赖合并;
  2. 将依赖加入搜索目录。

将所有依赖合并指的是将缺少的依赖也一起作为命令行参数传入要合并的程序集中。

而另一种是增加一个参数 /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 社区中的讨论:


参考资料


我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

发布了382 篇原创文章 · 获赞 232 · 访问量 47万+

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

  1. .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖

    原文:.NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖 我们有多种工具可以将程序集合并成为一个.打包成一个程序集可以避免分发程序的时候带上一堆依赖而出问题. ILMerge 可以用来 ...

  2. 未能加载文件或程序集“AspNetPager”或它的某一个依赖项。参数错误(转)

    未能加载文件或程序集“AspNetPager”或它的某一个依赖项.参数错误. 看你的的开发框架用的是多少的2.0, 3.0, 3.5, 4.0 那么删除的框架的文件夹也相对应的变化   删除 C:\W ...

  3. 目标平台、活动平台 配置,出现未能加载文件或程序集“xxx”或它的某一个依赖项报错

    今天在做动态加载程序集的时候,发现明明程序集存在的情况下,还是依然报“未能加载文件或程序集“xxx”或它的某一个依赖项报错”的错误,排除了程序和配置的错误后,怀疑是否是环境的问题,于是百度加msdn后 ...

  4. 未能加载文件或程序集“XXX”或它的某一个依赖项。试图加载格式不正确的程序。

    64位系统 IIS7.0配置.net网站时报错:未能加载文件或程序集"XXX"或它的某一个依赖项.试图加载格式不正确的程序. 背景: 在64位的操作系统中, IIS7.0配置.ne ...

  5. 未能加载文件或程序集“XXXXXX”或它的某一个依赖项。试图加载格式不正确的程序。

    在本机WIN7机器上的WebService部署到Win2008R2上发现错误 “/”应用程序中的服务器错误. 未能加载文件或程序集“XXXXXX”或它的某一个依赖项.试图加载格式不正确的程序. 说明: ...

  6. 未能加载文件或程序集“WcfService”或它的某一个依赖项。试图加载格式不正确的程序。

    “/”应用程序中的服务器错误. 未能加载文件或程序集“WcfService”或它的某一个依赖项.试图加载格式不正确的程序. 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息, ...

  7. 未能载入文件或程序集“DAL”或它的某一个依赖项。系统找不到指定的文件。

    这个一般出如今三层给B层与D层之间加抽象工厂-接口-映射.时候出的错.出错的地方是抽象工厂. --如图 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTA ...

  8. 异常:未能载入文件或程序集”DAL”或它的某一个依赖项——解决的方法

    以下是我再使用抽象工厂+反射重构机房时,在Factoy中出现了以下一个问题: 去网上查了一下资料,发现这是一个非常普遍的问题,它出现的原因主要有两种: 第一种: 载入DLL路径错误.解决的方法是调整D ...

  9. 能加载文件或程序集“XXX”或它的某一个依赖项,系统找不到指定的文件

    能加载文件或程序集“XXX”或它的某一个依赖项,系统找不到指定的文件 http://blog.csdn.net/pplcheer/article/details/7796211 做项目总是遇到各种的问 ...

随机推荐

  1. Asp.net 与 Core .net 用法区别

    1.  定义一个类 如下,注意int?这里 public class A{ public int? num{get;set;} } 2. 如果传递的参数不能转换成int类型,则core里面接受不了参数 ...

  2. Python并发请求之requests_future模块使用

    # -*- coding: utf-8 -*- # @Time : 2019-12-09 10:00 # @Author : cxa # @File : demo.py # @Software: Py ...

  3. SQL,NoSQL和NewSQL的区别

    SQL(Structured Query Language):数据库,指关系型数据库.主要代表:SQL Server.Oracle.MySQL.PostgreSQL. NoSQL(Not Only S ...

  4. 解决git 出现 Your account has been blocked问题

    使用git 出现 Your account has been blocked 无法从远程pull代码下来, 解决方案如下: $ git push origin masterGitLab: Your a ...

  5. MQTT研究之EMQ:【EMQX使用中的一些问题记录(3)】

    EMQX功能强大,但是帮助信息或者可用资料的确有限,遇到个问题,比较难找到处理的头绪,今天,我要记录的是,使用中出现EMQX宕机,但是呢,启动也启动不了. 今天记录的内容,就以操作EMQX 3.2.3 ...

  6. scrapy中的Pipeline

    当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item. 每个Item Pipeline都是实现了简单方法的Pyth ...

  7. 006-tomcat 多实例安装、appBase和docBase、Context说明

    一.多实例部署 主要是为了充分利用服务器资源,并且可以交叉部署应用.主要做法可以有使用docker部署,多实例部署. 多实例多应用:多个 Tomcat 部署多个不同的项目.这种模式在服务器资源有限,或 ...

  8. Anaconda(一)

    一.Anaconda下载安装 Anaconda + Pycharm是知乎大佬们推荐的Python标配, Anaconda有众多版本,截至2019年11月的最新版Anaconda内置的是Python3. ...

  9. Qt开发经验小技巧51-60

    在某些http post数据的时候,如果采用的是&字符串连接的数据发送,中文解析乱码的话,需要将中文进行URL转码. QString content = "测试中文"; Q ...

  10. Elasticsearch学习笔记——索引模板

    在索引模板里面,date类型的字段的format支持多种类型,在es中全部会转换成long类型进行存储,参考 https://zhuanlan.zhihu.com/p/34240906 一个索引模板范 ...