18th Dec 2009
Using TFS (TeamBuild) to build Setup projects in Visual Studio
If you took the shortcut of a Visual Studio Setup project (as opposed to using Wix) then you must have faced the same problem that I did, viz., not being able to create the MSI as part of your TFS nightly builds which hands over the bits to the test team. The problem here is that the vdproj files of the setup projects is in a format that MSBuild (and TeamBuild) does not understand. But we know that Visual Studio can build this project. So I tried to see if I can use devenv.exe to build the project. I tried devenv.exe /? on the command prompt and found that it indeed takes a build switch. So I tried this devenv.exe MySetup.vdproj /build
That did not succeed. The following error message was spit out:
Microsoft (R) Visual Studio Version 9.0.30729.1.
Copyright (C) Microsoft Corp. All rights reserved.
—— Starting pre-build validation for project ‘MySetup’ ——
ERROR: Cannot find outputs of project output group ‘(unable to determine name)’. Either the group, its configuration, or its project may have been removed from the solution.
ERROR: Cannot find outputs of project output group ‘(unable to determine name)’. Either the group, its configuration, or its project may have been removed from the solution.
—— Pre-build validation for project ‘MySetup’ completed ——
—— Build started: Project: MySetup, Configuration: Debug ——
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========
I then decided to run it against the solution file devenv.exe MySolution.sln /Build
That did the trick. The setup files were created in MySolution/MySetup/Debug/ folder.
So I needed to integrate this into the build script. Using devenv.exe means this build machine needs to have Visual Studio installed on it. We already had it, so I was in luck. In some teams they might not allowed the build machine to have Visual Studio.
I added the path to devenv.exe to the system path. Screen shot below should show you how to do that.
As a first attempt I added the following code to the AfterDropBuild target.
<Target Name="AfterDropBuild">
<Exec Command="devenv.exe $(SolutionRoot)/MySolution.sln /Build"/>
<ItemGroup>
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" />
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" />
</ItemGroup>
<Copy SourceFiles="@(SetupFiles)" DestinationFolder="C:\Temp\MSI" />
</Target>
This attempt failed. The error message was not helpful. So I logged into the build machine and tried the same command from command prompt and nothing happened ! So changed the current directory to the location of the sln file and then ran the command again and it worked. So it seems that devenv needs only the name of the sln file (not the full path to it) and the current working directory needs to be the directory when the sln file resides.
So my second attempt:
<Target Name="AfterDropBuild">
<Exec Command="devenv.exe MySolution.sln /Build" WorkingDirectory="$(SolutionRoot)"/>
<ItemGroup>
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" />
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" />
</ItemGroup>
<Copy SourceFiles="@(SetupFiles)" DestinationFolder="C:\Temp\MSI" />
</Target>
That worked ! Well not fully, but the Exec task worked but the Copy task failed. I found the reason for that was the files were getting created in the Debug folder and not the Release folder. In order to force a Release build I had to pass additional info to devenv. So I changed the script as shown below and I could see the bits were getting copied correctly.
<Target Name="AfterDropBuild">
<Exec Command="devenv.exe MySolution.sln /Build "Release|Any CPU"" WorkingDirectory="$(SolutionRoot)"/>
<ItemGroup>
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" />
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" />
</ItemGroup>
<Copy SourceFiles="@(SetupFiles)" DestinationFolder="C:\Temp\MSI" />
</Target>
Here is my final version for copying it to a remote drop location.
<Target Name="AfterDropBuild">
<Exec Command="devenv.exe MySolution.sln /Build "Release|Any CPU"" WorkingDirectory="$(SolutionRoot)"/>
<ItemGroup>
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" />
<SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" />
</ItemGroup>
<Copy SourceFiles="@(SetupFiles)" DestinationFolder="\\Build-Machine\Build_Drop_Folders\MyProjectMSI\$(BuildNumber)" />
<Copy SourceFiles="@(SetupFiles)" DestinationFolder="\\Build-Machine\Build_Drop_Folders\MyProjectMSI\Latest_MSI" />
</Target>
Note: Here $(SolutionRoot) is the path you have given while creating the build definition. You can see it by editing the build definition.
If you took the shortcut of a Visual Studio Setup project (as opposed to using Wix) then you must have faced the same problem that I did, viz., not being able to create the MSI as part of your TFS nightly builds which hands over the bits to the test team. The problem here is that the vdproj files of the setup projects is in a format that MSBuild (and TeamBuild) does not understand. But we know that Visual Studio can build this project. So I tried to see if I can use devenv.exe to build the project. I tried devenv.exe /? on the command prompt and found that it indeed takes a build switch. So I tried this devenv.exe MySetup.vdproj /build
That did not succeed. The following error message was spit out:
Microsoft (R) Visual Studio Version 9.0.30729.1.
Copyright (C) Microsoft Corp. All rights reserved.
—— Starting pre-build validation for project ‘MySetup’ ——
ERROR: Cannot find outputs of project output group ‘(unable to determine name)’. Either the group, its configuration, or its project may have been removed from the solution.
ERROR: Cannot find outputs of project output group ‘(unable to determine name)’. Either the group, its configuration, or its project may have been removed from the solution.
—— Pre-build validation for project ‘MySetup’ completed ——
—— Build started: Project: MySetup, Configuration: Debug ——
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========
I then decided to run it against the solution file devenv.exe MySolution.sln /Build
That did the trick. The setup files were created in MySolution/MySetup/Debug/ folder.
So I needed to integrate this into the build script. Using devenv.exe means this build machine needs to have Visual Studio installed on it. We already had it, so I was in luck. In some teams they might not allowed the build machine to have Visual Studio.
I added the path to devenv.exe to the system path. Screen shot below should show you how to do that.
As a first attempt I added the following code to the AfterDropBuild target.
<Target Name="AfterDropBuild"> <Exec Command="devenv.exe $(SolutionRoot)/MySolution.sln /Build"/> <ItemGroup> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" /> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" /> </ItemGroup> <Copy SourceFiles="@(SetupFiles)" DestinationFolder="C:\Temp\MSI" /> </Target>
This attempt failed. The error message was not helpful. So I logged into the build machine and tried the same command from command prompt and nothing happened ! So changed the current directory to the location of the sln file and then ran the command again and it worked. So it seems that devenv needs only the name of the sln file (not the full path to it) and the current working directory needs to be the directory when the sln file resides.
So my second attempt:
<Target Name="AfterDropBuild"> <Exec Command="devenv.exe MySolution.sln /Build" WorkingDirectory="$(SolutionRoot)"/> <ItemGroup> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" /> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" /> </ItemGroup> <Copy SourceFiles="@(SetupFiles)" DestinationFolder="C:\Temp\MSI" /> </Target>
That worked ! Well not fully, but the Exec task worked but the Copy task failed. I found the reason for that was the files were getting created in the Debug folder and not the Release folder. In order to force a Release build I had to pass additional info to devenv. So I changed the script as shown below and I could see the bits were getting copied correctly.
<Target Name="AfterDropBuild"> <Exec Command="devenv.exe MySolution.sln /Build "Release|Any CPU"" WorkingDirectory="$(SolutionRoot)"/> <ItemGroup> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" /> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" /> </ItemGroup> <Copy SourceFiles="@(SetupFiles)" DestinationFolder="C:\Temp\MSI" /> </Target>
Here is my final version for copying it to a remote drop location.
<Target Name="AfterDropBuild"> <Exec Command="devenv.exe MySolution.sln /Build "Release|Any CPU"" WorkingDirectory="$(SolutionRoot)"/> <ItemGroup> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/MySetup.msi" /> <SetupFiles Include="$(SolutionRoot)/MySetup/Release/Setup.exe" /> </ItemGroup> <Copy SourceFiles="@(SetupFiles)" DestinationFolder="\\Build-Machine\Build_Drop_Folders\MyProjectMSI\$(BuildNumber)" /> <Copy SourceFiles="@(SetupFiles)" DestinationFolder="\\Build-Machine\Build_Drop_Folders\MyProjectMSI\Latest_MSI" /> </Target>
Note: Here $(SolutionRoot) is the path you have given while creating the build definition. You can see it by editing the build definition.
Posted by pc under
General
2 Comments »
