How to Integrate ILMerge into Visual Studio Build Process to Merge Assemblies?

Visual StudioVisual Studio-2008MsbuildIlmerge

Visual Studio Problem Overview


I want to merge one .NET DLL assembly and one C# Class Library project referenced by a VB.NET Console Application project into one command-line console executable.

I can do this with ILMerge from the command-line, but I want to integrate this merging of reference assemblies and projects into the Visual Studio project. From my reading, I understand that I can do this through a MSBuild Task or a Target and just add it to a C#/VB.NET Project file, but I can find no specific example since MSBuild is large topic. Moreover, I find some references that add the ILMerge command to the Post-build event.

  1. How do I integrate ILMerge into a Visual Studio (C#/VB.NET) project, which are just MSBuild projects, to merge all referenced assemblies (copy-local=true) into one assembly?

  2. How does this tie into a possible ILMerge.Targets file?

  3. Is it better to use the Post-build event?

Visual Studio Solutions


Solution 1 - Visual Studio

The "MSBuild ILMerge task" (or MSBuild.ILMerge.Task) NuGet package makes this process quite simple. It defaults to merging any "copy local" references into your main assembly.

Note: Although the packages have similar names, this one is different from ILMerge.MSBuild.Tasks that Davide Icardi mentioned in his answer. The one I'm suggesting here was first published in August 2014.

Solution 2 - Visual Studio

Here an alternative solution:

  1. Install ILMerge.MSBuild.Tasks package from nuget

> PM> Install-Package ILMerge.MSBuild.Tasks

  1. Edit the *.csproj file of the project that you want to merge by adding the code below:

    $(ProjectDir)$(OutDir)MERGED_ASSEMBLY_NAME.exe

  2. Build your project as usual.

Solution 3 - Visual Studio

Some more information that might be useful to some people implementing Scott Hanselman's solution.

When I first set this up it would complain about not being able to resolve references to System.Core, etc. It is something to do with .NET 4 support. Including a /lib argument pointing to the .NET 4 Framework directory fixes it (in fact just include the $(MSBuildBinPath)).

/lib:$(MSBuildBinPath)

I then found that IlMerge would hang while merging. It was using a bit of CPU and a lot of RAM but wasn't outputting anything. I found the fix on stackoverflow of course.

/targetplatform:v4

I also found that some of the MSBuild properties used in Scott's blog article relied on executing MsBuild from the project's directory, so I tweaked them a bit.

I then moved the targets & ilmerge.exe to the tools folder of our source tree which required another small tweak to the paths...

I finally ended up with the following Exec element to replace the one in Scott's original article:

<Exec Command="&quot;$(MSBuildThisFileDirectory)Ilmerge.exe&quot; /lib:$(MSBuildBinPath) /targetplatform:v4 /out:@(MainAssembly) &quot;$(MSBuildProjectDirectory)\@(IntermediateAssembly)&quot; @(IlmergeAssemblies->'&quot;%(FullPath)&quot;', ' ')" /> 

UPDATE I also found Logic Labs answer about keeping the CopyLocal behaviour and just excluding ilMerged assemblies from CopyLocal essential if you are using Nuget packages. Otherwise you need to specify a /lib argument for each package directory of referenced assemblies that aren't being merged.

Solution 4 - Visual Studio

The article Mixing Languages in a Single Assembly in Visual Studio seamlessly with ILMerge and MSBuild at http://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlesslyWithILMergeAndMSBuild.aspx demonstrates how to use ILMerge and MSBuild within a Visual Studio Project.

Solution 5 - Visual Studio

One issue I found with the article at: http://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlesslyWithILMergeAndMSBuild.aspx.

If you have any references that you do not wish to ILMerge then the code in the article fails because it overrides the default CopyLocal behaviour to do nothing.

To fix this - Instead of:

<Target Name="_CopyFilesMarkedCopyLocal"/> 

Add this entry to the targets file instead (.NET 3.5 only) (to filter out the non-ilmerge copylocal files, and treat them as normal)

<Target Name="AfterResolveReferences">
    <Message Text="Filtering out ilmerge assemblies from ReferenceCopyLocalPaths" Importance="High" />
    <ItemGroup>
        <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.IlMerge)'=='true'" />
    </ItemGroup>
</Target>

Solution 6 - Visual Studio

This is a great article that will show you how to merge your referenced assemblies into the output assembly. It shows exactly how to merge assemblies using msbuild.

Solution 7 - Visual Studio

My 2 cents - I picked up @Jason's response and made it work for my solution where I wanted to generate the *.exe in the bin/Debug folder with all *.dlls inside the same folder.

<Exec Command="&quot;$(SolutionDir)packages\ILMerge.2.13.0307\Ilmerge.exe&quot; /wildcards /out:&quot;$(SolutionDir)..\$(TargetFileName)&quot; &quot;$(TargetPath)&quot; $(OutDir)*.dll" /> 

Note: This solution is obviously hardcoded into the ILMerge nuget package version. Please let me know if you have some suggestions to improve.

Solution 8 - Visual Studio

Edit the *.csproj file of the project that you want to merge by adding the code below:

<Target Name="AfterBuild" Condition=" '$(ConfigurationName)' == 'Release' " BeforeTargets="PostBuildEvent">
  <CreateItem Include="@(ReferenceCopyLocalPaths)" Condition="'%(Extension)'=='.dll'">
    <Output ItemName="AssembliesToMerge" TaskParameter="Include" />
  </CreateItem>
  <Exec Command="&quot;$(SolutionDir)packages\ILMerge.3.0.29\tools\net452\ILMerge.exe&quot; /internalize:&quot;$(MSBuildProjectPath)ilmerge.exclude&quot; /ndebug  /out:@(MainAssembly)  &quot;@(IntermediateAssembly)&quot; @(AssembliesToMerge->'&quot;%(FullPath)&quot;', ' ')" />
  <Delete Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>

Notes:

  1. Replace $(SolutionDir)packages\ILMerge.3.0.29\tools\net452\ILMerge.exe with whatever path you have the ILMerge.exe in.
  2. You can remove the Condition in the target to also merge on Debug but then the Debugger might not work
  3. If you are not excluding anything you can remove: /internalize:&quot;$(MSBuildProjectPath)ilmerge.exclude&quot;

Solution 9 - Visual Studio

Check out this article by Jomo. He has a quick process to hack ILMerge into the msbuild system

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAMissicoView Question on Stackoverflow
Solution 1 - Visual StudioHolistic DeveloperView Answer on Stackoverflow
Solution 2 - Visual StudioDavide IcardiView Answer on Stackoverflow
Solution 3 - Visual StudioJason DuffettView Answer on Stackoverflow
Solution 4 - Visual StudioAMissicoView Answer on Stackoverflow
Solution 5 - Visual StudioLogic LabsView Answer on Stackoverflow
Solution 6 - Visual StudioRohan WestView Answer on Stackoverflow
Solution 7 - Visual StudioruiView Answer on Stackoverflow
Solution 8 - Visual StudioN TView Answer on Stackoverflow
Solution 9 - Visual StudioJaredParView Answer on Stackoverflow