From time to time, we see questions around building a project created with the Visual Studio 2010 SDK on a build server (e.g. Team Foundation Build, TeamCity, CC.NET, etc…). The primary misconception that folks have is that you must install Visual Studio 2010 + SDK on the build server.
In this post, I’ll walk through the process of getting a C#/VB VSPackage project up and running on Team Foundation Build, without requiring an install of Visual Studio on the build agent machine. The same steps apply for editor extensions or other extensibility project types.
Once you’ve configured the build server and are ready to try out a build, you’ll probably see something like the following error in your build log:
Since neither Visual Studio nor the Visual Studio SDK are installed on my build machine, the build complains about the missing Microsoft.VsSDK.targets file. This is simple enough to fix by doing the following:
Let’s try checking in again and seeing where we are now:
The reason that MSBuild is trying to run AxImp.exe is because we have a collection of COMReference elements in our VSPackage project. Instead of registering these assemblies as COM components on the build server, let’s copy these binaries to our local project and add them as normal assembly references:
Let’s check in and try another build on the server
Let’s take a look at the actual line where we’re hitting the error in Microsoft.VsSDK.Common.targets:
<Target Name="FindSDKInstallation" Condition="'$(VsSDKInstall)'==''"> <FindVsSDKInstallation SDKVersion="$(VsSDKVersion)"> …
The reason this task needs to run is because the VsSDKInstall property (and friends) hasn’t been set yet. Let’s use the “vssdk_tools” folder we had set up earlier. Edit your project file again, and add the following properties to the first <PropertyGroup> element:
<VsSDKInstall>..\vssdk_tools</VsSDKInstall> <VsSDKIncludes>$(VsSDKInstall)\inc</VsSDKIncludes> <VsSDKToolsPath>$(VsSDKInstall)\bin</VsSDKToolsPath>
Clearly, this won’t work until we actually have the corresponding files from the Visual Studio SDK also checked in to those directories. Let’s do that now:
Let’s checkin again and see where we are now:
Hmmm…this one is a bit tricky. It turns out that some of the VSSDK build tasks rely on not only the $(VsSDKToolsPath) MSBuild property, but they also rely on this being set as an environment variable. We can do that fairly easily with an inline build task which we can add to our project file:
<UsingTask TaskName="SetVsSDKEnvironmentVariables" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> <ParameterGroup> <ProjectDirectory Required="true" /> </ParameterGroup> <Task> <Code Type="Fragment" Language="cs"> System.Environment.SetEnvironmentVariable("VsSDKToolsPath", System.IO.Path.GetFullPath(ProjectDirectory + @"\..\vssdk_tools\bin")); </Code> </Task> </UsingTask> <Target Name="SetVsSDKEnvironmentVariables" BeforeTargets="VSCTCompile"> <SetVsSDKEnvironmentVariables ProjectDirectory="$(MSBuildProjectDirectory)" /> </Target>
Let’s cross our fingers and try again:
By default, TFS will use the x64 version of MSBuild.exe (assuming you’re on a 64-bit server). Since the VSCT assembly is 32-bit only, it will fail to load in a 64-bit process. To use 32-bit MSBuild.exe on the server (if you’re using Team Foundation Build), simply edit the build definition and change Process => Advanced => MSBuild Platform to “X86” instead of “Auto”.
One more try:
In step 3, we only added the COMReferences to source control. Now, let’s do a similar procedure with the other assemblies:
One more time…
CreatePkgDef.exe is the tool used to create a pkgdef file for your VSPackage. The tool itself relies on types defined in the Microsoft.VisualStudio.Shell.Immutable.10.0 assembly. On a machine with Visual Studio 2010 installed, there isn’t a problem loading it since the assembly is installed to the GAC. However, on our build server, the assembly is not in the GAC since Visual Studio 2010 isn’t installed.
In order to allow CreatePkgDef.exe to find the assembly, we can simply add a copy of this binary in our vssdk_tools\bin directory. Do the following:
This task fails because the build task can’t locate the XML schema file for VSIXManifest to do schema validation. We could just switch this task off, but since it’s a good idea to run this validation when we build, let’s do what’s necessary to enable validation. There is an MSBuild property we can set to override this location on our build server. Simply add the following property to the first <PropertyGroup>:
Of course, we also need to add the schema file to this directory:
Let’s try again and see where we are:
To make ‘F5’ debugging work without any work by the user, by default, there are some additional targets that run in Microsoft.VsSDK.Common.targets. These targets ‘deploy’ your extension’s files to the Experimental instance for debugging. Since this scenario doesn’t make sense for our build server, we should disable it.
The Visual Studio SDK includes a project property page for configuring this property:
Note that you will probably want a separate build configuration for your build server (to set this property to false) so that developers can still easily debug their package on a client machine.
If you prefer to configure this directly in your project file instead of using the UI, use the following property:
Let’s see how this affects our build:
Hooray! If I check the build output directory, we now see that we have a VSIX file that was built on the server: