ILMerge最佳实践

你用ILMerge吗? 你使用ILMerge来合并多个程序集以缓解dll的部署吗? 在将ILMerging程序集合在一起之后,您是否发现部署/版本控制方面的问题?

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

我使用ILMerge来处理几乎所有不同的应用程序。 我把它集成到发布构build过程中,所以我最终得到的是每个应用程序一个exe,没有额外的dll。

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

我为ILMerge编写了一个包装程序可执行文件,其中我传入了要合并的项目的启动exe名称和一个输出exe名称,然后它反映了相关的程序集并使用适当的命令行参数调用ILMerge。 现在,当我将新的程序集添加到项目中时,我不必记住更新构build脚本。

介绍

这篇文章展示了如何用一个单独的combined .exe .exe + .dll filesreplace所有的.exe + .dll files 。 它也保持debugging.pdb文件不变。

对于控制台应用

这是Visual Studio 2010 SP1的基本Post Build String ,使用.NET 4.0。 我正在构build一个控制台.exe,其中包含的所有子.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实用程序复制到您的解决scheme目录中(这样您可以分发源代码而不必担心loggingILMerge的安装问题),或者将此path更改为指向ILMerge.exe所在的位置。

先进的提示

如果您在使用中遇到问题,请打开“ Output ,然后select“ Show output from: Build 。 检查Visual Studio实际生成的确切命令,并检查错误。

示例生成脚本

此脚本将所有.exe + .dll filesreplace为一个combined .exe 。 它也保持debugging.pdb文件不变。

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

我们在Microsoft应用程序块上使用ILMerge,而不是12个独立的DLL文件,我们有一个文件可以上传到我们的客户区,再加上文件系统结构很简单。

合并文件后,我不得不编辑Visual Studio项目列表,删除12个单独的assmeblies并添加单个文件作为参考,否则它会抱怨说找不到特定的程序集。 我不太清楚这将如何工作后部署虽然,可能值得一试。

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

我们在很多项目上使用ILMerge。 Web服务软件工厂 ,例如产生类似8个组件的输出。 我们将所有这些DLL合并到一个DLL中,以便服务主机只需引用一个DLL。

它让生活变得轻松一点,但也不是什么大不了的事情。

我们有相同的问题,结合WPF依赖…. ILMerge似乎并没有处理这些。 Costura.Fody为我们完美的工作,然后花了大约5分钟去…一个非常好的经验。

只需使用Nuget进行安装(在软件包pipe理器控制台中select正确的默认项目)。 它将自己介绍到目标项目中,并且默认设置立即为我们工作。

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

许可证是麻省理工学院,因此您可以根据需要修改/分发。

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

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

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

我们刚刚开始在我们的解决scheme中使用ILMerge,这些解决scheme在我们的其他项目中被重新分配和使用,并且非常好。 一切似乎工作正常。 我们甚至直接模糊了包装的组件。

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

我看到的唯一真正的问题是来自软件包的单个程序集的版本控制。

我最近有一个问题,我在程序集中ilmerged大会我有一些类,这些被称为通过在Umbraco开源CMS反思。

通过reflection进行调用的信息取自具有实现的类名称和名称空间的db表。 问题是reflection调用会失败,当DLL合并,但如果DLL是分开的,一切工作正常。 我觉得问题可能类似于一个长久以来的事情?

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

如果在一个新项目中引用ILMerged库和一个依赖于你给ILMerge的input的遗留库,你会发现你不能将任何types的ILMerged库传递给遗留的库没有做某种types的映射(例如自动映射器或手动映射)。 这是因为一旦所有东西都被编译了,这些types就会被一个程序集名称所限定。

名字也会碰撞,但你可以使用extern别名修复。

我的build议是避免在你的合并程序集中包含你的合并程序集公开的lib(例如通过返回types,方法/构造函数参数,字段,属性,generics…),除非你确定您的合并程序集不会,也不会依赖于同一个库的独立版本。

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

其他ILMerge缺点:

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

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

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