using ILMerge with .NET 4 libraries

Two problems:

1) Basic .NET Assembly Not Included in ILMerged Assembly

I’m having trouble using ILMerge in my post-build after upgrading from .NET 3.5/Visual Studio 2008 to .NET 4/Visual Studio 2010. I have a Solution with several projects whose target framework is set to “.NET Framework 4”. I use the following ILMerge command to merge the individual project DLLs into a single DLL:

if not $(ConfigurationName) == Debug
  if exist "C:/Program Files (x86)/Microsoft/ILMerge/ILMerge.exe"
    "C:/Program Files (x86)/Microsoft/ILMerge/ILMerge.exe"
      /lib:"C:/Windows/Microsoft.NET/Framework64/v4.0.30319"
      /lib:"C:/Program Files (x86)/Microsoft Visual Studio 10.0/Common7/IDE/PublicAssemblies"
      /keyfile:"$(SolutionDir)$(SolutionName).snk"
      /targetplatform:v4
      /out:"$(SolutionDir)bin/development/$(SolutionName).dll"
      "$(SolutionDir)Connection/$(OutDir)Connection.dll"
      ...other project DLLs...
      /xmldocs 

If I leave off specifying the location of the .NET 4 framework directory, I get an “Unresolved assembly reference not allowed: System” error from ILMerge. If I leave off specifying the location of the MSTest directory, I get an “Unresolved assembly reference not allowed: Microsoft.VisualStudio.QualityTools.UnitTestFramework” error.

The ILMerge command above works and produces a DLL. When I reference that DLL in another .NET 4 C# project, however, and try to use code within it, I get the following warning:

The primary reference “MyILMergedDLL” could not be resolved because it has an indirect dependency on the .NET Framework assembly “mscorlib, Version=4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” which has a higher version “4.0.65535.65535” than the version “4.0.0.0” in the current target framework.

If I then remove the /targetplatform:v4 flag and try to use MyILMergedDLL.dll, I get the following error:

The type ‘System.Xml.Serialization.IXmlSerializable’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’.

It doesn’t seem like I should have to do that. Whoever uses my MyILMergedDLL.dll API should not have to add references to whatever libraries it references. How can I get around this?

2) TypeLoadException Only When Using Merged Assembly

Edit: beyond this, even if I do add a reference to System.Xml in the consumer project that uses MyILMergedDLL.dll, making use of some code in MyILMergedDLL.dll gives this exception:

System.TypeLoadException: Could not load type ‘System.Func`2’ from assembly ‘MyILMergedDLL, Version=1.0.1.1, Culture=neutral, PublicKeyToken=…’.

This is the code in my consumer project; the line that caused the TypeLoadException is the second one:

var keys = new[] {"a", "b", "c"};
var row = new Row(keys);

The particular Row constructor that throws the TypeLoadException is defined in a public class in MyILMergedDLL, and when I use this constructor when referencing the individual project DLLs, it works fine. It is only when I use this constructor when referencing the IL-merged DLL that I get the exception. I don’t know what’s going on.

Here’s that constructor:

public Row(IEnumerable<string> keys) : base(keys) { }

And the base to which it is referring has this code:

foreach (string key in keys.Where(
    key => !string.IsNullOrEmpty(key)
))
{
    _dic.Add(key, string.Empty);
}

Running ILMerge tool using .NET 4 on Windows 8

We are running ILMerge as a post build step and having problems when building on a Windows 8 machine. ILMerge.exe is a .NET 2 application so should be able to be loaded/hosted within the .NET 4 runtim

Build With ILMerge Error

Has anyone had this error with IlMerge? I am trying to merge a few assemblies for a .NET project using the 4.0 Framework. ILMerge /log /lib:../Libraries /targetplatform:v4 /internalize:../SolutionFile

Serious trouble with ILMerge and .NET 4.0

For the life of me, I can’t seem to get my .NET 4 application merging properly with ILMerge. Even after setting /targetplatform, /lib, /ndebug and adding a custom ILMerge.exe.config file the output fi

Merging dlls using ILMerge

I am trying to merge some dlls into one merge dll using ILMerge. i have tried several post build commands and nothing worked. C:/Program Files (x86)/Microsoft/ILMerge/ILMerge.exe /lib:C:/Windows/Micro

ILMerge for Silverlight 4

I’m trying to get ILMerge working with a SL 4 class library (no xaml). I have a post build task: <Target Name=AfterBuild> <CreateItem Condition=’%(Extension)’==’.dll’ [email protected](Referenc

Using ILMerge with log4net is causing “inaccessible due to protection level” error

I created a wrapper class for the initialization of my log4net logging objects in order to make it easier to establish custom properties in the ThreadContext. This occurs within a class library that I

ILMerge hangs on merge

I am using ILMerge to combine 9 .NET DLL’s written in C# .NET 4. The problem is ILMerge gets stuck, no error message or anything. The log shows that ILMerge merges all the assemblies correctly, then s

Using ILMerge but retaining namespaces

Is it possible to merge a couple of assemblies via ILMerge and retain the initial namespaces of all libraries? Thanks for any feedback.

.NET type definitions in merged assemblies (ILMerge)

I am merging several .NET assemblies using ILMerge including some 3rd party assemblies. Since doing so, I’ve experienced several errors that all boil down to the fact that type definitions are tied to

Application stopped logging after using ILMerge

I have a very modest application with a single external assembly (log4net.dll) that I wanted to use ILMerge on. I merge the App.exe and the log4net.dll, and the resulting executable (New.exe) appears

Answers

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)

Here is the “Post Build String” for Visual Studio 2010 SP1, using .NET 4.0. I am building a console .exe with all of the sub-.dll files included in it.

"$(SolutionDir)ILMerge/ILMerge.exe" /out:"$(SolutionDir)/deploy/$(TargetFileName)" "$(TargetDir)$(TargetFileName)" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:/Windows/Microsoft.NET/Framework64/v4.0.30319 /wildcards

Basic hints:

  • Notice the “/deploy/” directory: this is where the output .exe file ends up.
  • Notice the “ILMerge/” directory. I copied the ILMerge utility into my solution directory (so I could distribute the source without having to worry about documenting the install of ILMerge).

Advanced hints:

If you have problems with it not working, add an “echo” before the “Post Build” command. Then, open the “Output” window in Visual Studio (View..Output), and check the exact command that Visual Studio actually generated. In my particular case, the exact command was:

"T:/PhiEngine/CSharp/ILMerge/ILMerge.exe" /out:"T:/PhiEngine/CSharp/Server Side/deploy/NfServiceDataHod.History.exe" "T:/PhiEngine/CSharp/Server Side/NfServiceDataHod/bin/Debug/NfServiceDataHod.History.exe" "T:/PhiEngine/CSharp/Server Side/NfServiceDataHod/bin/Debug/*.dll" /target:exe /targetplatform:v4,C:/Windows/Microsoft.NET/Framework64/v4.0.30319 /wildcards

Update

Added this to my “Post Build” step, it replaces all .exe + .dll files with a single combined .exe. It also keeps the debugging .pdb file intact:

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 name we started with.
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).pdb"
ren "$(TargetDir)$(TargetName).all.exe" "$(TargetName).exe"
exit 0

Other alternatives:

You can also add a config file with the following:

<?xml version ="1.0"?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <requiredRuntime safemode="true" imageVersion="v4.0.30319" version="v4.0.30319"/>
  </startup>
</configuration>

Taken from here

Just set PresentationCore and PresentationFramework references to have “Copy Local = True” in the Visual Studio properties window (after selecting the references in the Solution Explorer). It will solve the problem without hard-coding the framework path. I prefer this solution because the path is different depending on whether the developer/build server is 64bit or 32bit and inevitably will change as new .NET/VS versions are released.