views:

510

answers:

3

I have a little project, and I want to have 2 compiled versions of that project:

  • one that is targetting the .NET 2.0 framework
  • one that is targetting the .NET 3.5 framework

All is going well; I've put my project under continuous integration (using CC.NET), and I've created 2 CC.NET 'projects'. One project for each target-framework.

I won't go too much in (irrelevant) details, but my solution is set up to target the .NET 3.5 framework in VS.NET.

I have 2 msbuild-tasks:

  • one task that builds the solution for .NET 3.5 (simple and easy)
  • one task that builds the solution for .NET 2.0

    In this Task, I call MSBuild, and I specify that the TargetFrameworkVersion should be v2.0. I also define some additional build-conditions (so that .NET3.5 specific code is not built in the assembly targetting .NET2.0).

So far, so good. Everything works fine. Now, the problem however is this:

My solution has a few dependencies (references to 3rd party assemblies). In VS.NET, I've set 'copy local' to true for these dependencies. When CC.NET builds my .NET3.5 version of the assembly, the 3rd party dependencies are indeed copied to my output-directory.

However, when CC.NET builds my .NET2.0 version of the assembly, the dependencies are not copied to my output-directory. (Then, this causes my unit-tests to fail).

My question now is: How can I say to msbuild that certain of the 3rd party references have to be copied local when building my .NET2.0 version of my project ? Or, is there any other way to achieve this, since, I wouldn't like to specify every dependency once again in my build-script. This would quickly become a maintenance nightmare, I guess.

A: 

I've been able to solve this problem by making sure that I do not reference assemblies from the GAC. Instead, I've created a 'lib' directory in my project that contains the 3rd party assemblies. In my solution, I reference the 3rd party assemblies from there, and set copy local==True.

Next to that, you must also make sure that in your csproj file, the referenced assemblies have a Private tag whose value is set to true. Like this:

<Reference Include="...">
   <SpecificVersion>False</SpecificVersion>
   <HintPath>...</HintPath>
   <Private>True</Private>
</Reference>
Frederik Gheysels
+1  A: 

I've been revisiting this problem again, since I do not like to have to manually change the csproj file. (When I change my reference, I must not forget to adapt the csproj file again, to set the Private node to true again).

So, I've been digging into MSDN, and I stumbled upon this:

ResolveAssemblyReference.TargetFrameworkDirectories Property

Remarks This property is required to determine the CopyLocal status for resulting items.

If this property is not specified, no resulting items will be have a CopyLocal value of true unless they explicitly have a Private metadata value of true on their source item.

So, this means that there is yet another possibility, and that is to set the TargetFrameworkDirectories of the ResolveAssemblyReference task. However, is there anybody out there who knows how to do this ?
I've been trying different things, but nothing seems to be working ...

I've tried this:

<ItemGroup>
    <TargetFrameworkDir Include="$(SystemRoot)\Microsoft.NET\Framework\v2.0.50727" />
</ItemGroup>

<PropertyGroup>
   <TargetDirsToUse>@(TargetFrameworkDir)</TargetDirsToUse>
</PropertyGroup>

<ResolveAssemblyReference TargetFrameworkDirectories="$(TargetDirsToUse)" />

But to no avail ... Maybe someone else knows how to do this, or has a golden tip. (I've been spending way to much time on this f*cking issue).

Frederik Gheysels
A: 

One question: what happens if you try to compile your 2.0 solution/projects inside VisualStudio? Are 3rd party references auto-copied or not?

It's odd that this would work for 3.5 and not for 2.0. I haven't done any parallel-building myself, but when I converted my projects from 2.0 to 3.5 all the 3rd party references were copied regardless of the .NET version.

BTW: I never reference 3rd party libraries from GAC (only those from Microsoft, and even not all of them). I always copy them to my lib directory structure, add them to the source control and reference them from there. Using assemblies from GAC is bad practice as far as I am concerned, since it represents an unnecessary dependency on a development machine setup.

Example of such a directory: http://code.google.com/p/projectpilot/source/browse/#svn/trunk/lib

Igor Brejc
When I build from VS.NET targetting .NET 2.0, the resources are being copied locally (just like i want).When I let CC.NET build the solution using my msbuild buidscript, targetting .NET2.0, the referenced assemblies are not copied locally. When it's being build targetting 3.5 (like it is specified in VS.NET), the assemblies are copied.I think I will inspect the csproj and sln file, and see what is specified in it.I also do not reference any 3rd party assemblies from the GAC. I have my dependencies in a lib directory, and i reference them from there. (just like you do)
Frederik Gheysels
Then I guess the difference has to somewhere between the .csproj and your MSBuild build script. Unfortunately I cannot help you much there - I don't use custom MSBuild scripting, I just call MSBuild with the VS solution file. For the rest of the scripting I use my own custom C# build engine.
Igor Brejc