ILMerge 最佳实践

你用 ILMerge 吗?是否使用 ILMerge 合并多个程序集以简化 dll 的部署?在将程序集合并在一起之后,您是否发现生产中的部署/版本控制存在问题?

我正在寻找一些关于使用 ILMerge 来减少部署摩擦的建议,如果可能的话。

57435 次浏览

我们在很多项目中使用 ILMerge。例如,网络服务软件工厂产生类似于8个程序集的东西作为其输出。我们将所有这些 DLL 合并到一个 DLL 中,以便服务主机只需引用一个 DLL。

这让生活变得轻松了一些,但也没什么大不了的。

我们在 Microsoft 应用程序块上使用 ILMerge ——不是12个独立的 DLL 文件,我们有一个单独的文件,我们可以上传到我们的客户端区域,另外文件系统结构更加整洁。

合并文件后,我必须编辑可视化工作室项目列表,删除12个独立的程序集并添加单个文件作为引用,否则它会抱怨找不到特定的程序集。我不太确定这将如何工作后部署,虽然,可能是值得一试。

我们刚刚开始在我们的解决方案中使用 ILMerge,这些解决方案被重新发布,并在我们的其他项目中使用,到目前为止还不错。看起来一切正常。我们甚至直接混淆了包装好的装配。

我们正在考虑对 MS 企业库程序集进行同样的操作。

我看到的唯一真正的问题是从包中对单个程序集进行版本控制。

我在几乎所有不同的应用程序中都使用 ILMerge。我已经把它集成到了发布版本构建过程中,所以我最终得到的是每个应用程序一个 exe,没有额外的 dll。

不能 ILMerge 任何具有本机代码的 C + + 程序集。 您也不能 ILMerge 任何包含 XAML for WPF 的程序集(至少我在这方面还没有取得任何成功)。它在运行时抱怨无法找到资源。

我确实为 ILMerge 编写了一个可执行的包装程序,其中我传递了我想要合并的项目的启动 exe 名称和一个输出 exe 名称,然后它反映了相关的程序集,并使用适当的命令行参数调用 ILMerge。现在向项目中添加新程序集时要容易得多,我不必记得更新构建脚本。

在合并具有相同命名空间中的资源的 DLL 时,我们遇到了问题。在合并过程中,一个资源名称空间被重命名,因此无法找到资源。也许我们只是做错了什么,还在调查这个问题。

我最近遇到了一个问题,我在组装中融入了 Assembly,我有一些类,这些类是通过 Umbraco 开源内容管理系统中的反射来调用的。

通过反射进行调用的信息取自具有程序集名称和实现的类的命名空间以及接口的 db 表。问题在于,当 dll 被合并时,反射调用会失败,但是如果 dll 是独立的,那么它就能正常工作。我想问题可能类似于长寿的一个?

在我看来,ILMerge 的最佳实践就是不要使用 ILMerge。相反,使用 SmartAssembly。其中一个原因是,# 2 ILMerge 最佳实践是在执行 ILMerge 之后始终运行 PEVerify,因为 ILMerge 不能保证它将正确地将程序集合并到一个有效的可执行文件中。

ILMerge 的其他缺点:

  • 在合并时,它会删除 XML 注释(如果我关心这一点,我会使用模糊处理工具)
  • 它不能正确处理创建对应的.pdb 文件

另一个值得关注的工具是 Mono.Cecil 和 Mono.Linker [2]工具。

[2] : http:// www.mono-project.com/linker

简介

这篇文章展示了如何用一个 combined .exe代替所有的 .exe + .dll files。它还保持了调试 .pdb文件的完整性。

适用于控制台应用程序

下面是 VisualStudio2010SP1的基本 Post Build String,使用。NET 4.0.我在建一个控制台。与所有子。包含的 dll 文件。

"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards

基本提示

  • 输出是一个文件“ AssemblyName.all.exe”,它将所有子 dll 合并到一个. exe 中。
  • 注意 ILMerge\目录。您需要将 ILMerge 实用程序复制到您的解决方案目录中(这样您就可以分发源代码而无需担心记录 ILMerge 的安装) ,或者更改此路径以指向 ILMerge.exe 所在的位置。

提示

如果您有问题,它不工作,打开 Output,并选择 Show output from: Build。检查 VisualStudio 实际生成的确切命令,并检查错误。

生成脚本示例

这个脚本用一个 combined .exe代替了所有的 .exe + .dll files

使用时,将其粘贴到 C # 项目的 Build Events选项卡下的 Post Build步骤中,并确保调整第一行中指向 ILMerge.exe的路径:

rem Create a single .exe that combines the root .exe and all subassemblies.
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
rem Remove all subassemblies.
del *.dll
rem Remove all .pdb files (except the new, combined pdb we just created).
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).all.pdb.temp"
del *.pdb
ren "$(TargetDir)$(TargetName).all.pdb.temp" "$(TargetName).all.pdb"
rem Delete the original, non-combined .exe.
del "$(TargetDir)$(TargetName).exe"
rem Rename the combined .exe and .pdb to the original project name we started with.
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).pdb"
ren "$(TargetDir)$(TargetName).all.exe" "$(TargetName).exe"
exit 0

我知道这是一个老问题,但我们不仅使用 ILMerge 来减少依赖关系的数量,而且还内化“内部”依赖关系(如自动化程序,restSharp 等) ,这是由实用程序使用。这意味着它们是完全抽象的,并且使用合并实用程序的项目不需要知道它们。这又一次减少了项目中所需的引用,并允许它在需要时使用/更新相同外部库的自己版本。

我们在组合 WPF 依赖项时遇到了同样的问题... ..。ILMerge 似乎没有处理这些问题。哥斯图拉。然而,福迪为我们完美地工作,并花了大约5分钟开始... 一个非常好的经验。

只需使用 Nuget 安装(在 Package Manager Console 中选择正确的默认项目)。它将自己引入到目标项目中,默认设置立即为我们工作。

它合并标记为“ CopyLocal”= true 的所有 DLL 并生成一个合并的。EXE (与标准输出放在一起) ,它的大小被很好地压缩(比总输出大小小得多)。

许可证是 MIT 的,因此您可以根据需要进行修改/分发。

Https://github.com/fody/costura/

我刚开始使用 ILMerge 作为我的 CI 构建的一部分,将许多细粒度的 WCF 契约合并到一个库中。它工作得非常好,但是新合并的库不能轻松地与其组件库或其他依赖于这些组件库的库共存。

在一个新的项目中,如果你同时引用 ILMerge 库和一个依赖于你给 ILMerge 的输入的遗留库,你会发现如果不进行某种类型映射(例如自动映射或手动映射) ,你就不能将任何类型从 ILMerge 库传递到遗留库中的任何方法。这是因为一旦编译了所有内容,类型就会被有效地限定为程序集名称。

名称也会发生冲突,但是您可以使用 外部化名修复这个问题。

我的建议是避免在合并程序集中包含合并程序集公开的任何公开可用的库(例如,通过返回类型、方法/构造函数参数、字段、属性、泛型...) ,除非您确切知道合并程序集的用户不会也永远不会依赖于同一库的独立版本。

注意,对于 Windows GUI 程序(例如 WinForms) ,您需要使用/target: 葡萄酒开关。< br/>/target: 前任开关创建一个合并的 控制台应用程序。