How or why is MSBuild choosing the x64 platform when I don't specify it instead of AnyCPU? - msbuild

I'm running msbuild.exe via Rake from a regular PowerShell console. This is the command as printed from a diagnostic level run
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" "D:/Projects/machine.specifications/Source/Machine.Specifications/Machine.Specifications.csproj31881140" /maxcpucount /target:Build /verbosity:diagnostic /property:Configuration=Debug /property:TrackFileAccess=false /property:BuildInParallel=false /property:BuildRunner=Rake
And the build is failing because msbuild is picking x64 as the Platform.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(483,9): error : The OutputPath property is not set for project 'Machine.Specifications.csproj37103470'. Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='Debug' Platform='X64'. You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Configuration or Platform that doesn't exist for this project.
I'm not passing it in on the command line (or from the script). The csproj has a default configuration
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
and two specific configurations
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
So, I expected the AnyCPU platform to be selected. But, for some reason, something is picking or sending in x64. I don't think the Rake system is a problem here, I've seen this behavior before on raw cmd line calls to msbuild (but I haven't documented them).
I'm on 64-bit Windows 7, calling msbuild 4.0. I don't know if that's relevant.
I am loading the 64-bit Visual Studio tools (C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64) using Invoke-BatchFile in my PowerShell profile. Could that be the culprit?
Why would msbuild deliberately choose x64 anyway? The 32-bit version doesn't choose x86 for you.
*1: The PowerShell console is at %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
*2: I'm running the MSpec build (here's the rakefile and the msbuild call)

When you launch Visual Studio x64 command window, it sets an environment variable :
Platform=X64
This is a difference from the 32 bit command window, where this environment variable is not defined, and MSBuild then uses the conditional logic to use default platform.
You can either remove the Platform environment variable in your batch file, or pass in explicit Platform property as a parameter to MSBuild.

Related

Command line MSBuild not exluding Debug libraries

So I have build a UWP application which I have built an .appxupload package through Visual Studio and submitted it to the store and it has been accepted to the store fine.
I am now trying to use Visual Studio Online to Automate my build process.
I am building my project in a new configuration I have defined called AppStore that looks like the following:
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'AppStore|AnyCPU'">
<OutputPath>bin\AppStore\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
And my Command line arguments for the Automated build are:
/p:Configuration=AppStore;AppxBundle=Always;AppxBundlePlatforms="x86|x64|ARM";AppxPackageDir="$(Build.BinariesDirectory)\AppxPackages\\";UapAppxPackageBuildMode=StoreUpload
This then created my .appxupload package on request which was great.. BUT... when I uploaded to the store I get the following:
Debug configuration
Error Found: The debug configuration test detected the following errors:
The binary MyApp.Logging.dll is built in debug mode.
The binary MyApp.Reports.dll is built in debug mode.
The binary MyApp.DataAccess.dll is built in debug mode.
The binary MyApp.Business.dll is built in debug mode.
The binary MyApp.Core.dll is built in debug mode.
Are my MsBuild arguments incorrect?
Update
this is the command MSBuild is running:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe" "C:\agent\_work\1\s\MyApp\MyApp\MyApp.UWP\MyApp.UWP.csproj" /nologo /nr:false /t:"Clean" /dl:CentralLogger,"C:\agent\_work\_tasks\VSBuild_71a9a2d3-a98a-4caa-96ab-affca411ecda\1.118.0\ps_modules\MSBuildHelpers\Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll";"RootDetailId=ebe5f0fb-1da0-4f6b-aa54-d80c73ac3060|SolutionDir=C:\agent\_work\1\s\MyApp\MyApp\MyApp.UWP"*ForwardingLogger,"C:\agent\_work\_tasks\VSBuild_71a9a2d3-a98a-4caa-96ab-affca411ecda\1.118.0\ps_modules\MSBuildHelpers\Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll" /p:Configuration=AppStore;AppxBundle=Always;AppxBundlePlatforms="x86|x64|ARM";AppxPackageDir="C:\agent\_work\1\b\AppxPackages\\";UapAppxPackageBuildMode=StoreUpload /p:configuration="AppStore" /p:VisualStudioVersion="15.0" /p:_MSDeployUserAgent="VSTS_7c0e42bd-65b9-486e-9338-1c87ca14bb55_build_3_1182"
It seems to produce x86 in Release mode and x64 and ARM in debug and thats where my app fails Windows Certification Checks
Refer to these steps to change configuration:
Right click solution file in VS > Configuration Manager
Select AppStore configuration
Change configurations of MyApp.Logging, MyApp.Reports, MyApp.DataAccess … (e.g. release)

What configuration and platform does msbuild use by default when building a solution file or project files

If I execute msbuild from the command line with my solution file or project file as input without setting configuration and platform how does msbuild determine which configuration and platform to use for each project in the solution or the single project file?
In case of solution files - both msbuild and xbuild try to find Debug config and Mixed platforms platform, but if that doesn't exist then it falls back to the first one that it can find under SolutionConfigurationPlatforms in the .sln file. Keep in mind that this is just solution level config/platform, and it uses the mapping in ProjectConfigurationPlatforms in the .sln file to determine the config/platform to use for the project.
In case of project files, the *proj files usually have the default Configuration and Platform specified. But if even that is missing then the Microsoft.Common.*targets file chooses Debug|AnyCPU as the default.
Update: default specification in the csproj might look like this:
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
...
It's essentially saying "if $(Configuration) is unspecified, then set it to Debug", and similar for Platform.

What is default msbuild platform

How does msbuild chose a platform if it is not specified? It seems to me that for some solutions it selects "Mixed Platforms" for others "x86".
I switch on the diagnostics level of logging and the only thing I can see is that "Initial Properties" at the beginning contain e.g. "Platform = Mixed Platforms" without any explanation why.
To preempt some answers, I know that I can override the platform manually. That is not an issue. I need to know what msbuild does when it is NOT specified.
This may help: I was researching this and finally tracked down the default platform for my install, by looking in Microsoft.Cpp.Default.props (line 21 in this version of Visual Studio), which lives in Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120:
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
This means that under VS12 (Visual Studio 2013) MSBuild will pick Win32 as the platform if no other platform is explicitly specified. As noted in some other questions, setting an environment variable named Platform will change the default to the value you set.
Important note: If you invoke MSBuild on a Visual Studio solution file (*.sln) rather than a project file, and you don't specify a platform in the MSBuild arguments, then it appears that MSBuild will choose the platform automatically based on the first entry under the SolutionConfigurationPlatforms global section in the solution file. I haven't found this documented anywhere but from experimentation it appears to be the case. This means that editing your project file and providing a different default Platform property (as described above), MSBuild will ignore this default, because it will have chosen the platform already before it even starts looking at the project. Invoking MSBuild directly on the project file seems to bypass this behavior.
MSBuild does not choose but whatever MSBuild project it is building may default certain properties. I am assuming that your question relates to how MSBuild builds a solution file.
msbuild.exe "somesolution.sln" /t:Build
You need to look at the projects that make up the solution, in there you will see the properties that are set. For example you will probably see the following at the top of the project file:
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
...
</PropertyGroup>
This shows a PropertyGroup containing amongst others two properties, Configuration and Platform. Their values are set based on a Condition. The condition says says that if no value has been set for the property Configuration it should default to 'Debug'. Likewise if nothing is set for Platform it should default to AnyCPU.
You may also see a Conditional PropertyGroup:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
...
</PropertyGroup>
What this condition says is that if the property Configuration and Platform match Debug and AnyCPU then it should apply all of the properties contained within.
A point to note is that the property names are just an arbitrary name and the values are just strings. However when building .Net projects there is a convention to which these properties and their values are a part. To see what the default values are you do not need to open each project in a text editor. You can go into Visual Studio and look at the solution configuration.

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>

Overriding MSBuildExtensionsPath in the MSBuild task is flaky

This is already cross-posted at MS Connect:
https://connect.microsoft.com/VisualStudio/feedback/details/560451
I am attempting to override the property $(MSBuildExtensionsPath) when building a solution containing a C# web application project via msbuild. I am doing this because a web application csproj file imports the file "$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets". This file is installed by Visual Studio to the standard $(MSBuildExtensionsPath) location (C:\Program Files\MSBuild). I would like to eliminate the dependency on this file being installed on the machine (I would like to keep my build servers as "clean" as possible). In order to do this, I would like to include the Microsoft.WebApplication.targets in source control with my project, and then override $(MSBuildExtensionsPath) so that the csproj will import this included version of Microsoft.WebApplication.targets. This approach allows me to remove the dependency without requiring me to manually modify the web application csproj file.
This scheme works fine when I build my solution file from the command line, supplying the custom value of $(MSBuildExtensionsPath) at the command line to msbuild via the /p flag. However, if I attempt to build the solution using the MSBuild task in a custom msbuild project file (overriding MSBuildExtensionsPath using the "Properties" attribute), it fails because the web app csproj file is attempting to import the Microsoft.WebApplication.targets from the "standard" Microsoft.WebApplication.targets location (C:\Program Files\MSBuild). Notably, if I run msbuild using the "Exec" task in my custom project file, it works. Even more notably, the FIRST time I run the build using the "MSBuild" task AFTER I have run the build using the "EXEC" task (or directly from the command line), the build works.
Has anyone seen behavior like this before? Am I crazy? Is anyone aware of the root cause of this problem, a possible workaround, or whether this is a legitimate bug in MSBuild?
Steps to Reproduce:
1) Create a new empty solution in MSVS 2008 (Fake.sln)
2) Add a new C# web application to the solution (WebApplication1.csproj)
3) Close MSVS
4) Copy the contents of "C:\Program Files\MSBuild\" to a directory called "MSBuildExtensions" in the directory containing your solution.
5) rename the directory "C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\WebApplications" so that WebApplication1.csproj will not be able to import Microsoft.WebApplication.targets from that location.
6) Create a custom MSBuild project file called "TestBuild.proj" in the same directory as the solution. It should have the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="BuildMSBuild">
<PropertyGroup>
<MSBuildExtensionsPath>$(MSBuildProjectDirectory)\MSBuildExtensions\</MSBuildExtensionsPath>
<BuildThis>Fake.sln</BuildThis>
</PropertyGroup>
<Target Name="BuildMSBuild">
<MSBuild Projects="$(BuildThis)" Properties="MSBuildExtensionsPath=$(MSBuildExtensionsPath);" Targets="Clean" />
<MSBuild Projects="$(BuildThis)" Properties="MSBuildExtensionsPath=$(MSBuildExtensionsPath);"/>
</Target>
</Project>
7) execute "msbuild TestBuild.proj" from a MSVS command prompt (note: the build may succeed the first time, but will fail if you run more than once)
Did you try setting the environment variable MSBuildExtensionPath in the CMD prompt and then running your build?
For example:
C:\> SET MSBuildExtensionsPath=C:\My\MSBuild\Extensons
Then on this project file:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<Message Text='MSBuildExtensionsPath="$(MSBuildExtensionsPath)"' />
</Target>
</Project>
you will get the following output:
c:\Users\chuckeng\Desktop\ConsoleApplication1>"C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe" my.proj
Microsoft (R) Build Engine Version 3.5.30729.4926
[Microsoft .NET Framework, Version 2.0.50727.4927]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 6/25/2010 1:04:05 PM.
Project "c:\my.proj" on node 0 (default targets).
MSBuildExtensionsPath="C:\My\MSBuild\Extensons"
Done Building Project "c:\my.proj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.03
This works from v4.0 as well. Although, support is generally better in v4.0 for things like this. And, v4.0 is 100% backward compatible (bugs not withstanding). So, you can build your v3.5 and prior projects with v4.0. Just select ToolsVersion 3.5.
msbuild my.proj /tv:3.5
Hope this helps...
Chuck England
Visual Studio
Program Manager - MSBuild
This is a bug in MSBuild 3.5 but it is fixed in MSBuild 4.
If you can, switch to MSBuild 4 (you still can compile your 3.5 projects), otherwise you'll have to override the property in the project file.
It works fine if you override MSBuildExtensionsPath directly in the web app .csproj file.
<PropertyGroup>
<MSBuildExtensionsPath>C:\Users\madgnome\Desktop\msbuild</MSBuildExtensionsPath>
<!-- It works too with relative path -->
<!--<MSBuildExtensionsPath>..\msbuild</MSBuildExtensionsPath>-->
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
Don't know if this might help anyone in the future, but I was able to use the following at the top of my file and it works as I would expect in both 32 and 64 bit build environments.
<PropertyGroup>
<MSBuildExtensionsPath Condition=" '$(MSBuildExtensionsPath64)' != '' ">$(MSBuildExtensionsPath64)</MSBuildExtensionsPath>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/>