当编写规模稍大一点的程序时,需要进行模块划分。我们一般是对每个模块建一个工程,输出一个类库,这样就形成了一个exe加多个类库的解放方案。这样本身是没有什么问题的,就是发布上稍微有点麻烦,需要发布一个exe加多个dll文件。特别是那些需要经常更新的程序,其实本身可能并不大,一共也就几百kb,但每次还要发布三四个dll确实令人厌烦,做成安装包就更没必要了。
在C++中,我们一般可以通过静态链接解决这种问题,但在.net中却不行,每个类库只能输出dll,VisualStudio官方也没有提供静态链接的选项,其实从理论上讲要想合并似乎也不难,ildasm能够把.NET程序反编译成il,那么把两个il合并到一个il当中再用il编译就可以了。虽然M$却没有直接提供这种功能,但M$的一位大牛提供了一个工具ILMerge可以实现这种功能,可以在http://research.microsoft.com/~mbarnett/ILMerge.aspx下载。
网上也有一些文章对这个工具进行了介绍,margiex的blog中的说明就介绍的较简明扼要,这里转录一下:
ilmerge /ndebug /target:exe /targetplatform:v1.1 /out:newclient.exe oldclient.exe /log AutoUpdater.dll DockingSuite.dll DocumentManager.dll FileHelpers.dll OutlookBar.dll SandBar.dll ICSharpCode.SharpZipLib.dll
解释如下:
- target: 指定输出组件的类型,有DLL/EXE/WINEXE; (如果是EXE,则程序在执行的时候将出现一个DOS窗口(即使是WINFORM的程序). 因此应该设置target为winexe)
- targetplatform: 输出组件的.net运行版本;
- out: 合并后的组件全名;
后面是主要的被合并的组件名称, 及相关所有的其它DLL;
上面的示例只是合并为EXE, 也可以多个DLL合并成一个DLL使用, 各自的命名空间不会改变;
- 不能合并interop这种由COM转换过来的DLL; (可以合并,但相关依赖的DLL必须也一起合并, 第一次合并的时候只有Excel.dll,总是报错,以为是interop的缘故,后来才发现是没有合并vbide.dll的缘故,复制到目录再一起合并,一切OK.)
- 如果有资源DLL, 应该将要被合并的oldclient.exe先改为别的名称,然后合并后的输出命名为:oldclient.exe,因为资源文件名是:oldclient.resources.dll,而ILMERGE不能合并资源文件,否则在导出后将找不到此资源文件。(如果哪位知道如何合并资源文件,请指教,谢谢)
- 虽然合并后的EXE比较大,但在用户那里只有一个EXE,这样直观的多,也容易升级维护.
原文地址:http://www.cnblogs.com/margiex/archive/2008/06/24/302329.html
具体的详细使用文档请参看它的说明文档,还是很简单的。
另外,也可以通过编程的方式来调用ILMerge的库来实现简化合并,这里转录一下CodeProject上的一篇文章Post build step static linking tool for C#, using ILMerge的代码:
Code
using System;
using System.Text;
using System.Collections;
namespace HTMerge
{
class Program
{
static void Main(string[] args)
{
try
{
String strDir = "";
if (args.Length != 1)
{
Console.WriteLine("Usage: HTMerge directoryName");
return;
}
else
{
strDir = args[0];
}
String[] exeFiles = System.IO.Directory.GetFiles(strDir, "*.exe");
String[] dllFiles = System.IO.Directory.GetFiles(strDir, "*.dll");
ArrayList ar = new ArrayList();
Boolean bAdded = false;
//there might be more than 1 exe file,
//we go for the first one that isn't the vshost exe
foreach (String strExe in exeFiles)
{
if (!strExe.Contains("vshost"))
{
ar.Add(strExe);
bAdded = true;
break;
}
}
if (!bAdded)
{
Console.WriteLine("Error: No exe could be found");
//I know multiple returns are bad�
return;
}
bAdded = false;
foreach (String strDLL in dllFiles)
{
ar.Add(strDLL);
bAdded = true;
}
//no point merging if nothing to merge with!
if (!bAdded)
{
Console.WriteLine("Error: No DLLs could be found");
//I know multiple returns are bad�
return;
}
//You will need to add a reference to ILMerge.exe from Microsoft
//See http://research.microsoft.com/~mbarnett/ILMerge.aspx
ILMerging.ILMerge myMerge = new ILMerging.ILMerge();
String[] files = (String[])ar.ToArray(typeof(string));
String strTargetDir = strDir + "\\Merged";
try
{
System.IO.Directory.CreateDirectory(strTargetDir);
}
catch
{
}
//Here we get the first file name
//(which was the .exe file) and use that
// as the output
String strOutputFile = System.IO.Path.GetFileName(files[0]);
myMerge.OutputFile = strTargetDir + "\\" + strOutputFile;
myMerge.SetInputAssemblies(files);
myMerge.Merge();
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Error :{0}",ex.Message));
}
}
}
}
另外,需要说明的是,这个工具目前支持的是.net 2.0,那些.net 3.0 3.5的程序由于是和.net2.0同一个clr,也可以使用(我试过的)。