Post build step static linking tool for C#, using ILMerge






4.62/5 (12 votes)
Dec 1, 2005
2 min read

82368

765
Post build step static linking tool for C#, using ILMerge.
Introduction
So there I was, wanting to release an application of mine, but I didn’t want to release all the assemblies that my application used. Why? Well, that would be exporting some functionality that this particular app didn’t use, and even though it was dotfuscated, it just felt wrong.
It turns out that .NET, and even .NET 2.0, despite people asking for it, does not support static linking. For those not sure what that is – static linking is when you don’t compile to a DLL, you compile to a .lib, and then the whole thing gets linked together into one .exe file.
There are many arguments as to the pros & cons of static linking, and I am not going to get into that here – suffice to say that I wanted to static link – which is good enough for me.
So – off to Google I go, and I find that Microsoft has a tool called ILMerge, which takes a plethora of parameters. What ILMerge does is de-compile .NET assemblies and then build them all into one primary assembly. Yes, it does .NET 2.0 as well.
You can also use ILMerge within your own applications as it exposes an interface, so you can just reference it (obviously, you can only do this in VS 2005, as prior to that, you cannot use .exe files as a reference – you can however get around this in 2003 if you so wish – search CodeProject – it has been done in here!).
What HTMerge (Hollingside Technologies Merge) does is make it so simple that I just have a post build step as:
htmerge "$(TargetDir)
The “ before the $ is to ensure that directory paths with spaces in are parsed correctly. This does assume that HTMerge is on the path. Given that parameter as a post build step, all assemblies that are part of your application are merged into one .exe file, which is stored in a subdirectory called merged beneath the debug/release directory.
As it stands, this code only works properly when building a .exe type project, but the concept stands.
Hope someone finds this useful!
The 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));
}
}
}
}