Mimo, że program istnieje od 2004 roku, nigdy nie miałem potrzeby korzystania z ILMerge aż do ostatniego tygodnia. No i tu się rozpoczęły schody :)

Jak to zawsze bywa z czymś nowym, nie wiemy zbytnio jak z tego korzystać. Jeżeli produkt jest nowy, to jedyna szansa dowiedzenia się co i jak to przez dokumentację (jeżeli istnieje) oraz metodę prób i błędów. Tutaj na szczęście miałem pomoc Scotta, który opublikował bardzo fajny post pokazujący co i jak skonfigurować by ILMerge zaczął działać.

Niestety, jak to bywa z postami z przed 5 lat, są one trochę out of date. Część kroków jednak można spokojnie wykonać.

Po pierwsze, nie umieszczałbym pliku trargets w Program Files, chcę móc potem kod udostępnić i dać możliwość innym dev go ściągania i buildowania. Więc ta opcja jest po prostu zła :) To co ja zrobiłem (a wszystko zależy od waszych preferencji) to w katalogu w którym znajduje się plik solution (.sln) stworzyłem katalogu build w którym utworzyłem plik targets. Następnie w solution, dodałem wirtualny katalog build do którego załączyłem istniejący plik targets.

Teraz mogłem spokojnie edytować ten plik z poziomu VS – co się naprawdę przydało.

Do pliku targets możecie przekopiować zawartość udostępnioną na stronie Scotta. Jej zmianą zajmiemy się później.

Teraz pora dodać ILMerge do naszego projektu. Za pomocą NuGet możemy łatwo dodać ILMerge do solution – na szczęście NuGet tworzy tylko katalog w packages/ILMerge_version i nic pozatym.

Teraz pora zająć się konfiguracją naszego projektu, któremu chcemy połączyć assemblies. Na projekcie robimy unload i przechodzimy do edycji jego w XML editor w VS.

Na samym końcu pliku przy import robimy to samo co Scott, z tą różnicą iż zamiast MSBuildExtensionsPath wpisujemy SolutionDir – to odwoła się do katalogu w którym znajduje się plik sln. Teraz wystarczy tylko przekierować do naszego katalogu buildIlmerge.CSharp.targets i kłopot z głowy.

W zależności od tego które biblioteki chcemy połączyć, do ProjectReference albo do:

<Reference Include="XXX"> 

    <HintPath>XX.dll</HintPath>

</Reference>

Dodajemy prosty tag:

<IlMerge>True</IlMerge>

Plik projektu zapisujemy i projekt ponownie możemy załadować.

Teraz tak naprawdę to powinno być wszystko, ale tak nie jest :)

Zaczynamy zabawę. Po pierwsze, mnie interesują konkretne odwołania a nie wszystkie które mają CopyToLocal ustawione na true.

Dlatego też, z pliku Scotta, należy usunąć fragment:

'%(CopyLocal)'=='true' and

To spowoduje, że jedynie pliki z zaznaczeniem <IlMerge>True</IlMerge> będą brane pod uwagę.

Teraz trzeba naprawić referencje do pliku IlMerge. Jeżeli instalowaliście to za pomocą NuGet, to fragment:

&quot;$(ProgramFiles)MicrosoftIlmergeIlmerge.exe&quot;

Należy zastąpić:

&quot;$(SolutionDir)packagesilmerge.2.12.0803Ilmerge.exe&quot;

Kolejny problem na jaki natrafimy zapewne, to biblioteki dodatkowe, które są przez nasz projekt wykorzystywane.

Dlatego zaraz po Ilmerge.exe&quot; dodajemy:

/lib:&quot;$(SolutionDir)packagesNAZWA_PACKAGE&quot;

Albo podobne, w zależności od waszej konfiguracji. /lib odwołuje się do folderu, nie do DLLki!

Teraz możemy spróbować przekompilować projekt, jednak za pewne dostaniemy błąd związany z brakiem ref do .NET 4.0 lub 4.5

Tak, jest z tym problem. Jeżeli dodamy do polecenia:

/lib:&quot;$(MSBuildBinPath)&quot;

Przestaniemy mieć problem z referencją do .NET 4.0, ale nasz build zacznie dosłownie pożerać nasze zasoby systemowe – CPU i RAM, ja po 5 minutach po prostu go z cancelowałem.

Rozwiązaniem tego problemu było dodanie:

/targetplatform:v4

Zaraz po ostatnim parametrze /lib.

Teraz all się ładnie buildowało. Uwaga, dla .NET 4.5 istnieje trochę inne rozwiązanie.

Jednak w katalogu build nie znajdowały się żadne dodatkowe biblioteki – żadne które miały CopyLocal a nie były wykorzystane w merge. Co trochę było dziwne, a i także do innych problemów może prowadzić.

Rozwiązaniem tego problemu, jest usunięcie linijki z pliku Scotta:

<Target Name="_CopyFilesMarkedCopyLocal"/>

Jeżeli zaś chcemy nie załączać plików już z mergowanych to, linijkę podmieniamy na:

<Target Name="AfterResolveReferences">

    <Message Text="Copying not used assemblies by ilmerge" Importance="High" />

    <ItemGroup>

        <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.IlMerge)'=='true'" />

    </ItemGroup>

</Target>

Ten fragment znalazłem gdzieś w sieci. Powoduje on skopiowanie wszystkich załączonych bibliotek które są kopiowane do katalogu buildu, które nie są oznaczone ILMerge True.

Tak o to w prosty/nie prosty sposób możemy za pomocą ILmerge mergować assemblies zarówno z poziomu VS Build jak i MSBuild.