Pages

Friday, February 21, 2014

Automatically Embed Copy Local Assemblies with Symbols in MSBuild

Many have written about how to automatically embed assemblies into an executable, such as:
Lots of questions about this on stackoverflow as well, such as:
However, none of these show how pdb-files can be embedded as well to ensure symbols are also loaded when resolving embedded assemblies as detailed in Embedded Assembly Loading with support for Symbols and Portable Class Libraries in C#.

Automatically embed all dll- and pdb-files exclude xml-files

The solution, shown below, is a simple extension of what Daniel Chambers has described, but also includes pdb-files and exclude copying of xml-files to the output directory since many libraries often include these documentation files.
<Target Name="EmbedReferencedAssemblies" AfterTargets="ResolveAssemblyReferences">
  <ItemGroup>
    <!-- get list of assemblies marked as CopyToLocal -->
    <FilesToEmbed Include="@(ReferenceCopyLocalPaths)" 
                  Condition="('%(ReferenceCopyLocalPaths.Extension)' == '.dll' Or '%(ReferenceCopyLocalPaths.Extension)' == '.pdb')" />
    <FilesToExclude Include="@(ReferenceCopyLocalPaths)" 
                  Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.xml'" />

    <!-- add these assemblies to the list of embedded resources -->
    <EmbeddedResource Include="@(FilesToEmbed)">
      <LogicalName>%(FilesToEmbed.DestinationSubDirectory)%(FilesToEmbed.Filename)%(FilesToEmbed.Extension)</LogicalName>
    </EmbeddedResource>

    <!-- no need to copy the assemblies locally anymore -->
    <ReferenceCopyLocalPaths Remove="@(FilesToEmbed)" />
    <ReferenceCopyLocalPaths Remove="@(FilesToExclude)" />
  </ItemGroup>

  <Message Importance="high" Text="Embedding: @(FilesToEmbed->'%(Filename)%(Extension)', ', ')" />
</Target>
To use this simply copy and paste this into the executable project file (e.g. *.csproj) right after:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

Automatically embed all dll- and pdb-files exclude xml-files and mixed mode assemblies

However, unfortunately as far as I know embedding mixed mode assemblies (e.g. with both managed and native code from for example a C++/CLI project) does not work. So these still have to be copied to the build output. At least, if you do not want to extract the embedded file, as detailed in Single Assembly Deployment of Managed and Unmanaged Code.

One solution to this is to simply exclude these files by adding exclude conditions to the above xml. For example:
<Target Name="EmbedReferencedAssemblies" AfterTargets="ResolveAssemblyReferences">
  <ItemGroup>
    <!-- get list of assemblies marked as CopyToLocal -->
    <FilesToEmbed Include="@(ReferenceCopyLocalPaths)" 
                  Condition="('%(ReferenceCopyLocalPaths.Extension)' == '.dll' Or '%(ReferenceCopyLocalPaths.Extension)' == '.pdb') And '%(Filename)'!='MixedModeAssemblyA' And '%(Filename)'!='MixedModeAssemblyB'" />
    <FilesToExclude Include="@(ReferenceCopyLocalPaths)" 
                  Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.xml'" />

    <!-- add these assemblies to the list of embedded resources -->
    <EmbeddedResource Include="@(FilesToEmbed)">
      <LogicalName>%(FilesToEmbed.DestinationSubDirectory)%(FilesToEmbed.Filename)%(FilesToEmbed.Extension)</LogicalName>
    </EmbeddedResource>

    <!-- no need to copy the assemblies locally anymore -->
    <ReferenceCopyLocalPaths Remove="@(FilesToEmbed)" />
    <ReferenceCopyLocalPaths Remove="@(FilesToExclude)" />
  </ItemGroup>

  <Message Importance="high" Text="Embedding: @(FilesToEmbed->'%(Filename)%(Extension)', ', ')" />
</Target>
I would love to have a solution that actually checks whether an assembly is mixed mode (i.e. not pure) before embedding it. Or at least create a list of assembly names to exclude instead of the crude condition hack above.

One could also imagine checking the path of the assembly and whether this has AnyCPU, x86, x64 in the path or similarly as a convention for embedding or not embedding the given assembly. Lots of other improvements should be possible...

There is also a complete solution out there in the form of Costura.Fody, which exists as a convenient nuget package as well, see http://www.nuget.org/packages/Costura.Fody. This does, however, rely on IL rewriting which may be a problem for some. It does look as if it handles all possible issues via configuration, though.

1 comment:

  1. Casino Nights, Avis Casino & Sports Betting at JTM Hub
    JTM, the world's biggest online 논산 출장샵 gaming operator, today announced 인천광역 출장마사지 that it has 충주 출장샵 partnered with Bally Sportsbook for 광주광역 출장안마 the all-new 동해 출장마사지

    ReplyDelete