ILMerge 最佳实践

Posted

技术标签:

【中文标题】ILMerge 最佳实践【英文标题】:ILMerge Best Practices 【发布时间】:2010-09-05 18:43:45 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

我将 ILMerge 用于几乎所有不同的应用程序。我将它直接集成到发布构建过程中,所以我最终得到的是每个应用程序一个 exe,没有额外的 dll。

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

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

【讨论】:

你是如何进行发布构建集成的? @Svish -- hanselman.com/blog/… 以下是 ILMerge + XAML 的潜在解决方法:richarddingwall.name/2009/05/14/… roman.st/Article/ILMerge-and-GeneratedInternalTypeHelper - ILMerge + XAML 的另一种解决方法 @Lamar 你能分享 ILMerge 的包装器 .exe 吗?【参考方案2】:

简介

这篇文章展示了如何用一个combined .exe 替换所有.exe + .dll files。它还保持调试.pdb文件完好无损。

对于控制台应用程序

这是使用 .NET 4.0 的 Visual Studio 2010 SP1 的基本 Post Build String。我正在构建一个包含所有 sub-.dll 文件的控制台 .exe。

"$(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。检查 Visual Studio 实际生成的确切命令,并检查错误。

示例构建脚本

此脚本将所有.exe + .dll files 替换为单个combined .exe。它还保持调试 .pdb 文件完好无损。

要使用,请将其粘贴到您的 Post Build 步骤中,在 C# 项目的 Build Events 选项卡下,并确保将第一行中的路径调整为指向 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

【讨论】:

见***.com/questions/2961357/… 如何显示构建的输出?我在编写输出时遇到了静默问题。 ***.com/questions/42301103/… @octopusgrabbus 在 Visual Studio 中,选择View.. Output,选择Build,它会显示编译器的命令行输出(包括上述步骤)。或者,将这些命令复制到 .bat 文件中,然后从 DOS 窗口运行它以查看输出。【参考方案3】:

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

合并文件后,我必须编辑visual studio项目列表,删除12个单独的程序集并添加单个文件作为参考,否则它会抱怨找不到特定的程序集。不过,我不太确定这在部署后如何工作,值得一试。

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

我们在很多项目中使用 ILMerge。例如,Web Service Software Factory 会生成 8 个程序集作为其输出。我们将所有这些 DLL 合并到一个 DLL 中,这样服务主机只需引用一个 DLL。

它让生活更轻松,但也没什么大不了的。

【讨论】:

【参考方案6】:

我们在合并 WPF 依赖项时遇到了同样的问题.... ILMerge 似乎无法处理这些问题。 Costura.Fody 非常适合我们,但花了大约 5 分钟才开始……非常好的体验。

只需使用 Nuget 安装(在包管理器控制台中选择正确的默认项目)。它将自己引入目标项目,默认设置立即为我们工作。

它合并所有标记为“Copy Local”=true 的 DLL,并生成一个合并的 .EXE(与标准输出一起),它的大小被很好地压缩(远小于总输出大小)。

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

https://github.com/Fody/Costura/

【讨论】:

【参考方案7】:

请注意,对于 Windows GUI 程序(例如 WinForms),您需要使用 /target:winexe 开关。 /target:exe 开关创建一个合并的控制台应用程序。

【讨论】:

【参考方案8】:

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

如果在一个新项目中,您既引用了 ILMerged 库,也引用了依赖于您提供给 ILMerge 的输入之一的旧库,您会发现无法将 ILMerged 库中的任何类型传递给遗留库中的任何方法,无需进行某种类型映射(例如自动映射器或手动映射)。这是因为一旦所有内容都编译完毕,这些类型就会有效地使用程序集名称进行限定。

名称也会发生冲突,但您可以使用 extern alias 解决此问题。

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

【讨论】:

【参考方案9】:

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

【讨论】:

【参考方案10】:

我们刚刚开始在我们的解决方案中使用 ILMerge,这些解决方案在我们的其他项目中重新分发和使用,到目前为止效果很好。一切似乎都正常。我们甚至直接混淆了打包的程序集。

我们正在考虑对 MS 企业库程序集做同样的事情。

我看到的唯一真正问题是包中各个程序集的版本控制。

【讨论】:

【参考方案11】:

我最近遇到了问题,我在程序集中合并了程序集,我有一些类是通过 Umbraco 开源 CMS 中的反射调用的。

通过反射进行调用的信息取自 db 表,该表具有程序集名称和实现和接口的类的命名空间。问题是当 dll 被合并时反射调用会失败,但是如果 dll 是分开的,它就一切正常。我认为问题可能与 longeasy 的问题类似?

【讨论】:

【参考方案12】:

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

ILMerge 的其他缺点:

合并时,它会去除 XML 注释(如果我关心这个,我会使用混淆工具) 它无法正确处理创建相应的 .pdb 文件

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

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

【讨论】:

“它没有正确处理创建相应的 .pdb 文件”——在什么情况下这是真的?我看过 ILMerge 生成合并的 pdb,并毫无问题地使用它们。 当您要合并的任何程序集还没有 .pdb 时。此外,SmartAssembly 可以正确处理 BAML 等 WPF 资源。 ILMerge 与 Smartassembly 相比的一大优势在于,它将合并 XML 文档文件。自发布之日起,Smartassembly 不会这样做。 - 付费 Smartassembly 用户

以上是关于ILMerge 最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

后端日志最佳实践

DAO(数据访问对象)最佳实践 - 我看到的示例同时使用 DAO 和服务对象,这里的最佳实践是啥?

平均堆栈身份验证 - 最佳实践

Activity的最佳实践

Openstack迁移DDH最佳实践

Ansible — 示例与最佳实践