Сгенерированная сборка ILMerge не запускается, хотя выход журнала не содержит ошибок - почему это?

Я тестирую ILMerge для нового проекта, и хотя файл .exe создается правильно, он не запускается.

Я установил ILMerge через установщик .msi(нашёл здесь http://www.microsoft.com/download/en/confirmation.aspx?id=17630), и я запускаю тестовый проект с использованием командного файла. Ниже приведен командный файл и последующий выходной журнал после запуска. Все отображается нормально в журналах, об ошибках не сообщается. Я запускаю .NET framework 4.0 для этого тестового проекта.

Когда я пытаюсь запустить .exe, он не работает со стандартом "Эта программа перестала работать".

Я прочитал, что у некоторых людей проблемы с .NET 4, но я думаю, что я добавил правильные аргументы, чтобы справиться с этим. Я получаю тот же результат, добавляю ли я в аргументы .NET 4 или нет.

Может ли кто-нибудь понять, почему это может быть? Спасибо заранее.

Пакетный файл

REM Clear directory first

CD C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL

DEL . /s/q

REM Change dir to iLMerge install (installed via msi installer) 
REM Installer Download: http://www.microsoft.com/download/en/confirmation.aspx?id=17630

CD C:\Program Files (x86)\Microsoft\ILMerge\

REM Combine assemblies with logging

ilmerge.exe /lib:"C:\Windows\Microsoft.NET\Framework\v4.0.30319" /lib:"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies" /t:exe /log:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\MergeLog.txt /target:winexe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework\v4.0.30319 /out:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\CombinedDLL.exe C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll

Выход журнала:

ILMerge version 2.11.1103.0
Copyright (C) Microsoft Corporation 2004-2006. All rights reserved.
ILMerge /lib:C:\Windows\Microsoft.NET\Framework\v4.0.30319 /lib:C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies /t:exe /log:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\MergeLog.txt /target:winexe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework\v4.0.30319 /out:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\CombinedDLL.exe C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll 
Set platform to 'v4', using directory 'C:\Windows\Microsoft.NET\Framework\v4.0.30319' for mscorlib.dll
Running on Microsoft (R) .NET Framework v2.0.50727
mscorlib.dll version = 2.0.0.0
The list of input assemblies is:
    C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe
    C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll
    C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll
Trying to read assembly from the file 'C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe'.
    Successfully read in assembly.
    There were no errors reported in TestILMerge metadata.
Trying to read assembly from the file 'C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll'.
    Successfully read in assembly.
    There were no errors reported in TestDLL2 metadata.
Trying to read assembly from the file 'C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll'.
    Successfully read in assembly.
    There were no errors reported in TestDLL3 metadata.
Checking to see that all of the input assemblies have a compatible PeKind.
    TestILMerge.PeKind = ILonly, Requires32bits
    TestDLL2.PeKind = ILonly
    TestDLL3.PeKind = ILonly
All input assemblies have a compatible PeKind value.
Using assembly 'TestILMerge' for assembly-level attributes for the target assembly.
Merging assembly 'TestILMerge' into target assembly.
Merging assembly 'TestDLL2' into target assembly.
Merging assembly 'TestDLL3' into target assembly.
Copying 2 Win32 Resources from assembly 'TestILMerge' into target assembly.
Transferring entry point 'TestILMerge.Program.Main(System.String[])' from assembly 'TestILMerge' to assembly 'CombinedDLL'.
    There were no errors reported in the target assembly metadata.
ILMerge: Writing target assembly 'C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\CombinedDLL.exe'.
Location for referenced assembly 'mscorlib' is 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll'
    There were no errors reported in  mscorlib metadata.
ILMerge: Done.

UPDATE: вот разборка - выглядит так, как я ожидал бы, чтобы она

Dissassembly

enter image description here

ОБНОВЛЕНИЕ 2

Я обнаружил, что компонент работает, если я ссылаюсь на другой проект и использую его как сборку, но не автономный исполняемый файл.

Ответ 1

ILMerge велик, если вы написали все сборки, которые вы пытаетесь объединить, и вы знаете, что никто из них не делает предположений об организации сборки. Но при многих обстоятельствах (особенно в тех случаях, когда задействованы тяжелые размышления или динамический язык Runtime), ILMerge просто не работает. Иногда вещи терпят неудачу удивительными и таинственными способами.

Когда ILMerge терпит неудачу, Джеффри Рихтер более надежный способ заставить приложения с несколькими зависимостями DLL развертываться как единая сборка.

Это не без компромиссов, но даже автор ILMerge, Майк Барнетт, сказал в комментарии к этому сообщению блога: "Как автор ILMerge, я думаю, что это фантастика! Если бы я знал об этом, Я никогда бы не написал ILMerge."

Если вы можете использовать метод Рихтера, вы не будете преодолевать большинство ловушек отражения или динамизма.

Шаги внедрения

  • Внедрите все сторонние сборки, на которые вы зависите в своем приложении Ресурсы.
  • Зарегистрируйте ResolveEventHandler с событием AppDomain.CurrentDomain.AssemblyResolve.
  • Когда ваш обработчик вызывается с помощью сборки, которую вы спрятали в разделе "Ресурсы", загрузите сборку.

Вы делаете часть 3 следующим образом:

var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
return Assembly.Load(new BinaryReader(resourceStream).ReadBytes(int.MaxValue));

Ответ 2

Полностью автономный исполняемый файл может быть легко создан в Visual Studio 2010, и этот метод вообще не требует ILMerge.

Шаги:

  • Создать пустой исполняемый проект
  • Добавьте свои библиотеки DLL (и ваш EXE файл) в качестве ресурсов. (Щелкните правой кнопкой мыши по имени проекта в обозревателе решений, свойствах, ресурсах, добавить ресурс).

После этого Visual Studio автоматически создаст новый класс под названием "Ресурсы", который вы должны использовать в своем новом проекте.

  • Добавьте два метода ниже в Program.cs, чтобы сделать окончательную работу приложения.

Затем вы должны скомпилировать свою программу с помощью Visual Studio и ее.

static void Main(string[] args)
{
    // Load your assembly with the entry point from resources:
    Assembly start = Assembly.Load((byte[]) Properties.Resources.NameOfDllOrExeInYourResources);
    Type t = start.GetType("Foo.Bar.Program");

    // Install the resolver event
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

    // Find Program.Main in the loaded assembly
    MethodInfo m = t.GetMethod("Main", BindingFlags.Public | BindingFlags.Static);

    // Launch the application
    m.Invoke(null, new object[] { args });
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string assemblyName = new AssemblyName(args.Name).Name.Replace('.', '_');

    // Locate and load the contents of the resource 
    byte[] assemblyBytes = (byte[]) Properties.Resources.ResourceManager.GetObject(assemblyName, Properties.Resources.Culture);

    // Return the loaded assembly
    return Assembly.Load(assemblyBytes);
}

Ответ 3

Возможно, это не решит вашу проблему, но я считаю, что хорошо проверить, что ваш исполняемый файл не содержит ссылок на объединенные библиотеки. Вы можете проверить это с помощью ILSpy (http://wiki.sharpdevelop.net/ILSpy.ashx) - просто разобщите свой исполняемый файл и проверьте дерево, какие сборки находятся в ссылках. ILSpy также может помочь вам убедиться в том, что ваш исполняемый файл с ирригацией содержит классы из объединенных сборок.

Следующим вариантом может быть также отладка привязки сборок при попытке запустить ваше инерционное приложение (http://msdn.microsoft.com/en-us/library/e74a18c4%28v=VS.100%29.aspx).

Вы также можете попытаться отладить сборку, чтобы узнать, не сработало ли приложение даже до вызова основной функции или, возможно, где-то внутри.

Я думаю, что определение определенного типа, которое невозможно найти, может помочь устранить проблему.

Ответ 4

Проверьте свои средства просмотра событий на наличие подробных сообщений об ошибках.

Оберните тело вашего метода void Main(string args[]) с помощью

try
{
...
}
catch (Exception ex)
{
  Console.WriteLine(ex.ToString());
}

Также попробуйте изменить целевую платформу на x86, например.

Вам не нужно указывать каталоги framework.net в командах командной строки /lib и /targetplatform, если вы укажете /targetplatform:v4.

Ответ 5

После нескольких часов борьбы с этой проблемой я удалил папку проекта и сделал новое извлечение из git. Я попробовал очистить и перестроить свой проект, и это та же проблема. Затем я сравнил проект моих коллег и внутри *\Library\Build *, мне не удалось найти папку Результаты. После добавления папки \Library\Build\Results мое решение построено без ошибок.