使用“.net-4.0”指定后,Nant构建仍使用.NET 4.5(Beta)程序集引用

7

安装了 .Net 4.5 Beta 后,我的 Nant 构建输出失败,错误信息如下:

"无法从程序集 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' 中加载类型 'System.Runtime.CompilerServices.ExtensionAttribute'。"

原因在于 这个问题的回答 中所述,ExtensionAttribute 已经从 System.Core.dll 移动到了 mscorlib.dll 中。 因此,尽管我在 nant 构建脚本中指定了目标框架如下,nant 构建仍然包含了 .net4.5 程序集:

<property name="nant.settings.currentframework" value="net-4.0" />

在Visual Studio下编译正常(生成的.dll不需要.Net 4.5)。但我需要使用nant进行编译,因为我们有“老派人士”和使用nant的构建过程。我需要在nant构建脚本中添加什么来确保编译实际上是针对4.0版本的?
3个回答

10

昨天我将 VS 2012 与 VS 2010 并排安装后,重新编译和部署 web 项目,结果出现了同样的异常。经过一小时的研究,我找到了解决方案。

首先,您需要编辑 nant.exe.config

打开该文件并查找:

<framework
   name="net-4.0" 

这大约在第555行(使用NAnt 0.92的默认配置)。

你会看到一个巨大的xml,描述了net-4.0编译。找到其中三个子元素为<reference-assemblies>的元素。前两个看起来像是:

<reference-assemblies basedir="${path::combine(installRoot, 'v4.0.30319')}">
<reference-assemblies basedir="${path::combine(installRoot, 'v4.0.30319')}/WPF">

第三个是

<reference-assemblies basedir="${environment::get-folder-path('ProgramFiles')}/Reference Assemblies/Microsoft/Framework/.NETFramework/v4.0">

现在,只需编辑前两个以匹配第三个(从第三个复制并粘贴替换第1个和第2个)。此后,NAnt将在参考程序集文件夹中查找所有.dll文件(而不是'损坏的'Windows/Microsoft .NET/...)。

不必担心第二个文件名后缀中的/WPF - 在参考程序集中,所有文件都位于一个文件夹中,没有/WPF子文件夹。

第二步 - 更改您的构建脚本

在调用csc任务时,添加两个属性:nostdlibnoconfig

<csc target="..." output="..." nostdlib="true" noconfig="true" ...>
这将禁用从csc文件夹自动引用"bad new" mscorlib和其他库。并且在元素内手动添加mscorlib.dll、system.core.dll和所有使用的系统库。NAnt将在Referenced Assemblies文件夹中找到它们。
<references>
    <include name="mscorlib.dll"/>
    <include name="Microsoft.CSharp.dll"/>
    <include name="System.dll"/>
    <include name="System.Configuration.dll"/>
    <include name="System.Core.dll"/>
    ...

经过这个步骤(当然需要重新构建),我的网站成功地在托管机器上以“原始”的.NET Framework 4启动了:)

P.S. 看起来微软重新发明了DLL HELL :)


1
确实重新发明了DLL地狱!感谢您抽出时间发布这篇文章! - DanO
似乎无法与VB.Net一起使用,因为nant下没有“noconfig”选项:(我还尝试使用通过Studio生成的dll来使其工作,但也失败了。:( - Rory Becker
1
对于Visual Basic编译器,noconfig / nostdlib标志的行为不同,并且值得注意的是它们不会防止链接到某些标准库。幸运的是,微软意识到了这个问题并添加了应该使用的/sdkpath参数。使用nant时,我通过在vbc任务中添加以下内容来解决它:<arg line="/sdkpath:"${environment::get-folder-path('ProgramFiles')}\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0""/>。 - Oskar Berggren
如果我们的nant脚本只是调用MSBuild(目标:Build),而不是直接调用CSC,会怎样呢? - Carl Bussema
2
如果您的nant脚本调用MSBuild,则所有工作都由MSBuild完成,并且它使用正确的程序集,就像在Visual Studio中构建时一样。 - Dmitry

1
基本上,Dmitry的解决方案是正确的,但在我能够在Windows Server 2012上编译.Net 4.0程序集之前,我必须对其进行一些修改。我在我的环境中使用了最新的nant-0.93-nightly-2013-10-20。
  1. 在Visual Studio 2013的构建输出中可以看到,对于.NET 4.0目标,CSC是带有/noconfig和/nostdlib+标志执行的。这证明了你的解决方案是有效的。

  2. basedir="${environment::get-folder-path('ProgramFiles')}..." 对我不起作用,因为NAnt.exe是一个64位进程。事实上,大多数标准程序集仅在Program Files (x86)根目录下可用。我尝试了corflagging NAnt.exe,但导致其他问题。为了确保32位和64位进程都能找到核心程序集,我创建了一个名为C:\Nant\Microsoft.Net\v4.0的目录,并将它们复制到那里。由于目录不在Program Files目录下,所以它始终可见。

  3. 我们的NAnt构建脚本非常庞大,我不想手动修改每个csc任务的引用。为了减少对脚本所需的修改,我稍微定制了NAnt 0.93夜间版。如果目标框架名称为"net-4.0",并且任务是CscTask类型,则自动添加mscorlib.dll,System.dll以及在csc任务源根目录中找到的所有System程序集引用。定制的源代码和二进制文件可以在这里找到:http://support.decos.nl/berend/NAnt-0.93-nightly-2013-10-20-modified.zip

修改后的代码将添加的引用记录到NAnt构建输出中:
Inserted reference System.Data.dll
Inserted reference System.Xml.dll
Inserted reference System.configuration.dll
Inserted reference System.dll
Inserted reference mscorlib.dll
      [csc] Compiling 11 files to '...

感谢分享!我们最终以几乎相同的方式修复了nant,不幸的是,由于它只是用于内部使用,因此没有兴趣发布我们的源代码补丁。在github上也存在针对nant此问题的类似补丁,但主项目的维护者尚未拉取或集成它们...看到nant这样消亡真是令人悲哀。 - DanO

1
你可能需要做两件事情(我没有尝试过,但我记得在4发布时它有所帮助)。首先,修改nant.exe.config文件,在配置文件的启动部分中添加版本到支持的框架版本中(我认为它们应该放在那里,一旦你打开它就会很明显)。然后,升级到最新和最伟大的NaNT版本。然后,在您的构建文件中执行以下操作:
<property 
    name="assembly-location" value="${framework::get-assembly-directory('net-4.5')}" />
<property 
    name="dotNetReferenceAssemblyPath" value="${assembly-location}\" />

再次见到你们,已经有一段时间了。我不能百分之百确定这会不会解决问题,但它可能会让你朝着正确的方向前进。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接