在.NET 4库中使用ILMerge
两个问题:
1)不包含在ILMerged程序集中的基本.NET程序集
从.NET 3.5 / Visual Studio 2008升级到.NET 4 / Visual Studio 2010后,我在使用ILMerge进行后构build时遇到了问题。我有一个解决scheme,其中有几个项目的目标框架设置为“.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中得到“未parsing的程序集引用不允许:系统”错误。 如果我没有指定MSTest目录的位置,我得到“未parsing的程序集引用不允许:Microsoft.VisualStudio.QualityTools.UnitTestFramework”错误。
上面的ILMerge命令工作并产生一个DLL。 但是,当我在另一个.NET 4 C#项目中引用该DLL并尝试使用其中的代码时,出现以下警告:
主要引用“MyILMergedDLL”无法parsing,因为它具有.NET Framework程序集“mscorlib,Version = 4.0,Culture = neutral,PublicKeyToken = b77a5c561934e089”的间接依赖关系,它具有比版本“4.0.65535.65535”更高的版本当前目标框架中的“4.0.0.0”。
如果我然后删除/targetplatform:v4
标志并尝试使用MyILMergedDLL.dll,我得到以下错误:
types“System.Xml.Serialization.IXmlSerializable”是在未引用的程序集中定义的。 您必须添加对程序集“System.Xml,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089”的引用。
似乎我不应该这样做。 无论谁使用我的MyILMergedDLL.dll API不应该添加引用它引用的任何库。 我怎样才能解决这个问题?
2)仅当使用合并程序集时TypeLoadException
编辑:除此之外,即使我在使用MyILMergedDLL.dll的使用者项目中添加对System.Xml
的引用,使用MyILMergedDLL.dll中的一些代码给出此exception:
System.TypeLoadException:无法从程序集“MyILMergedDLL,Version = 1.0.1.1,Culture = neutral,PublicKeyToken = …”中加载types“System.Func`2”。
这是我的消费者项目中的代码; 导致TypeLoadException
的行是第二个:
var keys = new[] {"a", "b", "c"}; var row = new Row(keys);
引发TypeLoadException
的特定Row
构造函数在TypeLoadException
中的公共类中MyILMergedDLL
,并且在引用单个项目DLL时使用此构造函数时,它工作正常。 只有当我使用这个构造函数引用IL合并的DLL时,我得到了exception。 我不知道发生了什么事。
这是那个构造函数:
public Row(IEnumerable<string> keys) : base(keys) { }
而它所指的base
有这样的代码:
foreach (string key in keys.Where( key => !string.IsNullOrEmpty(key) )) { _dic.Add(key, string.Empty); }
最近有一个解决x64问题的版本。 如果您仍然有问题,请直接与Mike Barnett联系(microsoft dot com上的mbarnett)
附录。 你的/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
选项有一些非常非常错误的/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
。 在.NET 4.5发布之后,这已经让很多程序员陷入困境。 该目录不适用于.NET 4.0引用程序集。 它的内容被4.5程序集覆盖,你不能再用它来定位.NET 4.0的安装。 你得到的运行时错误是非常尴尬的,程序无法find某些types了。 通常在[Extension]属性上轰炸,有时在ICommand界面上轰炸。
这些types和其他一些types从一个程序集移到另一个程序集。 使用正确的参考组件是一项艰巨的任务。 您必须使用:
/lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
调整以匹配您的特定机器和目标框架版本。
这里是Visual Studio 2010 SP1的“Post Build String”,使用.NET 4.0。 我正在构build一个控制台.exe,其中包含的所有子.dll文件。
"$(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实用程序复制到我的解决scheme目录中(这样我就可以分发源代码而不必担心loggingILMerge的安装问题)。
高级提示:
如果您在使用时遇到问题,请在“发布后”命令之前添加“回显”。 然后,打开Visual Studio(View..Output)中的“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
更新
添加到我的“后构build”步骤,它将replace所有的.exe + .dll文件与一个单一的.exe。 它也保持debugging.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
其他select:
- 将多个程序集合并为一个WPF应用程序的单个EXE 。
- .Net反应堆 。
- SmartAssembly (一个非常昂贵的商业select)。
您还可以添加一个configuration文件与以下内容:
<?xml version ="1.0"?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <requiredRuntime safemode="true" imageVersion="v4.0.30319" version="v4.0.30319"/> </startup> </configuration>
从这里采取
只需将PresentationCore和PresentationFramework引用设置为在Visual Studio属性窗口中具有“Copy Local = True”(在“解决scheme资源pipe理器”中select引用之后)即可。 它不会对框架path进行硬编码就能解决问题。 我更喜欢这个解决scheme,因为path是不同的,这取决于开发者/构build服务器是64位还是32位,并且不可避免地会随着新的.NET / VS版本的发布而改变。