78

我想将一个 .NET DLL 程序集和一个由 VB.NET 控制台应用程序项目引用的 C# 类库项目合并到一个命令行控制台可执行文件中。

我可以从命令行使用 ILMerge 来完成此操作,但我想将这种引用程序集和项目的合并集成到 Visual Studio 项目中。根据我的阅读,我知道我可以通过 MSBuild 任务或目标来执行此操作,只需将其添加到 C#/VB.NET 项目文件中,但我找不到具体示例,因为 MSBuild 是一个大主题。此外,我发现一些将 ILMerge 命令添加到 Post-build 事件的参考资料。

  1. 如何将 ILMerge 集成到只是 MSBuild 项目的 Visual Studio (C#/VB.NET) 项目中,以将所有引用的程序集 (copy-local=true) 合并到一个程序集中?

  2. 这如何与可能的 ILMerge.Targets 文件联系起来?

  3. 使用 Post-build 事件会更好吗?

4

9 回答 9

69

MSBuild ILMerge 任务”(或MSBuild.ILMerge.Task)NuGet 包使这个过程非常简单。它默认将任何“复制本地”引用合并到您的主程序集中。

注意:虽然这些包的名称相似,但这一个与Davide Icardi 在他的回答ILMerge.MSBuild.Tasks中提到的不同。我在这里建议的版本于 2014 年 8 月首次发布。

于 2014-10-13T19:26:32.170 回答
21

这里有一个替代解决方案:

1) 从 nuget 安装 ILMerge.MSBuild.Tasks 包

PM> 安装包ILMerge.MSBuild.Tasks

2) 通过添加以下代码编辑要合并的项目的 *.csproj 文件:

  <!-- Code to merge the assemblies into one:setup.exe -->
  <UsingTask TaskName="ILMerge.MSBuild.Tasks.ILMerge" AssemblyFile="$(SolutionDir)\packages\ILMerge.MSBuild.Tasks.1.0.0.3\tools\ILMerge.MSBuild.Tasks.dll" />
  <Target Name="AfterBuild">
    <ItemGroup>
      <MergeAsm Include="$(OutputPath)$(TargetFileName)" />
      <MergeAsm Include="$(OutputPath)LIB1_To_MERGE.dll" />
      <MergeAsm Include="$(OutputPath)LIB2_To_MERGE.dll" />
    </ItemGroup>
    <PropertyGroup>
      <MergedAssembly>$(ProjectDir)$(OutDir)MERGED_ASSEMBLY_NAME.exe</MergedAssembly>
    </PropertyGroup>
    <Message Text="ILMerge @(MergeAsm) -&gt; $(MergedAssembly)" Importance="high" />
    <ILMerge InputAssemblies="@(MergeAsm)" OutputFile="$(MergedAssembly)" TargetKind="SameAsPrimaryAssembly" />
  </Target>

3)像往常一样构建你的项目。

于 2012-11-19T00:08:44.453 回答
18

一些可能对实施Scott Hanselman 解决方案的人有用的更多信息。

当我第一次设置它时,它会抱怨无法解析对 System.Core 等的引用。这与 .NET 4 支持有关。包含一个指向 .NET 4 Framework 目录的 /lib 参数可以修复它(实际上只包含 $(MSBuildBinPath))。

/lib:$(MSBuildBinPath)

然后我发现 IlMerge 在合并时会挂起。它使用了一点 CPU 和大量 RAM,但没有输出任何东西。我当然找到了 stackoverflow的修复程序。

/targetplatform:v4

我还发现 Scott 的博客文章中使用的一些 MSBuild 属性依赖于从项目目录执行 MsBuild,所以我对它们进行了一些调整。

然后,我将目标和 ilmerge.exe 移动到源树的工具文件夹中,这需要对路径进行另一个小调整......

我最终用以下Exec元素代替了 Scott 原始文章中的元素:

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

更新 我还发现Logic Labs 回答了关于保持 CopyLocal 行为并仅从 CopyLocal 中排除 ilMerged 程序集的答案,如果您使用的是 Nuget 包。否则,您需要为未合并的引用程序集的每个包目录指定一个 /lib 参数。

于 2012-05-10T14:58:01.123 回答
16

http://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlessWithILMergeAndMSBuild.aspx 上的文章在 Visual Studio 的单个程序集中使用 ILMerge 和 MSBuild 无缝混合语言演示了如何在 Visual Studio 项目中使用 ILMerge 和 MSBuild

于 2010-03-31T20:43:19.203 回答
9

我在以下文章中发现了一个问题:http ://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlessWithILMergeAndMSBuild.aspx 。

如果您有任何不希望 ILMerge 的引用,那么本文中的代码将失败,因为它会覆盖默认的 CopyLocal 行为以不执行任何操作。

要解决这个问题 - 而不是:

<Target Name="_CopyFilesMarkedCopyLocal"/> 

将此条目添加到目标文件(仅限 .NET 3.5)(过滤掉非 ilmerge 复制本地文件,并将它们视为正常文件)

<Target Name="AfterResolveReferences">
    <Message Text="Filtering out ilmerge assemblies from ReferenceCopyLocalPaths" Importance="High" />
    <ItemGroup>
        <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.IlMerge)'=='true'" />
    </ItemGroup>
</Target>
于 2012-03-07T20:02:04.803 回答
4

这是一篇很棒的文章,它将向您展示如何将引用的程序集合并到输出程序集中。它准确地展示了如何使用 msbuild 合并程序集。

于 2010-03-31T20:50:57.140 回答
1

我的 2 美分 - 我收到了 @Jason 的回复,并使它适用于我的解决方案,我想在 bin/Debug 文件夹中生成 *.exe,所有 *.dll 都在同一个文件夹中。

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

注意:这个解决方案显然是硬编码到 ILMerge nuget 包版本中的。如果您有一些改进建议,请告诉我。

于 2014-11-13T18:46:36.377 回答
1

通过添加以下代码来编辑要合并的项目的 *.csproj 文件:

<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>

笔记:

  1. 替换$(SolutionDir)packages\ILMerge.3.0.29\tools\net452\ILMerge.exe为您拥有的任何路径ILMerge.exe
  2. 您可以删除Condition目标中的 Debug 也可以合并,但调试器可能无法正常工作
  3. 如果您不排除任何可以删除的内容:/internalize:&quot;$(MSBuildProjectPath)ilmerge.exclude&quot;
于 2020-05-20T21:09:05.767 回答
0

查看 Jomo 的这篇文章。他有一个快速的过程来破解 ILMerge 进入 msbuild 系统

于 2010-03-31T20:46:31.420 回答