<!--
***********************************************************************************************
Microsoft.NET.TargetFrameworkInference.targets

WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
          created a backup copy.  Incorrect changes to this file will make it
          impossible to load or build your projects from the command-line or the IDE.

Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!--
    Note that this file is only included when $(TargetFramework) is set and so we do not need to check that here.

    Common targets require that $(TargetFrameworkIdentifier) and $(TargetFrameworkVersion) are set by static evaluation
    before they are imported. In common cases (currently netstandard, netcoreapp, or net), we infer them from the short
    names given via TargetFramework to allow for terseness and lack of duplication in project files.

    For other cases, the user must supply them manually.

    For cases where inference is supported, the user need only specify the targets in TargetFrameworks, e.g:
      <PropertyGroup>
        <TargetFrameworks>net45;netstandard1.0</TargetFrameworks>
      </PropertyGroup>

    For cases where inference is not supported, identifier, version and profile can be specified explicitly as follows:
       <PropertyGroup>
         <TargetFrameworks>portable-net451+win81;xyz1.0</TargetFrameworks>
       <PropertyGroup>
       <PropertyGroup Condition="'$(TargetFramework)' == 'portable-net451+win81'">
         <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
         <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
         <TargetFrameworkProfile>Profile44</TargetFrameworkProfile>
       </PropertyGroup>
       <PropertyGroup Condition="'$(TargetFramework)' == 'xyz1.0'">
         <TargetFrameworkIdentifier>Xyz</TargetFrameworkVersion>
       <PropertyGroup>

    Note in the xyz1.0 case, which is meant to demonstrate a framework we don't yet recognize, we can still
    infer the version of 1.0. The user can also override it as always we honor a TargetFrameworkIdentifier
    or TargetFrameworkVersion that is already set.
   -->

  <!-- Hook for importing custom target framework parsing -->
  <Import Project="$(BeforeTargetFrameworkInferenceTargets)" Condition="$(BeforeTargetFrameworkInferenceTargets) != ''" />

  <!--
    Parse TargetFramework properties.
  -->
  <PropertyGroup Condition="'$(TargetFramework)' != '' and ('$(TargetFrameworkIdentifier)' == '' or '$(TargetFrameworkVersion)' == '')">

    <TargetFrameworkIdentifier>$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)', 2))</TargetFrameworkVersion>
  </PropertyGroup>
  
  <PropertyGroup>
    <_TargetFrameworkVersionWithoutV>$(TargetFrameworkVersion.TrimStart('vV'))</_TargetFrameworkVersionWithoutV>
  </PropertyGroup>

  <!--
    Parse TargetPlatform properties.
  -->
  <PropertyGroup Condition="'$(TargetFramework)' != '' and ('$(TargetPlatformIdentifier)' == '' or '$(TargetPlatformVersion)' == '')">
    <TargetPlatformIdentifier Condition="'$(TargetPlatformIdentifier)' == ''">$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
    <TargetPlatformVersion Condition="'$(TargetPlatformIdentifier)' == 'Windows'" >$([MSBuild]::GetTargetPlatformVersion('$(TargetFramework)', 4))</TargetPlatformVersion>
    <TargetPlatformVersion Condition="'$(TargetPlatformVersion)' == '' or ('$(TargetPlatformIdentifier)' == 'Windows' and !$([MSBuild]::VersionGreaterThanOrEquals($(TargetPlatformVersion), 10.0)))" >$([MSBuild]::GetTargetPlatformVersion('$(TargetFramework)', 2))</TargetPlatformVersion>
    <TargetPlatformVersion Condition="$([MSBuild]::VersionEquals($(TargetPlatformVersion), 0.0))" ></TargetPlatformVersion>
    <!-- Normalize casing of windows to Windows -->
    <TargetPlatformIdentifier Condition="'$(TargetPlatformIdentifier)' == 'Windows'">Windows</TargetPlatformIdentifier>
  </PropertyGroup>

  <!--
    Trigger an error if we're unable to infer the framework identifier and version.

    We have to evaluate this here and not in the target because by the time the target runs,
    Microsoft.Common.targets will have defaulted to .NETFramework,Version=v4.0
  -->
  <PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == '' or '$(TargetFrameworkIdentifier)' == 'Unsupported' or '$(TargetFrameworkVersion)' == ''">
    <_UnsupportedTargetFrameworkError>true</_UnsupportedTargetFrameworkError>
  </PropertyGroup>

  <!--
    NOTE: We must not validate the TFM before restore target runs as it prevents adding additional TFM
          support from being provided by a nuget package such as MSBuild.Sdk.Extras.

          We run before RunResolvePackageDependencies and GetReferenceAssemblyPaths so that design-time builds
          which do not currently invoke _CheckForInvalidConfigurationAndPlatform, will not trigger spurious
          errors that are only consequences of the root cause identified here.
  -->
  <Target Name="_CheckForUnsupportedTargetFramework"
          BeforeTargets="_CheckForInvalidConfigurationAndPlatform;RunResolvePackageDependencies;GetFrameworkPaths;GetReferenceAssemblyPaths;Restore"
          Condition="'$(_UnsupportedTargetFrameworkError)' == 'true'"
          >
    <NETSdkError Condition="!$(TargetFramework.Contains(';'))"
                 ResourceName="CannotInferTargetFrameworkIdentifierAndVersion"
                 FormatArguments="$([MSBuild]::Escape('$(TargetFramework)'))" />

    <NETSdkError Condition="$(TargetFramework.Contains(';'))"
                 ResourceName="TargetFrameworkWithSemicolon"
                 FormatArguments="$([MSBuild]::Escape('$(TargetFramework)'))" />
  </Target>

  <!-- Skip this target for design time builds when there are missing workload packs.
       This will prevent design time builds from failing and therefore allow
       Visual Studio to collect the workloads from the GetSuggestedWorkloads target -->
  <Target Name="_CheckForUnsupportedTargetPlatformIdentifier"
          BeforeTargets="_CheckForInvalidConfigurationAndPlatform;RunResolvePackageDependencies;GetFrameworkPaths;GetReferenceAssemblyPaths;CollectPackageReferences"
          Condition="'$(TargetPlatformIdentifier)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) And ('$(DesignTimeBuild)' != 'true' Or '@(MissingWorkloadPack)' == '')" >

    <PropertyGroup>
      <TargetPlatformSupported Condition="'$(TargetPlatformIdentifier)' == 'Windows'">true</TargetPlatformSupported>
      <UseWorkloadsSpecificError Condition="($(TargetPlatformIdentifier) == 'ios' or $(TargetPlatformIdentifier) == 'tvos' or $(TargetPlatformIdentifier) == 'maccatalyst' or $(TargetPlatformIdentifier) == 'android' or $(TargetPlatformIdentifier.StartsWith('browser'))) and '$(MSBuildEnableWorkloadResolver)' != 'true'">true</UseWorkloadsSpecificError>
    </PropertyGroup>

    <NETSdkError Condition="'$(TargetPlatformSupported)' != 'true' and '$(UseWorkloadsSpecificError)' != 'true'"
                 ResourceName="UnsupportedTargetPlatformIdentifier"
                 FormatArguments="$(TargetPlatformIdentifier)" />

    <NETSdkError Condition="'$(TargetPlatformSupported)' != 'true' and '$(UseWorkloadsSpecificError)' == 'true'"
                 ResourceName="UnsupportedTargetPlatformIdentifierWithWorkloadsDisabled"
                 FormatArguments="$(TargetPlatformIdentifier)" />
  </Target>

  <UsingTask TaskName="AllowEmptyTelemetry" AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" />

  <Target Name="_CollectTargetFrameworkForTelemetry" AfterTargets="_CheckForUnsupportedTargetFramework">
    <ItemGroup>
      <TFTelemetry Include="TargetFrameworkVersion" Value="$([MSBuild]::Escape('$(TargetFrameworkMoniker)'))" />
      <TFTelemetry Include="RuntimeIdentifier" Value="$(RuntimeIdentifier)" />
      <TFTelemetry Include="SelfContained" Value="$(SelfContained)" />
      <TFTelemetry Include="UseApphost" Value="$(UseApphost)" />
      <TFTelemetry Include="OutputType" Value="$(OutputType)" />
      <TFTelemetry Include="UseArtifactsOutput" Value="$(UseArtifactsOutput)" />
      <TFTelemetry Include="ArtifactsPathLocationType" Value="$(_ArtifactsPathLocationType)" />
    </ItemGroup>
    <AllowEmptyTelemetry EventName="targetframeworkeval" EventData="@(TFTelemetry)" />
  </Target>

  <!--
    Don't leave TargetFrameworkVersion empty if it still hasn't been determined. We will trigger the error above,
    but we need this to be a valid version so that our error message does not get pre-empted by failure to interpret
    version comparison expressions, which is currently unrecoverable in VS.

    Also don't leave TargetFrameworkIdentifier unset as it will be defaulted to .NETFramework by common targets, which
    can cause restore (which we cannot block, see above) to silently succeed for empty TargetFramework.
  -->
  <PropertyGroup Condition="'$(TargetFrameworkVersion)' == ''">
    <TargetFrameworkVersion >v0.0</TargetFrameworkVersion>
  </PropertyGroup>
  <PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == ''">
    <TargetFrameworkIdentifier>_</TargetFrameworkIdentifier>
  </PropertyGroup>

  <!--
    Trigger an error if targeting a higher version of .NET Core than is supported by the current SDK.
  -->
  <Target Name="_CheckForUnsupportedNETCoreVersion" BeforeTargets="_CheckForInvalidConfigurationAndPlatform;Restore;CollectPackageReferences"
          Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(NETCoreAppMaximumVersion)' != ''">

    <PropertyGroup>
      <DisplayVSMessage Condition="$([MSBuild]::VersionLessThan($(MSBuildVersion), '$(MinimumVisualStudioVersionForUnsupportedTargetFrameworkVersion)')) and '$(BuildingInsideVisualStudio)' == 'true' and '$(_TargetFrameworkVersionWithoutV)' == '$(UnsupportedTargetFrameworkVersion)' and '$([MSBuild]::IsOSPlatform(`Windows`))' == 'true'">true</DisplayVSMessage>
    </PropertyGroup>

    <NETSdkError Condition="'$(_TargetFrameworkVersionWithoutV)' > '$(NETCoreAppMaximumVersion)' and '$(DisplayVSMessage)' != 'true'"
                 ResourceName="UnsupportedTargetFrameworkVersion"
                 FormatArguments=".NET;$(_TargetFrameworkVersionWithoutV);$(NETCoreAppMaximumVersion)"
      />

    <NETSdkError Condition="'$(DisplayVSMessage)' == 'true'"
                 ResourceName="UnsupportedVisualStudioVersion"
                 FormatArguments=".NET;$(_TargetFrameworkVersionWithoutV);$(NETCoreAppMaximumVersion);$(MinimumVisualStudioVersionForUnsupportedTargetFrameworkVersion)"
      />
  </Target>

  <!--
    Trigger a warning if targeting a lower version of .NET Standard than is recommended
  -->
  <Target Name="_CheckForNotRecommendedNETStandardVersion" BeforeTargets="_CheckForInvalidConfigurationAndPlatform;Restore;CollectPackageReferences"
          Condition="'$(TargetFrameworkIdentifier)' == '.NETStandard' and $([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '2.0'))">
    <PropertyGroup>
      <!-- Default the check to true, but allow developers to turn the warning off. -->
      <CheckNotRecommendedTargetFramework Condition="'$(CheckNotRecommendedTargetFramework)' == ''" >true</CheckNotRecommendedTargetFramework>
    </PropertyGroup>

    <NETSdkWarning Condition="'$(CheckNotRecommendedTargetFramework)' == 'true'"
          ResourceName="TargetFrameworkIsNotRecommended"
          FormatArguments="https://aka.ms/dotnet/dotnet-standard-guidance" />
  </Target>

  <!--
    Trigger an error if C++ project targeting a lower version of .NET Core than 3.1.
  -->
  <Target Name="_CheckForUnsupportedCppNETCoreVersion" BeforeTargets="_CheckForInvalidConfigurationAndPlatform;Restore;CollectPackageReferences">
    <NETSdkError Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and '$(_TargetFrameworkVersionWithoutV)' &lt; '3.1' and ('$(Language)' == 'C++' and '$(_EnablePackageReferencesInVCProjects)' != 'true')"
                 ResourceName="CppRequiresTFMVersion31"
      />
  </Target>

  <!--C++/CLI has its own logic of determine TargetPlatformIdentifier and TargetPlatformVersion-->
  <PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) and ('$(Language)' != 'C++' or '$(_EnablePackageReferencesInVCProjects)' == 'true')">
    <_EnableDefaultWindowsPlatform>false</_EnableDefaultWindowsPlatform>
    <UseOSWinMdReferences>false</UseOSWinMdReferences>
  </PropertyGroup>

  <PropertyGroup  Condition="'$(TargetFrameworkIdentifier)' == '.NETStandard' And '$(NETStandardMaximumVersion)' == ''">
    <NETStandardMaximumVersion>2.1</NETStandardMaximumVersion>
  </PropertyGroup>

  <Target Name="_CheckForUnsupportedNETStandardVersion" BeforeTargets="_CheckForInvalidConfigurationAndPlatform;Restore;CollectPackageReferences"
          Condition="'$(TargetFrameworkIdentifier)' == '.NETStandard' And '$(NETStandardMaximumVersion)' != ''">

    <NETSdkError Condition="'$(_TargetFrameworkVersionWithoutV)' > '$(NETStandardMaximumVersion)'"
                 ResourceName="UnsupportedTargetFrameworkVersion"
                 FormatArguments=".NET Standard;$(_TargetFrameworkVersionWithoutV);$(NETStandardMaximumVersion)"
      />
  </Target>

  <Target Name="_CheckForUnsupportedTargetFrameworkAndFeatureCombination" BeforeTargets="_CheckForInvalidConfigurationAndPlatform;Restore;CollectPackageReferences"
        Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">

    <NETSdkError Condition="'$(UsingNETSdkDefaults)' != 'true'"
                 ResourceName="NETFrameworkWithoutUsingNETSdkDefaults" />
  </Target>

  <Target Name="_CheckForSupportedOSPlatformVersionHigherThanTargetPlatformVersion" BeforeTargets="_CheckForInvalidConfigurationAndPlatform"
          Condition="'$(TargetPlatformVersion)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0))">

    <NETSdkError Condition="'$(SupportedOSPlatformVersion)' != '' and $(TargetPlatformVersion) != '' and $([MSBuild]::VersionGreaterThan($(SupportedOSPlatformVersion), $(TargetPlatformVersion)))"
                 ResourceName="CannotHaveSupportedOSPlatformVersionHigherThanTargetPlatformVersion"
                 FormatArguments="$(SupportedOSPlatformVersion);$(TargetPlatformVersion)"/>
  </Target>

  <!--C++/CLI targets rely on the patch version of the Windows SDK version as TargetPlatformVersion. Skip the normalization.-->
  <Target Name="_NormalizeTargetPlatformVersion"
    BeforeTargets="ProcessFrameworkReferences"
    Condition="'$(TargetPlatformVersion)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) and ('$(Language)' != 'C++' or '$(_EnablePackageReferencesInVCProjects)' == 'true')">
    <ItemGroup>
      <_ApplicableTargetPlatformVersion Include="@(SdkSupportedTargetPlatformVersion)" Condition="'@(SdkSupportedTargetPlatformVersion)' != '' and '%(SdkSupportedTargetPlatformVersion.DefineConstantsOnly)' != 'true'" RemoveMetadata="DefineConstantsOnly" />
      <_ValidTargetPlatformVersion Include="@(_ApplicableTargetPlatformVersion)" Condition="'@(_ApplicableTargetPlatformVersion)' != '' and $([MSBuild]::VersionEquals(%(Identity), $(TargetPlatformVersion)))" />
    </ItemGroup>

    <PropertyGroup>
      <TargetPlatformVersion Condition="'@(_ValidTargetPlatformVersion)' != '' and '@(_ValidTargetPlatformVersion->Distinct()->Count())' == '1' and '@(_ValidTargetPlatformVersion)' != '$(TargetPlatformVersion)'">@(_ValidTargetPlatformVersion->Distinct())</TargetPlatformVersion>
    </PropertyGroup>
  </Target>

  <Target Name="_CheckForInvalidTargetPlatformVersion"
      BeforeTargets="_CheckForInvalidConfigurationAndPlatform"
      DependsOnTargets="_NormalizeTargetPlatformVersion"
      Condition="'$(TargetPlatformVersion)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) and ('$(Language)' != 'C++' or '$(_EnablePackageReferencesInVCProjects)' == 'true')">
    <PropertyGroup>
      <TargetPlatformVersionSupported Condition="'$(TargetPlatformVersionSupported)' == '' and '@(_ValidTargetPlatformVersion)' != ''" >true</TargetPlatformVersionSupported>
      <_ValidTargetPlatformVersions Condition="'@(_ApplicableTargetPlatformVersion)' != ''" >@(_ApplicableTargetPlatformVersion, '%0a')</_ValidTargetPlatformVersions>
      <_ValidTargetPlatformVersions Condition="'@(_ApplicableTargetPlatformVersion)' == ''" >None</_ValidTargetPlatformVersions>
    </PropertyGroup>

    <NetSdkError Condition="'$(TargetPlatformVersionSupported)' != 'true'"
                 ResourceName="InvalidTargetPlatformVersion"
                 FormatArguments="$(TargetPlatformVersion);$(TargetPlatformIdentifier);$(_ValidTargetPlatformVersions)" />
  </Target>

  <!-- Hook for processing after target framework parsing (for example to customize output paths) -->
  <Import Project="$(AfterTargetFrameworkInferenceTargets)" Condition="$(AfterTargetFrameworkInferenceTargets) != ''" />

  <PropertyGroup>
    <ProduceReferenceAssembly Condition="'$(ProduceReferenceAssembly)' == '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) and ('$(ProduceOnlyReferenceAssembly)' != 'true') and '$(MSBuildProjectExtension)' != '.fsproj'" >true</ProduceReferenceAssembly>
    <ProduceReferenceAssembly Condition="'$(ProduceReferenceAssembly)' == '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 7.0)) and ('$(ProduceOnlyReferenceAssembly)' != 'true') and '$(MSBuildProjectExtension)' == '.fsproj'" >true</ProduceReferenceAssembly>
  </PropertyGroup>

</Project>
