前阵子,答应了帮一位哥们做一个桌面应用工具。
好吧,说干就干!花了一个周末的时候,应用功能的开发算是搞定了,剩下来就是交付的问题了。这时,我看到release目录里一堆的dll,程序代码的洁癖再也压制不住了。于是,临时给自己增加一个目标:把这些丑陋的dll给隐藏起来,放在一个子目录里,当然最好是全部打包成一个exe文件。
如果是.NET Core开发的应用,那就很好办,打包指令加上self-contained
就可以了。例如:
dotnet publish -c Release -r win-x64 --self-contained
好是不死,因为组件依赖的原因,我不得不使用.NET Framework。因此,只能求助互联网给我思路了。很快我便找到了两方案,都能够完美解决我的需求。
下面我就分别介绍一下吧。
一、ILMerge
获得ILMerge
- 下载源代码
git clone https://github.com/dotnet/ILMerge.git
编译代码 ``` SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MsBuild.exe"
%MSBUILD% ILMerge\ILMerge.csproj /t:Rebuild /p:Configuration=Release;OutDir=.\bin
#### 创建项目
创建一个名为`MergeAppDemo`的项目,项目中引用了我们熟悉的第三方库`Newtonsoft.Json`。然后正常编译出来的内容如下:
![image.png](https://qqcdn.chenreal.com/blog/202409/133709484971834755_gqC.png)
#### ILMerge打包脚本
执行以下命令
ILMerge.exe /log:merge.log /t:winexe /out:target\MergeAppDemo.exe source\MergeAppDemo.exe source\Newtonsoft.Json.dll
几秒钟后,得到一个新的可执行文件。并且我们发现了它的Size,增大了不少。看来`Newtonsoft.Json.dll`已经被打包在其中了!
![image.png](https://qqcdn.chenreal.com/blog/202409/133709487062209991_Vhk.png)
双击运行`MergeAppDemo.exe`,太好了,成功了!
#### 将ILMerge脚本整合项目工程
如果大家觉得每次生成编译还要额外多执行一次ILMerge脚本太过麻烦,我们可以将脚本写入在项目工程配置里,那么就可以简化成,每次Release发布成功后,自动执行ILMerge脚本,一气呵成。
首先,用文本编辑器打开工程文件`MergeAppDemo.csproj`,找到编译参数的配置节点,添加`PostBuildEvent`的脚本内容。
<PostBuildEvent>
ILMerge.exe /log:merge.log /t:winexe /out:$(ProjectDir)bin\MergeAppDemo.exe $(ProjectDir)bin\Release\MergeAppDemo.exe $(ProjectDir)bin\Release\Newtonsoft.Json.dll
## 二、Costura.Fody
#### 安装Costura.Fody
要使用Costura.Fody,你首先需要将其安装到你的项目中。你可以通过NuGet包管理器来安装它。在你的Visual Studio中,打开“包管理器控制台”,然后输入以下命令:
Install-Package Costura.Fody ```
编译项目
安装好Costura.Fody之后,无需做任何配置,直接编译项目。转到在bin/Release
目录,就可以找到已经打包好的exe文件,而且Size比ILMerge生成的更小。
看起来十分完美,同样双击运行MergeAppDemo.exe
,也可以正常执行!
总结
本文介绍了两种.NET应用程序的打包工具,分别是ILMerge和Costura.Fody。他们都能完成目标,把各种依赖的dll和其他资源全部打包在单一的exe文件中。
我个人推荐Costura.Fody。因为相对而言Costura.Fody实现更加简单方便:
- 配置简单,直接Nuget引入即可,不像ILMerge还需要额外编写脚本
- 而且编译打包速度更快,几乎感觉不到因打包产生的延迟
- 生成文件的Size更小,似乎Costura.Fody还做了一些裁剪