Pull to refresh

Comments 29

Не совсем понял, есть ли возможность включения в сборку .net runtime и запуска приложение на ОС, где .net не установлен. Если такой возможности нет, то особой пользы от ILMerge не вижу.
Польза в том, что все либы будут внутри. Если у вас небольшая утилита, то не придётся таскать всегда с собой разные либы.

Также это полезно большим проектам, где 100500 dll-ок. После смерживания они(проекты) шевелятся заметно шустрее.
Лучше при установке NGen'ом по этим сборкам пройтись, а не валить все в одну кучу. Обновляться потом печально будет.
Вы не путайте устанавливаемую софтину, которая может нормально использовать NGen, и portable-утилиту, которую идеально распространять одним exeшником.
Я в основном говорил о проекте со 100500 сборок.
Не знал про NGen,
но он решает другую задачу (вернее бенифит про быструю загрузку 100500 dll'ок).
Кстати хорошее объяснение как им пользоваться есть тут.
а насколько быстрее? буду благодарен за какое-нибудь сравнение
Весь .NET встроить не получиться. Но если нужна маленькая утилита и вы решили ее написать на .NET, но хотите чтобы она была в одном файле то тогда подойдет.
Или если библиотеку собрать в один dll, а не таскать кучу зависимостей.
Можно задать возможно глупый вопрос, а что происходит в момент запуска приложения и в момент вызова функции из библиотеки? Т.е. библиотеки сохраняют все свойства и просто находят в одном файле или они в какой-то момент экспортируются в отдельные файлы?
Я точно не знаю принцип работы ILMerge,
но судя по dotPeek (Reflector от JetBrains)
он сливает все namespace с классами в одну dll,
видимо разрешая имена классов и вызовы функций в рамках одной dll.
Соответсвенно:
IMHO при загрузке этой dll, загружается все необходимое пространство имен.
ILMerge может поломать вам Reflection, ибо если мержатся сборки с одинаковыми именами классов и неймспейсами (приватные бывает совпадают), их переименуют.
Хороша софтинка ILMerge, но при использовании её натолкнулся на неприятную, хоть и мелкую, багу: она игнорирует ключик, который заставляет её, в свою очередь, игнорировать сборки и неймспейсы, оказавшиеся в зависимостях. Проблему обошли, в итоге, но время потратили.
это который [/keyfile:filename [/delaysign]]?
как обошли?
Ниасилил EULA этой утилиты. Ее вообще можно в коммерческих целях применять?
С сайта ILMerge:
Commercial use permitted:
The language of ILMerge's license has raised many questions. In a nutshell: commercial use is permitted, redistribution is not. Read the license carefully for full details since I am not (nor do I wish to be!) a lawyer.


То есть встраивать в процесс сборки можно, а распространять со своим продуктом — нельзя.
Ok, с этим понятно. Другой спорный момент. Лицензии сторонних компонент часто содержат запрет на декомпиляцию. А ILMerge похоже занимается именно этим — декомпилирует сборки и заново собирает в один файл, так?
Декомпиляции не происходит, IL-код патчится на лету без преобразования его обратно в C#/VB.NET/etc. Чтобы понять, что именно происходит, стоит посмотреть на Mono.Cecil.
Может, конечно, спрошу глупость, но зачем нужен пункт
«Положить %PROGRAMFILES%\ILMerge\ILMerge.exe в папку ${SolutionDir}ILMerge\»
Неужели оно не будет работать (или будет криво работать) если оставить где есть, а в PATH дописать что там искать тоже, ну и в батнике написать ILMerge.exe без всяких абсолютных путей?
Если в PATH то будет.

Но в мою задачу входило придумать решение для source control,
так чтобы если солюшн скачивается из source control на очередной машине,
то нет необходимости лезть в PATH. Нажал build и все.
Правда ILMerge.exe и merge_all.bat надо еще в директорию солюшена закинуть в VS.

Просто ILMerge.exe не будет, тк текущая папка это папка проекта.
есть ещё aspnet_merge которая работает через ILMerge
ILMerge память жрет как бегемот… На большом количестве сборок вылетает с System.OutOfMemoryException.
Нет, всего сотни хватило :)
Вот мой выход. Можно было завернуть в отдельный подгужаемый таск-файл, но я не стал заморачивтся — нужно было в одном месте.

 <Target Name="AfterBuild">
  <ItemGroup>
   <OutputFiles Include="$(TargetDir)\*.dll" />
  </ItemGroup>
  <PropertyGroup>
   <BinOutput>$(SolutionDir)..\bin\$(Configuration)</BinOutput>
  </PropertyGroup>
  <MakeDir Directories="$(BinOutput)" />
  <Exec WorkingDirectory="$(TargetDir)" Command="$(SolutionDir)\..\Alien\ILMerge.exe /target:library /out:$(BinOutput)\$(TargetFileName).dll /targetplatform:v4,$(MSBuildBinPath) @(OutputFiles, ' ')" />
 </Target>

* This source code was highlighted with Source Code Highlighter.
Спасибо за пример. До не мог понять как подступиться к ms build.
я взял его за базу и добавив экранирования путей закончил следующим:
 <!-- ILMerge Step -->
 <Target Name="AfterBuild">
  <PropertyGroup >
    <ILMerge_Solution>$(SolutionDir)ILMerge\ILMerge.exe</ILMerge_Solution>
    <Programfiles>C:\Program Files (x86)\</Programfiles>
    <Programfiles Condition="!Exists('$(Programfiles)')">C:\Program Files\</Programfiles>
    <ILMerge_Installed>$(Programfiles)Microsoft\ILMerge\ILMerge.exe</ILMerge_Installed>
    <ErrorMesssage>ILMerge is not found here: '$(ILMerge_Solution)', nor here: '$(ILMerge_Installed)'</ErrorMesssage>

    <ILMerge>NOTSET</ILMerge>
    <ILMerge Condition="Exists('$(ILMerge_Installed)')">"$(ILMerge_Installed)"</ILMerge>
    <ILMerge Condition="Exists('$(ILMerge_Solution)')">"$(SolutionILMerge)"</ILMerge>
  </PropertyGroup>
  <Error Condition=" '$(ILMerge)' == 'NOTSET' " Text="Please Install ILMerge. $(ErrorMesssage)" />
  
  <ItemGroup>
   <OutputDlls Include="$(TargetDir)*.dll" />
   <OutputExes Include="$(TargetDir)*.exe" />
  </ItemGroup>
  <PropertyGroup>
   <BinOutput>$(TargetDir)merged\</BinOutput>
   <TargetFilePath>"$(BinOutput)$(TargetFileName)"</TargetFilePath>
   <OutputFiles>@(OutputExes->'"%(identity)"', ' ') @(OutputDlls->'"%(identity)"', ' ') </OutputFiles>
  </PropertyGroup>
  <MakeDir Directories="$(BinOutput)" />
  <Exec WorkingDirectory="$(TargetDir)" Command='$(ILMerge) /out:$(TargetFilePath) $(OutputFiles) /targetplatform:v4,$(MSBuildBinPath) ' />
 </Target>


* This source code was highlighted with Source Code Highlighter.
Мелкий штрих: MsBuild подцепляет системные переменные как свои, то-есть нет необходимости объявлять Programfiles явно: в любом случае будут доступны $(ProgramFiles), и, если есть, $(ProgramFiles(x86)). Вам же нужен всегда 32-битный Program Files, в MsBuild есть специальная зарезервированая переменная для этого: $(MSBuildProgramFiles32).

Ну и для полной красоты, чтобы не мешатся с AfterBuild-ами, можно поместить этот таржет в отдельний файл, присвоить ему (таржету) собственное имя, по соглашению начинающееся с подчеркивания, и перегрузить переменную BuildDependsOn:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <PropertyGroup>
  <BuildDependsOn>
   $(BuildDependsOn);_IlMergeOutput
  </BuildDependsOn>
 </PropertyGroup>
 <Target Name="_IlMergeOutput">
  ...
 </Target>
</Project>

* This source code was highlighted with Source Code Highlighter.
Как-то так. Тогда в результирующий *.*proj файл достаточно будет добавить одну строку импорта, а AfterBuild-ы можно будет оставить для других использований.
Отлично, не знал $(MSBuildProgramFiles32).
Кстати судя по ссылке она называется $(MSBuildExtensionsPath32).

За завершающий штрих спасибо, так уже будет готовое решение.

Не вы не знаете есть ли в переменных среды windows что-то типа %MSBuildExtensionsPath32%?
Extensions это не то. По ссылке нужно было смотреть коментарий :)
Среди переменных windows вроде ничего похожего не встречал.
Если вы используете .NET 4, то лучше пойти другим путем. Мы в своем проекте нахлебались от ILMerge, после перехода на AppDomain.CurrentDomain.AssemblyResolve — никаких проблем. И главное — никаких EULA.
Sign up to leave a comment.

Articles