Get a Visual Studio project (MSBuild) to know the Team Build output location - msbuild

I have this custom build step form my project:
<Target Name="BeforeBuild">
<WriteLinesToFile Condition="" File="$(OutputPath)\env.config"
Lines="$(Configuration)" Overwrite="true">
</WriteLinesToFile>
</Target>
Basically it outputs the build configuration to a file.
This works fine when building in Visual Studio. Team Build decided to make things harder. The OutputPathfor Team Build is in a different spot (not bin\$(Configuration))
I know how to find out if the build is part of a team build (Condition=" '$(TeamBuildConstants)' == '_TEAM_BUILD_' ") but unless I want to hard code the path, I can't see a way to get the Team Build path.
Any ideas on how to find out (in the project, the the Team Build file) what the output location is?

You might need to use $(OutDir) when running in Team Build:
http://blogs.msdn.com/aaronhallberg/archive/2007/06/07/preserving-output-directory-structures-in-orcas-team-build.aspx
So you could use the _TEAM_BUILD_ condition and have two calls - one with OutputPath and one with OutDir.

Related

How Do I Get _PublishedWebsites Folder via "AsConfigured" Build Definition Setting?

I'm currently setting up my builds in TFS to output on my build machine "AsConfigured". However, when I do this, _PublishedWebsites does not show up. I Get a _PublishedWebsites folder when I set up the build as SingleFolder, but I want to maintain my folder structure.
I've tried setting up a Publishing Profile, but I don't want it to apply to the entire solution (I am specifying the solution to build in the build definition). Using the following below, I've got close, but it only outputs one of my two web projects:
/p:DeployOnBuild=true;DeployTarget=PipelinePreDeployCopyAllFilesToOneFolder;PackageTempRootDir="C:\Publish";AutoParameterizationWebConfigConnectionStrings=false /p:UseWPP_CopyWebApplication=True /p:PipelineDependsOnBuild=False
Any ideas?
I ended up implementing a Publish Profile with FileSystem in tandem with modifying each web project's csproj file and inserting:
<DeployOnBuild Condition=" '$(IsInTFS)' == 'true'">true</DeployOnBuild>
<PublishProfile Condition=" '$(IsInTFS)' == 'true'">MyTFSProfile</PublishProfile>
Credit goes to http://dobrish.blogspot.ca/2013/04/web-deployement-in-tfs2012.html

WiX project that references an SSDT project fails to build in TFSBuild - Undefined preprocessor variable '$(var.DatabaseProject.TargetDir)'

My project which is part of a larger solution was converted from a dbproj to asqlproj (SSDT). The solution includes a WiX installer which references the SSDT project. The WiX project builds fine on multiple developer systems through VS2010. The automated builds that we've always used, however, are failing with this error:
error CNDL0150: Undefined preprocessor variable '$(var.DatabaseProject.TargetDir)'.
The solution has been built by TFS automated builds for many months without issue prior to this project being converted. I can see from the build log that the SSDT project is being built, here are some relevant lines from the build log:
Project "C:\B\1\SourcePath\Server\Server.wixproj" (8) is building "C:\B\1\SourcePath\Database\DatabaseProject.sqlproj" (12) on node 1 (default targets).
...
Done Building Project "C:\B\1\SourcePath\Database\DatabaseProject.sqlproj" (default targets).
I can also see that the .dacpac and .dll files for the database project are created and copied into the output directory that TFS build has redirected the projects to.
The reference to the database project seems fine and TFS build seems to know that it should be built, but WiX is complaining about the undefined preprocessor variable for TargetDir.
I must be missing something...Is the output redirect employed by TFS causing my issue? I'm not sure where to go from here and appreciate any help you can suggest.
MORE INFO
Looking at the log file for the build in more detail I can see that the parameters for the .sqlproj project aren't being passed on the command line to candle.exe. When I build locally in VS2010, I can see the expected parameters passed as follows (just like the other projects referenced by the WiX project):
-d"DatabaseProject.FullConfiguration=Release|AnyCPU"
-dDatabaseProject.Platform=AnyCPU
-dDatabaseProject.ProjectDir=C:\SourcePath\Database\
-dDatabaseProject.ProjectExt=.sqlproj
-dDatabaseProject.ProjectFileName=DatabaseProject.sqlproj
-dDatabaseProject.ProjectName=DatabaseProject
-dDatabaseProject.ProjectPath=C:\SourcePath\Database\DatabaseProject.sqlproj
-dDatabaseProject.TargetDir=C:\SourcePath\Database\sql\release\
-dDatabaseProject.TargetExt=.dll
-dDatabaseProject.TargetFileName=DatabaseProject.dll
-dDatabaseProject.TargetName=DatabaseProject
-dDatabaseProject.TargetPath=C:\SourcePath\Database\sql\release\DatabaseProject.dll
None of these parameters are being passed to candle.exe during the TFS build. I figured this information might be useful for helping answer the question.
Any help is greatly appreciated!
Based on #RobMenching's answer, you won't be able to rely on the SSDT project variable to be set by any command-line build, so you'll need to find another way to reference the project's output.
Fortunately, in a standard TFS build, the output folders will be the same for all projects in a given build configuration. Assuming you haven't redirected the output somehow, you should be able to use any of the other projects (which are working properly) as the reference path. E.g., assuming that you have a DatabaseProject.sqlproj and an DataAccessProject.csproj in the solution, you should be able to do:
<Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012'>
<?ifdef DatabaseProject.TargetDir ?>
<File Id='foo' Name='foo' src='$(var.DatabaseProject.TargetDir)\foo.dacpac' />
<?else?>
<File Id='foo' Name='foo' src='$(var.DataAccessProject.TargetDir)\foo.dacpac' />
<?endif?>
</Component>
For builds done inside VS2010, where each project is built to its own output folder, the correct preprocessor variable ought to be defined and it will use the first option. For TFS builds, where the preprocessor variable is not defined, TFS will have redirected the SSDT's output to the same folder as all of the other projects, so any one of the preprocessor variables should work just as well.
I believe the root issue here is that the .sqlproj does not support the necessary Visual Studio integration to provide the data for the preprocessor variable. This has created a lot of problems for the WiX toolset over the years. Unfortunately, fixing it requires the owners of the .sqlproj to fix their project system.

Using a project file as a parameter in MSBuild with Hudson

I'm currently using the Hudson build system with MSBuild steps. As part of the build, I have a project file with various targets in, one of which is to start a build with visual studio. However, I need to pass through a seperate project file to this target in order for it to build, but I keep getting the exception 'MSBUILD : error MSB1008: Only one project can be specified.'
I believe this is because the system is unable to calculate which project is supposed to be the parameter, and which the top-level target? If so, is there anyway to resolve this.
Here is a snippet of the target project file:
<Target Name="VisualStudioTask">
<!-- Required Properties:
$(BuildType)
$(ConfigurationSetup)
$(Solution)-->
<Exec Command="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe $(BuildType) $(ConfigurationSetup) $(Solution)" />
</Target>
The MSBuild step calling this looks like this:
/t:VisualStudioTask -p:BuildType="/Build" p:ConfigurationSetup="Release" -p:Solution="%22..\MyProject.vcproj%22"
Many thanks
Chris
I have figured it out, the problem was that I'd left out a '-' when declaring the 'ConfigurationSetup' parameter, so if you look in my original example it has this:
/t:VisualStudioTask -p:BuildType="/Build" p:ConfigurationSetup="Release" -p:Solution="%22..\MyProject.vcproj%22"
When it should have this..
/t:VisualStudioTask -p:BuildType="/Build" -p:ConfigurationSetup="Release" -p:Solution="%22..\MyProject.vcproj%22"

How do I specify the platform for MSBuild?

I am trying to use MSBuild to build a solution with a specified target platform (I need both binaries, x86 and x64). This is how I tried it:
C:\WINDOWS\Microsoft.NET\Framework\v3.5>MsBuild SolutionPath\Solution.sln /t:Rebuild /p:Configuration=Release /p:Platform="x86"
However the build always fails if the platform is different from "Any CPU". What am I doing wrong?
This is the while output MSBuild prints:
C:\WINDOWS\Microsoft.NET\Framework\v3.5>MsBuild
SolutionPath\Solution.sln /t:Rebuild
/p:Configuration=Release
/p:Platform="x86" Microsoft (R) Build
Engine Version 3.5.30729.1 [Microsoft
.NET Framework, Version
2.0.50727.3082] Copyright (C) Microsoft Corporation 2007. All rights
reserved.
Build started 1.7.2010 8:28:10.
Project "SolutionPath\Solution.sln" on
node 0 (Rebuild targe t(s)).
SolutionPath\Solution.sln : error
MSB4126: The specified sol ution
configuration "Release|x86" is
invalid. Please specify a valid
solution c onfiguration using the
Configuration and Platform properties
(e.g. MSBuild.exe Solution.sln
/p:Configuration=Debug
/p:Platform="Any CPU") or leave those
prope rties blank to use the default
solution configuration. Done Building
Project "SolutionPath\Solution.sln"
(Rebuild t arget(s)) -- FAILED.
Build FAILED.
"SolutionPath\Solution.sln" (Rebuild
target) (1) ->
(ValidateSolutionConfiguration target)
-> SolutionPath\Solution.sln : error MSB4126: The specified s olution
configuration "Release|x86" is
invalid. Please specify a valid
solution configuration using the
Configuration and Platform properties
(e.g. MSBuild.ex e Solution.sln
/p:Configuration=Debug
/p:Platform="Any CPU") or leave those
pro perties blank to use the default
solution configuration.
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:00.03
If I try to build it for x86/x64 with devenv it works perfectly, however I am trying to set up a build server without installing all the necessary versions of Visual Studio. By the way, if there is a better free tool (that supports .NET framework 4) out there, I'd love to hear about it.
In MSBuild or Teamcity use command line
MSBuild yourproject.sln /property:Configuration=Release /property:Platform=x64
or use shorter form:
MSBuild yourproject.sln /p:Configuration=Release /p:Platform=x64
However you need to set up platform in your project anyway, see the answer by Julien Hoarau.
If you want to build your solution for x86 and x64, your solution must be configured for both platforms. Actually you just have an Any CPU configuration.
How to check the available configuration for a project
To check the available configuration for a given project, open the project file (*.csproj for example) and look for a PropertyGroup with the right Condition.
If you want to build in Release mode for x86, you must have something like this in your project file:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
...
</PropertyGroup>
How to create and edit the configuration in Visual Studio
(source: microsoft.com)
(source: msdn.com)
(source: msdn.com)
How to create and edit the configuration (on MSDN)
If you're trying to do this from the command line, you may be encountering an issue where a machine-wide environment variable 'Platform' is being set for you and working against you. I can reproduce this if I use the VS2012 Command window instead of a regular windows Command window.
At the command prompt type:
set platform
In a VS2012 Command window, I have a value of 'X64' preset. That seems to interfere with whatever is in my solution file.
In a regular Command window, the 'set' command results in a "variable not defined" message...which is good.
If the result of your 'set' command above returns no environment variable value, you should be good to go.
Hopefully this helps someone out there.
For platform I was specifying "Any CPU", changed it to "AnyCPU" and that fixed the problem.
msbuild C:\Users\Project\Project.publishproj /p:Platform="AnyCPU" /p:DeployOnBuild=true /p:PublishProfile=local /p:Configuration=Debug
If you look at your .csproj file you'll see the correct platform name to use.
For VS2017 and 2019... with the modern core library SDK project files, the platform can be changed during the build process. Here's an example to change to the anycpu platform, just before the built-in CoreCompile task runs:
<Project Sdk="Microsoft.NET.Sdk" >
<Target Name="SwitchToAnyCpu" BeforeTargets="CoreCompile" >
<Message Text="Current Platform=$(Platform)" />
<Message Text="Current PlatformTarget=$(PlatformName)" />
<PropertyGroup>
<Platform>anycpu</Platform>
<PlatformTarget>anycpu</PlatformTarget>
</PropertyGroup>
<Message Text="New Platform=$(Platform)" />
<Message Text="New PlatformTarget=$(PlatformTarget)" />
</Target>
</Project>
In my case, I'm building an FPGA with BeforeTargets and AfterTargets tasks, but compiling a C# app in the main CoreCompile. (partly as I may want some sort of command-line app, and partly because I could not figure out how to omit or override CoreCompile)
To build for multiple, concurrent binaries such as x86 and x64: either a separate, manual build task would be needed or two separate project files with the respective <PlatformTarget>x86</PlatformTarget> and <PlatformTarget>x64</PlatformTarget> settings in the example, above.
When you define different build configurations in your visual studio solution for your projects using a tool like ConfigurationTransform, you may want your Teamcity build, to build you a specified build configuration. You may have build configurations e.g., Debug, Release, Dev, UAT, Prod etc defined. This means, you will have MSBuild Configuration transformation setup for the different configurations. These different configurations are usually used when you have different configurations, e.g. different database connection strings, for the different environment. This is very common because you would have a different database for your production environment from your playground development environment.
They say a picture is worth a thousand words, please see the image below how you would specify multiple build configurations in Teamcity.
In the commandline input text box, specify as below
/p:OutputPath=Publish;Configuration=Dev
Here, I have specified two commandline build configurations/arguments OutputPath and build Configuration with values Publish and Dev respectively, but it could have been, UAT or Prod configuration. If you want more, simply separate them by semi-colon,;
There is an odd case I got in VS2017, about the space between ‘Any’ and 'CPU'.
this is not about using command prompt.
If you have a build project file, which could call other solution files. You can try to add the space between Any and CPU, like this (the Platform property value):
<MSBuild Projects="#(SolutionToBuild2)" Properties ="Configuration=$(ProjectConfiguration);Platform=Any CPU;Rerun=$(MsBuildReRun);" />
Before I fix this build issue, it is like this (ProjectPlatform is a global variable, was set to 'AnyCPU'):
<MSBuild Projects="#(SolutionToBuild1)" Properties ="Configuration=$(ProjectConfiguration);Platform=$(ProjectPlatform);Rerun=$(MsBuildReRun);" />
Also, we have a lot projects being called using $ (ProjectPlatform), which is 'AnyCPU' and work fine. If we open proj file, we can see lines liket this and it make sense.
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
So my conclusion is,
'AnyCPU' works for calling project files, but not for calling solution files,
for calling solution files, using 'Any CPU' (add the space.)
For now, I am not sure if it is a bug of VS project file or MSBuild.
I am using VS2017 with VS2017 build tools installed.
In Visual Studio 2019, version 16.8.4, you can just add
<Prefer32Bit>false</Prefer32Bit>

MSBuild speedup: how to remove unnecessary project builds?

I have a solution with several projects in it. Let's say
project A depends on projects B and C
project B depends on project C
When I run my solution on the local machine VS builds each project once and it takes 1 minute. However, on our build machine it takes about 4 minutes to build and, as I can understand from the MSBuild logs it goes like this:
build A -> build B for A, build C for A
build B -> build C for B
So it builds some projects several times... How can I speed up the build process?
P.S. It's not a question of 3 extra minutes, I just wonder why is it so different from my local machine build?
I am not sure about your build order. Sometimes TeamBuild can look like it is building projects over and over but it is building for different configurations. Take a look and make sure you have not defined multiple FlavorsToBuild.
Also, if you don't want to do a fresh check out and rebuild every time, you can define this at the bottom of your TFSBuild file.
<PropertyGroup>
<IncrementalBuild>true</IncrementalBuild>
</PropertyGroup>-->
Put that right before the </Project> tag.
This sample seems to work for me. TestLib.Extra depends on TestLib. If I change something in TestLib, both projects will build. If I change only in TestLib.Extra, only that one will build, and if I don't change anything at all, they will just report Skipping target "CoreCompile" because all output files are up-to-date and so on.
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib\TestLib.csproj" />
<MSBuild Targets="Build" Projects="TestLib.Extra\TestLib.Extra.csproj" />
</Target>
The trick is to use the "Build" target of the projects, rather than "Rebuild". The difference between these is essentially the same as the difference between the "Build" and "Rebuild" commands in the build menu in Visual Studio.
Edit
This works well also if the projects are included in a solution file, and you specify the solution to build instead:
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib.sln" />
</Target>
Maybe like our's, your build server is a virtual machine (10x at least slower).
Also TFS (and maybe others), does a fresh checkout on build, so it will have to build all the projects regardless.
Are you using the /maxcpucount switch? There may be a difference in number of processors between your local machine and the build machine. This setting can also be different between your msbuild file and the visual studio setting which could also explain the difference you're seeing in build times.
I do this as follows. It is somewhat complicated custom build system but the basic idea is.
The dlls which are reused in many solutions are build to a known folder. This is achieved my using a msbuild project file that builds these common dlls.
When building other csproj files in a solution we copy the csproj files then use xslt manipulation to replace the project references with dll refernces for those common dlls.
The build scripts then build these changed csproj files using custom msbuild project files we maintain corresponding to each solutions. We don't build .sln files. These custom project files is a itemgroup of .csproj files in correct dependency order.
Maybe this can help you in achieving what you want.