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

我们有多种工具可以将程序集合并成为一个。打包成一个程序集可以避免分发程序的时候带上一堆依赖而出问题。

ILMerge 可以用来将多个程序集合并成一个程序集。本文介绍使用 ILMerge 工具和其 NuGet 工具包来合并程序集和其依赖。


以 NuGet 包的形式使用 ILMerge

ILMerge 提供了可供你项目使用的 NuGet 包。如果你在团队项目当中安装了 ILMerge 的 NuGet 包,那么无论团队其他人是否安装了 ILMerge 的工具,都可以使用 ILMerge 工具。这可以避免要求团队所有成员安装工具或者将工具内置到项目的源代码管理中。

要以 NuGet 包的形式来使用 ILMerge,需要首先安装 ILMerge 的 NuGet 包:

或者直接在你的项目的 csproj 文件中添加 PackageReference

<ItemGroup>
<PackageReference Include="ILMerge" Version="3.0.29" />
</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

而我们可以使用 ILMerge 将这些依赖和我们生成的主程序合并成一个程序集,这样分发程序的时候只需要一个程序集即可。

那么,我们现在需要编辑我们的项目文件:

    <Project Sdk="Microsoft.NET.Sdk">

        <PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
</PropertyGroup> <ItemGroup>
<PackageReference Include="Ben.Demystifier" Version="0.1.4" />
<PackageReference Include="ILMerge" Version="3.0.29" />
</ItemGroup> ++ <Target Name="ILMerge">
++ <Exec Command="&quot;$(ILMergeConsolePath)&quot; /ndebug /target:exe /out:$(OutputPath)$(AssemblyName).exe /log $(OutputPath)$(AssemblyName).exe /log $(OutputPath)Ben.Demystifier.dll /log $(OutputPath)System.Collections.Immutable.dll /log $(OutputPath)System.Reflection.Metadata.dll /targetplatform:v4" />
++ </Target> </Project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

我们只增加了三行,添加了一个名称为 ILMerge 的 Target。(注意到项目文件中我有额外引用一个其他的 NuGet 包 Ben.Demystifier,这是为了演示将依赖进行合并而添加的 NuGet 包,具体是什么都没有关系,我们只是在演示依赖的合并。)在这个 Target 里面,我们使用 Exec 的 Task 来执行 ILMerge 命令。具体这个命令代表的含义我们在下一节介绍 ILMerge 工具的时候会详细介绍。如果你希望在你的项目当中进行尝试,可以把所有 /log 参数之后的那些程序集名称改为你自己的名称。

那么在编译的时候使用命令 msbuild /t:ILMerge 就可以完成程序集的合并了。

注意,你普通编译的话是不会进行 IL 合并的。

如果你希望常规编译也可以进行 IL 合并,或者说希望在 Visual Studio 里面点击生成按钮的时候也能完成 IL 合并的话,那么你还需要增加一个跳板的编译目标 Target。

我将这个名为 _ProjectRemoveDependencyFiles 的 Target 增加到了下面。它的目的是在 AfterBuild 这个编译目标完成之后(AfterTargets)执行,然后执行前需要先执行(DependsOnTargets)ILMerge 这个 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="ILMerge" Version="3.0.29" />
</ItemGroup> <Target Name="ILMerge">
<Exec Command="&quot;$(ILMergeConsolePath)&quot; /ndebug /target:exe /out:$(OutputPath)$(AssemblyName).exe /log $(OutputPath)$(AssemblyName).exe /log $(OutputPath)Ben.Demystifier.dll /log $(OutputPath)System.Collections.Immutable.dll /log $(OutputPath)System.Reflection.Metadata.dll /targetplatform:v4" />
</Target> ++ <Target Name="_ProjectRemoveDependencyFiles" AfterTargets="AfterBuild" DependsOnTargets="ILMerge">
++ <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

最终生成的输出目录下只有我们最终期望生成的程序集:

以命令行工具的形式使用 ILMerge

你可以在这里下载到 ILMerge:

实际上 ILMerge 已经开源,你可以在 GitHub 上找到它:

装完之后,如果将 ILMerge 的可执行目录加入到环境变量,那么你将可以在任意的目录下在命令行中直接使用 ILMerge 命令了。加入环境变量的方法我就不用说了,可以在网上搜索到非常多的资料。

ILMerge 装完的默认目录在 C:\Program Files (x86)\Microsoft\ILMerge,所以如果你保持默认路径安装,那么几乎可以直接把这个路径加入到环境变量中。

那么 ILMerge 的命令行如何使用呢?它的参数列表是怎样的呢?

我们来写一个简单的例子:

ilmerge /ndebug /target:exe /out:Walterlv.Demo.AssemblyLoading.exe /log Walterlv.Demo.AssemblyLoading.exe /log Ben.Demystifier.dll /log System.Collections.Immutable.dll /log System.Reflection.Metadata.dll /targetplatform:v4
  • 1

其中:

  • /ndebug 表示以非调试版本编译,如果去掉,将会生成 pdb 文件
  • /target 合并之后的程序集类型,如果是控制台程序,则为 exe
  • /out 输出文件的名称(或路径)(此路径可以和需要合并的程序集名称相同,这样在合并完之后会覆盖同名称的那个程序集)
  • /log 所有需要合并的程序集名称(或路径)
  • /targetplatform 目标平台,如果是 .NET Framework 4.0 - .NET Framework 4.8 之间,则都是 v4

在合并完成之后,我们反编译可以发现程序集中已经包含了依赖程序集中的全部类型了。

以封装的 NuGet 包来使用 ILRepack

安装 NuGet 包:

之后,你就能直接使用 ILRepack 这个编译任务了,而不是在 MSBuild 中使用 Exec 来间接执行 ILRepack 的任务。

关于此 NuGet 包的使用,GitHub 中有很棒的例子,可以查看:

需要注意

如果使用新的基于 Sdk 的项目文件,那么默认生成的 PDB 是 Portable PDB,但是 ILMerge 暂时不支持 Portable PDB,会在编译时提示错误:

An exception occurred during merging:
ILMerge.Merge: There were errors reported in dotnetCampus.EasiPlugin.Sample's metadata.
数组维度超过了支持的范围。
在 ILMerging.ILMerge.Merge()
在 ILMerging.ILMerge.Main(String[] args)
  • 1
  • 2
  • 3
  • 4
  • 5

或者英文提示:

An exception occurred during merging:
ILMerge.Merge: There were errors reported in ReferencedProject's metadata.
Array dimensions exceeded supported range.
at ILMerging.ILMerge.Merge()
at ILMerging.ILMerge.Main(String[] args)
  • 1
  • 2
  • 3
  • 4
  • 5

目前,GitHub 上有 issue 在追踪此问题:


参考资料


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

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

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

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

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

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

    原文:.NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖 我们有多种工具可以将程序集合并成为一个.比如 ILMerge.Mono.Merge.前者不可定制.运 ...

  2. 使用ILmerge合并Exe、Dll文件的帮助类

    原文:使用ILmerge合并Exe.Dll文件的帮助类 using System; using System.Collections.Generic; using System.Text; using ...

  3. C#中用ILMerge合并DLL和exe文件成一个exe文件或者DLL

    ILMerge是一个将多个.NET程序集合并到一个程序集中的实用程序.它既可以作为  开源使用,也可以作为NuGet包使用. 如果您在使用它时遇到任何问题,请与我们联系.(mbarnett _at_ ...

  4. ILMerge合并多个DLL

    序言 如果你的项目要提供多个dll给别人用,那么不妨让你的dll合并为一个,让别人看起来简洁,引用起来不会过于繁琐. 本篇比较少,但也算是比较实用吧. 下载微软的辅助工具ILMerge Imerge下 ...

  5. ILMerge合并程序

    在DOS窗口中,进入到ILMerge的安装目录 中 如图所示,之后写合并代码, 使用命令进行捆绑,以如图为例,将CSkin.dll和MyTool.exe捆绑成一个新的newtool.exe文件./ou ...

  6. ilmerge合并多个组件

    原文 http://www.cnblogs.com/margiex/archive/2008/06/24/302329.html 年初的一篇文章中提到过一下: http://margiex.cnblo ...

  7. ILMerge合并多个DLL (转)

    最近在研究CodeDom,用到ILMerge 序言 如果你的项目要提供多个dll给别人用,那么不妨让你的dll合并为一个,让别人看起来简洁,引用起来不会过于繁琐. 本篇比较少,但也算是比较实用吧. 下 ...

  8. C# winform页面可视化设计打开失败,提示未能加载程序集或他的一个依赖项,dll错误

    这种情况发生在最初项目是x86属性,改成x64后,一些原来dll,页面没有及时更新,导致页面找不到dll, 最简单的解决方式,把项目属性改成AnyCpu,重新编译下,就可以打开可视化设计窗口了.

  9. .NET 的程序集加载上下文

    原文:.NET 的程序集加载上下文 我们编写的 .NET 应用程序会使用到各种各样的依赖库.我们都知道 CLR 会在一些路径下帮助我们程序找到依赖,但如果我们需要手动控制程序集加载路径的话,需要了解程 ...

随机推荐

  1. 利用iptables做端口转发

    需求背景: A与C不在同一网段无法直接访问,而A和B,C和B可以互通.现需要A借助B访问C的3306端口. 解决方案: 利用iptables配置规则,实现端口转发. 具体操作: 在B上开启端口转发功能 ...

  2. Sequelize 数据类型

    Sequelize.STRING // VARCHAR(255)Sequelize.STRING(1234) // VARCHAR(1234)Sequelize.STRING.BINARY // VA ...

  3. C复习---动态内存分配

    原型extern void *malloc(unsigned int num_bytes);头文件#include <stdlib.h>#include <malloc.h>函 ...

  4. 【Gamma】Scrum Meeting 1 & 与助教谈话

    前言 Gamma阶段第1次会议在5月26日22:00由PM在大运村一公寓三层召开, 时长30min. 任务分配 姓名 今日任务 明日任务 困难 周博闻 用户控制器解耦和注释 用户控制器解耦和注释 周国 ...

  5. 【Gamma阶段】第一次Scrum Meeting

    冰多多团队-Gamma阶段第一次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 卓培锦 推广软件,发放调查问卷 修改可移动button以及button手感反馈优化,编辑器风格切换(夜间模式 ...

  6. 11 JavaScript Utility Libraries you Should Know in 2019

    11 Useful Javascript utility libraries to speed your development.

  7. AES采用CBC模式128bit加密工具类

    写在前面 安全测试ECB模式过于简单需要改为CBC模式加密以下为工具类及测试 AESUtils.java package com.sgcc.mobile.utils; import sun.misc. ...

  8. linux下如何使用adb连接在qemu中运行的安卓系统?

    1. 运行安卓系统, 如下: $sudo qemu-system-x86_64 -m 4096 -boot d -enable-kvm -smp 3 -net nic -net user,hostfw ...

  9. 基于Vue SEO的四种方案

    基于Vue SEO的四种方案 https://segmentfault.com/a/1190000019623624?utm_source=tag-newest

  10. 重装系统之前需要做的checklist

    1. 各浏览器 ---- 导出收藏夹 2. 备份桌面 3. 查用工具截图保存.保存使用了哪些工具 4.查看C盘有没有放置其他资料,需要备份的