Wednesday 9 September 2009

Cruise control with MSBuild - Switching a reference on the build server

Background

This article is the result of the following problem I encountered a few days ago: We have a piece of software which references a third party dll. We had to deploy the software to a customer with a 64bit server.

This isn’t a problem for the code written in house, as it is all managed so runs in a 64bit environment no problem. Unfortunately, the third party dll we are using is 32 bit specific. There is a 64 bit version, but in order to develop against the library we have to reference the 32 bit dll (we all work on 32 bit machines).

The build setup

First off, we keep all third party dlls within a folder in our solution, so anyone can grab the source code from VSS (I know...) and compile it.

We run Continuous Integration using Cruise Control and MSBuild to do the building by reading our solutions files. On every check-in, a build is triggered, resulting in a build containing everything the software needs, ready to deploy.

Fixing the problem

First we deployed the software to a 64 bit server and tried simply copying over the 32 bit dll with the 64 bit version – they are both the same version number, so with fingers crossed we fired up the app. No such luck:

The located assembly's manifest definition does not match the assembly reference

Kind of expected that to be honest...

We then restructured our external references folder ‘BinRefs’ a little, and added the 64 bit dlls to the solution:

Then changed the reference in the project file to point to the new location for the 32 bit dll.

The plan was to get the build server to open the project file containing the reference to the 32 bit dll and change the path to the dll so it points at the 64 bit version before building the solution.

VS2008 project files hold their references to dlls as below:

So I simply needed to replace the string

“..\..\BinRefs\32Bit\SomeLibrary.dll”

With the relative path to the 64 bit dll

“..\..\BinRefs\64Bit\SomeLibrary.dll”

Before MSBuild starts compiling.

A quick and dirty VBScript with a batch file to kick it off takes care of the job of replacing the HintPath in the project file:

VBScript (Replace32bitDLL.vbs)

dim fso
dim txtStr
dim strHolder
dim strFileToFix

' Replace reference to SomLibrary in MyProject project
strFileToFix = "Build64\Services\PDF\MyProject.vbproj"
set fso = wscript.createobject("scripting.filesystemobject")
set txtStr = fso.opentextfile(strFileToFix,1,false,0)
strHolder = txtstr.readall
txtStr.close
set txtStr = nothing
strHolder = replace(strHolder,"..\..\BinRefs\32Bit\SomeLibrary.dll","..\..\BinRefs\64Bit\SomeLibrary.dll",1,-1,vbtextcompare)

set txtStr = fso.createtextfile(strFileToFix,true,false)
txtStr.write(strHolder)
txtStr.close
set txtStr = nothing


Batch Script (Replace32bitDLL.cmd)

ECHO StartingDllReplace
CScript Replace32bitDll.vbs
ECHO FinishedDllReplace


Finally a task is added to the project section in the Cruise Control config file before the call to MSBuild (shown in bold):


<tasks>
<exec>
<baseDirectory>E:\Dev\Development</baseDirectory>
<executable>Replace32bitDLL.cmd</executable>
</exec>

<msbuild>
&msb3Exe;
<workingDirectory>E:\Development\Build64</workingDirectory>
<projectFile>MySolution.sln</projectFile>
&releaseBuildArgs;
<targets>Build</targets>
&msBuildLogger;
</msbuild>
</tasks>


And you’re sorted. Check-ins result in builds ready to be deployed to 64 bit machines.

No comments: