Ilmerge Best Practices

ILMerge Best Practices

I use ILMerge for almost all of my different applications. I have it integrated right into the release build process so what I end up with is one exe per application with no extra dll's.

You can't ILMerge any C++ assemblies that have native code.
You also can't ILMerge any assemblies that contain XAML for WPF (at least I haven't had any success with that). It complains at runtime that the resources cannot be located.

I did write a wrapper executable for ILMerge where I pass in the startup exe name for the project I want to merge, and an output exe name, and then it reflects the dependent assemblies and calls ILMerge with the appropriate command line parameters. It is much easier now when I add new assemblies to the project, I don't have to remember to update the build script.

Best practices for merging assemblies?

The short, easy version:

Every reference within one process to a given Assembly should reference the same version.

If you don't, you might get into deep troubles because one part of the app cannot talk to another due to version mismatch.

Even with "really private" stuff like log4net you might miss out on possibilities for shared configuration space, like using a common root logger for all parts of the app. Of course, the final call in this case is -- as always -- with the responsible developer.

See also this other question about ILMerge and 3rd party assemblies.

When & How to use ILMerge with Visual Studio Project / Solution

The question ILMerge Best Practices
has good info on why.

When I use ILMerge, I use it to build a single DLL, to simplify deployment.

As to How, I define a separate, custom VS project, "Converged.csproj" if you like. In that .csproj file I define a custom Compile target. It is boilerplate code, that performs an ILMerge on all the referenced assemblies for the project.

It looks like this:

<Target Name="Compile">
<!-- Outputs="$(IntermediateOutputPath)$(TargetFileName)" -->
<!-- Outputs="$(TargetPath)" -->
<Message Text="Performing the Ilmerge." />
<!-- in this CreateItem stanza, we collect all the DLLs for the referenced projects -->
<CreateItem Include="@(_ResolvedProjectReferencePaths)">
<Output TaskParameter="Include" ItemName="AssembliesToMerge" />
</CreateItem>
<!-- This weird bit of hieroglyphics is the assemblies to merge, quoted, and separated by spaces -->
<!-- Example: "c:\foo\project1\bin\Debug\ProjectOne.dll" "c:\foo\project2\bin\Debug\ProjectTwo.dll" -->
<Message Text="AssembliesToMerge= @(AssembliesToMerge -> '"%(Fullpath)"', ' ')" />
<!-- Message Text="TargetPath= $(TargetPath)" / -->
<Message Text="TargetFileName= $(TargetFileName)" />
<!-- produce the merged assembly - putting the output in the "IntermediateOutputPath" eg obj\Debug. -->
<!-- it will be copied later by the CopyFilestoOutputDirectory task defined in Microsoft.Common.Targets -->

<Error
Text="ILMerge cannot be found. You need to download and install ILMerge in order to build DotNetZip."
Condition="!Exists('$(ProgramFiles)\Microsoft\Ilmerge\Ilmerge.exe')" />

<Exec Command=""$(ProgramFiles)\Microsoft\Ilmerge\Ilmerge.exe" /t:library /xmldocs /out:"$(IntermediateOutputPath)$(TargetFileName)" @(AssembliesToMerge -> '"%(Fullpath)"', ' ') " />

<!-- for some reason the XML doc file does not get copied automatically from obj\Debug to bin\Debug. -->
<!-- we do it here explicitly. -->
<Copy SourceFiles="$(IntermediateOutputPath)$(AssemblyName).XML" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)" />
</Target>

how to use ILMerge to combine several assemblies into one

Finally, I find the solution:

After installing the package and building the application, I copy all files in net452(solution packages folder -> ILMerge folder -> tools -> net452).Then I paste it to the path my app built(\bin\Debug).

Then I open the command prompt and cd to my directory and insert the following code:

ILMerge.exe /target:winexe /target:exe /out:filepath nameofexe mydll

It works well!

Drawbacks, advantages, etc. between ILMerge or ResolveAssembly for embedding assemblies?

I've since found this blog post from Jeffrey Richter and I think it answers adequately my question.

using ILMerge with .NET 4 libraries

There was a very recent release to solve x64 problems. Get in touch with Mike Barnett directly if you still have problems (mbarnett at microsoft dot com)


Addendum. There's something very, very wrong about your /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" option. This has been getting lots of programmers in trouble lately, after .NET 4.5 was released. That directory is not the proper one for .NET 4.0 reference assemblies. Its content gets overwritten with the 4.5 assemblies, you can no longer use it to target a .NET 4.0 install. The runtime error you get is very awkward, the program cannot find certain types anymore. Usually bombing on the [Extension] attribute, sometimes on the ICommand interface.

These types, and some others, were moved from one assembly to another. Using the correct reference assemblies is a rock-hard requirement. You must use:

 /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"

Adjust to match your particular machine and target framework version.

Using ILMerge to merge strongly named assemblies into a single strongly named assemly in .Net

To strong-name an assembly (and to make sure only the original author can do so), one needs the private key (snk). ILMerge (or any tool that generates or modifies an assembly) also needs it.

Otherwise anyone could modify (and re-sign) an assembly, which defeats the signing purpose (guarantee authorship).



Related Topics



Leave a reply



Submit