51

两个问题:

1) 基本 .NET 程序集不包含在 ILmerged 程序集中

从 .NET 3.5/Visual Studio 2008 升级到 .NET 4/Visual Studio 2010 后,我在后期构建中使用 ILMerge 时遇到问题。我有一个解决方案,其中包含多个目标框架设置为“.NET Framework 4”的项目. 我使用以下 ILMerge 命令将各个项目 DLL 合并到一个 DLL 中:

if not $(ConfigurationName) == Debug
  if exist "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe"
    "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe"
      /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
      /lib:"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies"
      /keyfile:"$(SolutionDir)$(SolutionName).snk"
      /targetplatform:v4
      /out:"$(SolutionDir)bin\development\$(SolutionName).dll"
      "$(SolutionDir)Connection\$(OutDir)Connection.dll"
      ...other project DLLs...
      /xmldocs 

如果我不指定 .NET 4 框架目录的位置,我会从 ILMerge 收到“不允许的未解析程序集引用:系统”错误。如果我不指定 MSTest 目录的位置,则会收到“不允许的未解析程序集引用:Microsoft.VisualStudio.QualityTools.UnitTestFramework”错误。

上面的 ILMerge 命令工作并生成一个 DLL。但是,当我在另一个 .NET 4 C# 项目中引用该 DLL 并尝试在其中使用代码时,我收到以下警告:

无法解析主要引用“MyILMergedDLL”,因为它间接依赖于 .NET Framework 程序集“mscorlib,Version=4.0,Culture=neutral,PublicKeyToken=b77a5c561934e089”,它的版本“4.0.65535.65535”高于版本当前目标框架中的“4.0.0.0”。

如果我随后删除该/targetplatform:v4标志并尝试使用 MyILMergedDLL.dll,则会收到以下错误:

'System.Xml.Serialization.IXmlSerializable' 类型是在未引用的程序集中定义的。您必须添加对程序集“System.Xml,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089”的引用。

看来我不应该这样做。使用我的 MyILMergedDLL.dll API 的人不必添加对它引用的任何库的引用。我怎样才能解决这个问题?

2) TypeLoadException 仅在使用合并程序集时

编辑:除此之外,即使我System.Xml在使用 MyILMergedDLL.dll 的消费者项目中添加了对的引用,使用 MyILMergedDLL.dll 中的一些代码也会产生此异常:

System.TypeLoadException:无法从程序集“MyILMergedDLL,Version=1.0.1.1,Culture=neutral,PublicKeyToken=...”加载类型“System.Func`2”。

这是我的消费者项目中的代码;导致的行TypeLoadException是第二行:

var keys = new[] {"a", "b", "c"};
var row = new Row(keys);

Row抛出的特定构造函数TypeLoadException在公共类中定义MyILMergedDLL,当我在引用单个项目 DLL 时使用此构造函数时,它工作正常。只有当我在引用 IL 合并的 DLL 时使用此构造函数时,我才会得到异常。我不知道发生了什么事。

这是构造函数:

public Row(IEnumerable<string> keys) : base(keys) { }

base它所指的有以下代码:

foreach (string key in keys.Where(
    key => !string.IsNullOrEmpty(key)
))
{
    _dic.Add(key, string.Empty);
}
4

6 回答 6

48

有一个非常新的版本可以解决 x64 问题。如果您仍有问题,请直接与 Mike Barnett 联系 (mbarnett at microsoft dot com)


附录。你的选择有一些非常非常错误的/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319"地方。在 .NET 4.5 发布之后,这最近让很多程序员陷入了困境。该目录不适用于 .NET 4.0 参考程序集。它的内容被 4.5 程序集覆盖,您不能再使用它来定位 .NET 4.0 安装。您得到的运行时错误非常尴尬,程序无法再找到某些类型。通常轰炸[Extension]属性,有时轰炸ICommand接口。

这些类型以及其他一些类型从一个程序集转移到另一个程序集。使用正确的参考组件是一项坚如磐石的要求。您必须使用:

 /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"

调整以匹配您的特定机器和目标框架版本。

于 2010-06-02T23:32:11.637 回答
22

这是使用 .NET 4.0 的 Visual Studio 2010 SP1 的“构建后字符串”。我正在构建一个包含所有 sub-.dll 文件的控制台 .exe。

"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(SolutionDir)\deploy\$(TargetFileName)" "$(TargetDir)$(TargetFileName)" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards

基本提示:

  • 注意“\deploy\”目录:这是输出 .exe 文件结束的地方。
  • 注意“ILMerge\”目录。我将 ILMerge 实用程序复制到了我的解决方案目录中(这样我就可以分发源代码而不必担心记录 ILMerge 的安装)。

进阶提示:

如果您遇到无法正常工作的问题,请在“Post Build”命令之前添加“echo”。然后,在 Visual Studio (View..Output) 中打开“输出”窗口,并检查 Visual Studio 实际生成的确切命令。在我的特殊情况下,确切的命令是:

"T:\PhiEngine\CSharp\ILMerge\ILMerge.exe" /out:"T:\PhiEngine\CSharp\Server Side\deploy\NfServiceDataHod.History.exe" "T:\PhiEngine\CSharp\Server Side\NfServiceDataHod\bin\Debug\NfServiceDataHod.History.exe" "T:\PhiEngine\CSharp\Server Side\NfServiceDataHod\bin\Debug\*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards

更新

将此添加到我的“构建后”步骤中,它将所有 .exe + .dll 文件替换为单个组合的 .exe。它还保持调试 .pdb 文件完整:

rem Create a single .exe that combines the root .exe and all subassemblies.
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
rem Remove all subassemblies.
del *.dll
rem Remove all .pdb files (except the new, combined pdb we just created).
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).all.pdb.temp"
del *.pdb
ren "$(TargetDir)$(TargetName).all.pdb.temp" "$(TargetName).all.pdb"
rem Delete the original, non-combined .exe.
del "$(TargetDir)$(TargetName).exe"
rem Rename the combined .exe and .pdb to the original name we started with.
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).pdb"
ren "$(TargetDir)$(TargetName).all.exe" "$(TargetName).exe"
exit 0
于 2011-03-23T15:58:52.837 回答
2

其他选择:

于 2011-03-23T16:08:04.990 回答
2

您还可以使用以下内容添加配置文件:

<?xml version ="1.0"?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <requiredRuntime safemode="true" imageVersion="v4.0.30319" version="v4.0.30319"/>
  </startup>
</configuration>

取自这里

于 2012-02-26T14:38:08.107 回答
1

只需在 Visual Studio 属性窗口中将 PresentationCore 和 PresentationFramework 引用设置为“Copy Local = True”(在解决方案资源管理器中选择引用之后)。它将解决问题,而无需对框架路径进行硬编码。我更喜欢这个解决方案,因为路径会根据开发人员/构建服务器是 64 位还是 32 位而有所不同,并且随着新 .NET/VS 版本的发布不可避免地会发生变化。

于 2013-04-26T14:38:03.120 回答
0

对于那些从.csproj 中的社区任务使用 ILMerge 的人:

<ILMerge InputAssemblies="@(MergeAssemblies)"
         ...
         TargetPlatformVersion="v4"
         TargetPlatformDirectory="$(ProgramFiles)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
/>

我们有 CI 构建代理的混合园区,因此我们使用 $(ProgramFiles) 环境变量来指向正确的路径(驱动器 + x86/x64 文件夹),正如MSBuild 团队所推荐的那样。

于 2018-06-12T16:48:14.637 回答