Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nant build using .NET 4.5 (Beta) assembly references despite specifying "net-4.0"

After installing .Net 4.5 Beta, the output of my Nant build fails with:

"could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'."

because as answered in this question ExtensionAttribute was moved to mscorlib.dll from System.Core.dll. So the nant build is incorporating .net4.5 assemblies despite me specifying the target framework in the nant build script as follows:

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

Under Visual Studio the build works fine (produces a .dll that doesn't require .Net 4.5). But I need the build to work with nant because we have "old-schoolers" as well as build processes that use nant.

What do i need to add to my nant build script to make the build actually stick to 4.0?

like image 226
DanO Avatar asked Aug 16 '12 16:08

DanO


3 Answers

Yesterday I installed VS 2012 side-by-side with VS 2010 and after recompiling and deploying web project it failed with same exception. After hour of research, I found the solution.

First, you need to edit nant.exe.config

Open it and find:

<framework
   name="net-4.0" 

This is approx. at line 555 (in default config for NAnt 0.92)

You'll see a huge xml, describing net-4.0 compilation. Find three child <reference-assemblies> elements. First two looks like

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

and third is

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

And now - just edit first two to match third (copy from third and paste-replace 1st and 2nd). After this, NAnt will look for all .dlls in Reference Assemblies folder (instead 'broken' Windows/Microsoft .NET/...)

Don't worry about /WPF suffix at second one - in Reference Assemblies all files are located in one folder, without /WPF subfolder.

Second step - change your build script

When calling csc task, add two attributes, nostdlib and noconfig:

<csc target="..." output="..." nostdlib="true" noconfig="true" ...>

This will disable automatic referencing of "bad new" mscorlib and other librares from csc's folder.

And inside <references> element - manually add mscorlib.dll, system.core.dll and all used system libraries. NAnt will find them in Referenced Assemblies folder:

<references>
    <include name="mscorlib.dll"/>
    <include name="Microsoft.CSharp.dll"/>
    <include name="System.dll"/>
    <include name="System.Configuration.dll"/>
    <include name="System.Core.dll"/>
    ...

After that (and rebuild of course) my site successfully started on hosting machine with "original" .NET Framework 4. :)

P.S. It looks that Microsoft re-invented DLL HELL :)

like image 75
Dmitry Avatar answered Sep 21 '22 14:09

Dmitry


You might have to do two things (I have not tried this at all, but I remember it helped when 4 was released). First, modify nant.exe.config and add the version to the supported framework versions in the startup section of the config file (I think that's where they go, it should be obvious once you open it). Then, upgrade to the latest and greatest NaNT version. And then, do something like this in your build file:

<property 
    name="assembly-location" value="${framework::get-assembly-directory('net-4.5')}" />
<property 
    name="dotNetReferenceAssemblyPath" value="${assembly-location}\" />

Again, it's been a while and I'm not 100% sure this will do it, but it might set you off on the right track.

like image 24
kprobst Avatar answered Sep 19 '22 14:09

kprobst


Basically, the solution of Dmitry is correct, but I had to modify it a bit before I could compile .Net 4.0 assemblies on my Windows Server 2012. I have used the latest nant-0.93-nightly-2013-10-20 in my environment.

  1. In the Visual Studio 2013 build output it can be seen that CSC is executed with /noconfig and /nostdlib+ flags for a .Net 4.0 target. This proves that your solution is valid.

  2. basedir="${environment::get-folder-path('ProgramFiles')}..." did not work for me because NAnt.exe is a 64 bit process. Actually, most of the standard assemblies are only available under the Program Files (x86) root. I tried corflagging NAnt.exe, but this caused other problems. To ensure that the core assemblies can be located by both 32 bits and 64 bits processes, I created a directory C:\Nant\Microsoft.Net\v4.0 and copied them there. Because the directory is not below Program Files, it is always visible.

  3. Our NAnt build script is huge and I did not want to modify the references of each and every csc task manually. To reduce the required modifications to the script, I have slightly customized the NAnt 0.93 nightly. If the target framework name is "net-4.0" and the task is of type CscTask, it autmatically adds mscorlib.dll, System.dll and all System asembly references found in a csproj located in the root directory of the csc task sources. Source code and binaries of the customization can be found here: http://support.decos.nl/berend/NAnt-0.93-nightly-2013-10-20-modified.zip

The modified code logs the added references to the NAnt build output:

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 '...
like image 23
Berend Engelbrecht Avatar answered Sep 19 '22 14:09

Berend Engelbrecht