using ILMerge with .NET 4 libraries
Solution 1
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.
Solution 2
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
Solution 3
Other alternatives:
- Combining multiple assemblies into a single EXE for a WPF application.
- .Net Reactor.
- SmartAssembly (a quite pricey commercial alternative).
Solution 4
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
Solution 5
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.
Sarah Vessels
I'm a software developer at GitHub, working out of Nashville, Tennessee. I love black tea and electropop, puns and hot chicken. When I'm not writing code, I'm playing video games like Skyrim, Diablo 3, and The Sims series. I sometimes blog about video games and tech.
Updated on July 09, 2022Comments
-
Sarah Vessels almost 2 years
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 theTypeLoadException
is defined in a public class inMyILMergedDLL
, 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); }
-
Sarah Vessels almost 14 yearsThanks for the info. I can't tell from looking at that page what the releases are for: VS 2010, C#, .NET 4, ILMerge?
-
Sarah Vessels almost 14 yearsNever mind, digging around on Mike Barnett's page I see he works on ILMerge. :)
-
Sarah Vessels almost 14 yearsYES! I didn't download any new release, but I'm still marking yours as the correct answer (the only one at the moment...) because it led me to visit Mike Barnett's page where he described using
/targetplatform:v4,<path to your v4 framework directory>
instead of/targetplatform:v4 /lib:<path to your v4 framework directory>
. -
Jeremy McGee over 13 yearsHere's a link to Mike's ILMerge main page: research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx
-
Contango about 13 yearsThanks for the comment - added /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 and it worked for me as well. I'm using .NET 4.0 and Visual Studio 2010 SP1.
-
ATL_DEV almost 13 yearsSmartAssembly may be pricey in comparison, but what is your time worth? I've spent far more money in billable hours than SmartAssembly costs to find out that the alternatives don't work and are impossible to debug. This "pricey" product is backed by quality, ease-of-use and excellent support.
-
Contango about 12 yearsUpdate: Just tried this string on a rather complex project with 10 custom sub-assemblies, and it worked perfectly.
-
Despertar about 10 yearsFor those merging with a .dll as the output, you have to change /target:exe to /target:library AND remove "$(TargetDir)$(TargetFileName)" otherwise it will load the main .dll there and in the wildcard *.dll resulting in a "ILMerge.Merge: ERROR!!: Duplicate type" error.
-
Barrett about 10 yearsI needed to use
/targetplatform:v4,C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0
because I was deploying the application to a machine running .NET 4.0 and not 4.5 (I think): mattwrock.com/post/2012/02/29/… -
user1703401 over 9 yearsDo beware that your post has a really nasty bug.
-
Mike Kelly over 9 yearsILMerge is now a NuGet package. If you install it from there, it is put in packages, so I modified the command line to: "$(SolutionDir)\packages\ilmerge.2.14.1208\tools\ILMerge.exe"
-
brenjt almost 9 yearsWhere do you place this file? What do you name it?
-
sebagomez almost 9 yearsif not present, you need to create an
ildasm.exe.config
file with the xml I put in my answer