How is PlatformTarget assigned?

2024年1月24日

In MSBuild, there are two similar properties, PlatformTarget and Platform.

Differences between PlatformTarget and Platform

PlatformTarget is basically an enum with possible values, AnyCPU, x86, x64, ARM, etc.

Platform on the other hand is a user-defined value, though it is commonly equal to x86 or x64. Certain Platform, as a configuration, may set PlatformTarget[1].

Assigning PlatformTarget

First of all, MSBuild has an option to set project-level properties.

msbuild -property:PlatformTarget=x86

Then, as I said, certain Platform can set PlatformTarget to a value if it chooses to.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <WarningsAsErrors>NU1605;CS0114</WarningsAsErrors>
    <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>

In this snippet, when Platform is AnyCPU, PlatformTarget is set to x86.

You can program in the proj file and insert a task that sets PlatformTarget to your liking.

Next, before calling compiler, Microsoft default targets (C:\Program Files (x86)\dotnet\sdk\3.1.426\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.props) may set PlatformTarget in certain conditions and when PlatformTarget itself is empty.

<PropertyGroup Condition=" '$(_PlatformWithoutConfigurationInference)' == 'x64' ">
	<PlatformTarget Condition=" '$(PlatformTarget)' == '' ">x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(_PlatformWithoutConfigurationInference)' == 'x86' ">
	<PlatformTarget Condition=" '$(PlatformTarget)' == '' ">x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(_PlatformWithoutConfigurationInference)' == 'ARM' ">
	<PlatformTarget Condition=" '$(PlatformTarget)' == '' ">ARM</PlatformTarget>
</PropertyGroup>

Non-emptiness of PlatformTarget?

In spite of the assignments, PlatformTarget is not guaranteed to be non-empty. To verify, add a PostBuildEvent and print the value.

<Target Name="Output" AfterTargets="PostBuildEvent">
	<Message Text="PlatformTarget = '$(PlatformTarget)'" />
</Target>

MSBuild prints PlatformTarget = ” on my Windows 10.

Is and how is PlatformTarget passed to the compiler? We have to dive into C:\Program Files\dotnet\sdk\3.1.426\Roslyn\Microsoft.CSharp.Core.targets. In the CoreCompile target, Csc task is called and Csc.Platform receives the value of PlatformTarget.

Is the Csc task compatible with an empty string of PlatformTarget? Yes. The Csc task class inherits the ManagedCompiler class, and latter defines a nullable property Platform.

Also, I notice ManagedCompiler.PlatformWith32BitPreference sets the property Platform to “anycpu32bitpreferred” if it is null or empty.

Conclusion

So far, I discovered the trace of the MSBuild property PlatformTarget and conclude that its value can remain empty throughout the compilation steps. When the value is empty, the compiler itself internally determines the architecture of the binary.

If I have a package or something that depends on the architecture of the output, I’m not able to use PlatformTarget to conditionally import a package in a smart way. That means, I must force users to specify an architecture, or I hard-code it in my csproj file.

参考资料

  1. Ben Villalobos. Platform vs. PlatformTarget In Any .NET Build. . 2021-09-22 [2024-01-24].