题
你用ILMerge吗?您是否使用 ILMerge 合并多个程序集以简化 dll 的部署?在将程序集合并在一起后,您是否发现生产中的部署/版本控制存在问题?
我正在寻找一些有关使用 ILMerge 减少部署摩擦的建议(如果可能的话)。
解决方案
我几乎将 ILMerge 用于所有不同的应用程序。我将其集成到发布构建过程中,因此我最终得到的是每个应用程序一个 exe,没有额外的 dll。
您无法 ILMerge 任何具有本机代码的 C++ 程序集。您也无法 ILMerge 任何包含 WPF XAML 的程序集(至少我在这方面没有取得任何成功)。它在运行时抱怨无法找到资源。
我确实为 ILMerge 编写了一个包装器可执行文件,其中传入要合并的项目的启动 exe 名称和输出 exe 名称,然后它反映依赖程序集并使用适当的命令行参数调用 ILMerge。现在,当我向项目添加新程序集时,事情变得容易多了,我不必记住更新构建脚本。
其他提示
介绍
这篇文章展示了如何替换所有 .exe + .dll files
与单个 combined .exe
. 。它还保留了调试 .pdb
文件完好无损。
对于控制台应用程序
这是基本的 Post Build String
对于 Visual Studio 2010 SP1,使用 .NET 4.0。我正在构建一个控制台 .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 实用程序复制到解决方案目录中(这样您就可以分发源代码,而不必担心记录 ILMerge 的安装),或者更改此路径以指向 ILMerge.exe 所在的位置。
高级提示
如果您遇到无法正常工作的问题,请打开 Output
, ,然后选择 Show output from: Build
. 。检查 Visual Studio 实际生成的确切命令,并检查是否有错误。
示例构建脚本
该脚本替换了所有 .exe + .dll files
与单个 combined .exe
. 。它还使调试 .pdb 文件保持完整。
要使用,请将其粘贴到您的 Post Build
步骤,在 Build Events
C# 项目中的选项卡,并确保将第一行中的路径调整为指向 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 个单独的程序集并添加单个文件作为参考,否则它会抱怨找不到特定的程序集。我不太确定这在部署后会如何工作,但可能值得一试。
我知道这是一个老问题,但我们不仅使用 ILMerge 来减少依赖项的数量,而且还内部化实用程序使用的“内部”依赖项(例如 automapper、restsharp 等)。这意味着它们被完全抽象出来,并且使用合并实用程序的项目不需要了解它们。这再次减少了项目中所需的引用,并允许它在需要时使用/更新同一外部库的自己版本。
我们在很多项目中使用 ILMerge。这 网络服务软件工厂, ,例如生成类似 8 个程序集作为其输出。我们将所有这些 DLL 合并到一个 DLL 中,以便服务主机只需引用一个 DLL。
它让生活变得更轻松,但这也没什么大不了的。
我们在组合 WPF 依赖项时遇到了同样的问题......ILMerge 似乎不处理这些。Costura.Fody 对我们来说工作得很好,花了大约 5 分钟才开始......非常好的体验。
只需使用 Nuget 进行安装(在包管理器控制台中选择正确的默认项目)。它将自己引入到目标项目中,默认设置立即为我们工作。
它合并所有标记为“Copy Local”= true 的 DLL,并生成合并的 .EXE(与标准输出一起),其大小得到很好的压缩(远小于总输出大小)。
该许可证是 MIT 的,因此您可以根据需要修改/分发。
请注意,对于 Windows GUI 程序(例如 WinForms),您需要使用 /target:执行程序 转变。
目标:EXE文件 switch 创建一个合并的 安慰 应用。
当合并具有相同命名空间的资源的 DLL 时,我们遇到了问题。在合并过程中,资源名称空间之一被重命名,因此无法找到资源。也许我们只是在那里做错了什么,仍在调查这个问题。
我们刚刚开始在我们的解决方案中使用 ILMerge,这些解决方案已重新分发并在我们的其他项目中使用,到目前为止一切顺利。一切似乎都正常。我们甚至直接对打包的程序集进行了混淆。
我们正在考虑对 MS Enterprise Library 程序集执行相同的操作。
我看到的唯一真正的问题是包中各个程序集的版本控制。
我最近遇到了一个问题,我在程序集中合并了程序集,我有一些类,这些类是通过 Umbraco 开源 CMS 中的反射调用的。
通过反射进行调用的信息取自数据库表,该表具有程序集名称以及实现的类和接口的命名空间。问题是,当 dll 合并时,反射调用会失败,但是如果 dll 是单独的,则一切正常。我认为问题可能与 longeasy 遇到的问题类似?
我刚刚开始使用 ILMerge 作为 CI 构建的一部分,将大量细粒度的 WCF 合约组合到一个库中。它工作得很好,但是新的合并库无法轻松与其组件库或依赖于这些组件库的其他库共存。
如果在新项目中,您既引用了 ILMerged 库,又引用了依赖于您提供给 ILMerged 的输入之一的遗留库,您会发现无法将任何类型从 ILMerged 库传递到中的任何方法。遗留库不进行某种类型映射(例如自动映射器或手动映射)。这是因为一旦所有内容都编译完毕,类型就可以使用程序集名称进行有效限定。
名称也会发生冲突,但您可以使用以下方法修复该问题 外部别名.
我的建议是避免在合并程序集中包含合并程序集公开的任何公开可用的库(例如通过返回类型、方法/构造函数参数、字段、属性、泛型...)除非您确定合并程序集的用户不会也永远不会依赖同一库的独立版本。
在我看来,#1 ILMerge 最佳实践是不要使用 ILMerge。相反,使用 智能装配. 。原因之一是,#2 ILMerge 最佳实践是在执行 ILMerge 后始终运行 PEVerify,因为 ILMerge 不保证它将正确地将程序集合并到有效的可执行文件中。
ILMerge 的其他缺点:
- 合并时,它会删除 XML 注释(如果我关心这一点,我会使用混淆工具)
- 它无法正确处理创建相应的 .pdb 文件
另一个值得关注的工具是 Mono.Cecil 和 Mono.Linker [2] 工具。
[2]:http://www.mono-project.com/Linker