.NET Multi-Target с.NET Standard и переносимой библиотекой MSBuild 15

Портируя на стандартную версию.NET, вы можете быть источником, идентичным переносимой библиотеке, но поддерживаемые платформы могут и не быть.

Например .NET standard 1.6 может быть самая низкая версия, которая имеет ваш API доступен с портативного Profile47, Profile47 поддерживает .net 4.5 или новее, гайка .NET Standard 1.6 поддерживает только 4.6.1 и более поздние версии!

С новым многоцелевым таргетингом с новым msbuild 15 csproj / fsproj (также VS2017) можно ли одновременно скомпилировать и Portable Library, и .Net Standard, чтобы упростить переход?

2 ответа

Решение

Предыдущий ответ точен, но на самом деле этого недостаточно. Чтобы получить правильное поведение, вам нужно сослаться на цели переносимого языка. Также могут быть другие ссылки на SDK, и вы, вероятно, захотите неявно определить ifdefs лайк PROFILE328,

Я написал пакет NuGet, который вы можете добавить в свой проект, который "делает все правильно" здесь:

https://github.com/onovotny/MSBuildSdkExtras

Редактировать: csproj будет выглядеть так:

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

  <PropertyGroup>
    <TargetFrameworks>netstandard1.6;portable-net45+sl5+win8</TargetFrameworks>
    <Description>YOUR DESCRIPTION</Description>
    <Company>YOUR COMPANY</Company>
    <Authors> YOUR AUTHORS </Authors>
    <Copyright>YOUR COPYRIGHT</Copyright>
    <AssemblyVersion>YOUR VERSION</AssemblyVersion>
    <FileVersion>YOUR VERSION</FileVersion>
    <PackageProjectUrl>YOUR PROJECT URL</PackageProjectUrl>
    <PackageLicenseUrl>YOUR LICENSE</PackageLicenseUrl>
    <PackageTags>YOUR TAGS</PackageTags>
    <IncludeSymbols>True</IncludeSymbols>
    <IncludeSource>True</IncludeSource>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
    <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
    <Version>YOUR NUGET VERSION</Version>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="MSBuild.Sdk.Extras" Version="1.0.5" PrivateAssets="all" />
  </ItemGroup>

  <Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
</Project>

Да, но это не так очевидно, как кросс-компиляция .netstandard с .net45 или же .net40 как непростые названия для ваших портативных библиотек.

В новом sdk Microsoft.NET.TargetFrameworkInference.targets говорится:

Для случаев, когда логический вывод не поддерживается, идентификатор, версия и профиль могут быть явно указаны следующим образом:

   <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>

TargetFrameworkProfile Вы получаете это от своего старого csproj/fsproj. Это идентификатор профиля вашей переносимой библиотеки. Вы также можете найти его в Nuget Target Frameworks.

TargetFrameworkIdentifier прост, это .NETPortable

TargetFrameworkProfile Возможно также может получить от вашего старого csproj/fsprog. Но вы также можете проверить C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\ и проверить v4.0, v4.5, а также v4.6 Каталоги профиля и найти свой профиль. Список этих каталогов выглядит следующим образом:

v4.0

Profile1/    Profile143/  Profile2/    Profile3/    Profile4/   Profile6/
Profile102/  Profile147/  Profile225/  Profile328/  Profile41/  Profile88/
Profile104/  Profile154/  Profile23/   Profile336/  Profile42/  Profile92/
Profile131/  Profile158/  Profile24/   Profile344/  Profile46/  Profile95/
Profile136/  Profile18/   Profile240/  Profile36/   Profile47/  Profile96/
Profile14/   Profile19/   Profile255/  Profile37/   Profile5/

v4.5

Profile111/  Profile259/  Profile49/  Profile7/  Profile75/  Profile78/

v4.6

Profile151/  Profile157/  Profile31/  Profile32/  Profile44/  Profile84/

Подходит ли название, которое вы выбираете для своих переносных целей? Да и нет, это важно для автоматической упаковки в nuget, поэтому лучше использовать значение из Nuget Target Frameworks с одним предупреждением. Я не уверен, что это из-за новейшей версии nuget, но кажется, что TargetFrameworkVersion нужно добавить в portable в прозвище. Таким образом, для Profile47, который v4.0должно быть на самом деле portable40-net45+sl5+win8

Еще один элемент для добавления определения компилятора, который может оказаться полезным с помощью DefineConstants. Вы можете сделать все, что захотите, это исторически PROFILEXXX в заглавных буквах, просто добавьте его в условную группу.

<DefineConstants>$(DefineConstants);PROFILE47</DefineConstants>

Последнее, что следует отметить, ссылки по умолчанию не включены, поэтому вам придется добавить свой собственный.

<ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8'">
  <Reference Include="System" />
  <Reference Include="System.Core" />
  <Reference Include="System.Windows" />
</ItemGroup>

Пример CSharp

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

  <PropertyGroup>
    <TargetFrameworks>netstandard1.6;portable40-net45+sl5+win8</TargetFrameworks>
    <Description>YOUR DESCRIPTION</Description>
    <Company>YOUR COMPANY</Company>
    <Authors> YOUR AUTHORS </Authors>
    <Copyright>YOUR COPYRIGHT</Copyright>
    <AssemblyVersion>YOUR VERSION</AssemblyVersion>
    <FileVersion>YOUR VERSION</FileVersion>
    <PackageProjectUrl>YOUR PROJECT URL</PackageProjectUrl>
    <PackageLicenseUrl>YOUR LICENSE</PackageLicenseUrl>
    <PackageTags>YOUR TAGS</PackageTags>
    <IncludeSymbols>True</IncludeSymbols>
    <IncludeSource>True</IncludeSource>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
    <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
    <Version>YOUR NUGET VERSION</Version>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8'">
     <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
     <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
     <TargetFrameworkProfile>Profile47</TargetFrameworkProfile>
     <DefineConstants>$(DefineConstants);PROFILE47</DefineConstants>
   </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8'">
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Windows" />
  </ItemGroup>

</Project>

Пример F#

* Предостережение: F# требует бета-версию Mono для Mac или Visual Studio 2017 Preview 15.3 в настоящее время для этого fsproj. Также изменение от примеров включает PackageReference к FSharp.Compiler.Tools а также FSharp.Core 4.1 последние портативные поддерживаемые версии FSharp (что относительно недавно.)

<Project Sdk="FSharp.NET.Sdk;Microsoft.NET.Sdk" ToolsVersion="15.0">

  <PropertyGroup>
    <TargetFrameworks>netstandard1.6;portable40-net45+sl5+win8</TargetFrameworks>
    <Description>YOUR DESCRIPTION</Description>
    <Company>YOUR COMPANY</Company>
    <Authors> YOUR AUTHORS </Authors>
    <Copyright>YOUR COPYRIGHT</Copyright>
    <AssemblyVersion>YOUR VERSION</AssemblyVersion>
    <FileVersion>YOUR VERSION</FileVersion>
    <PackageProjectUrl>YOUR PROJECT URL</PackageProjectUrl>
    <PackageLicenseUrl>YOUR LICENSE</PackageLicenseUrl>
    <PackageTags>YOUR TAGS</PackageTags>
    <IncludeSymbols>True</IncludeSymbols>
    <IncludeSource>True</IncludeSource>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
    <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
    <Version>YOUR NUGET VERSION</Version>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8'">
     <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
     <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
     <TargetFrameworkProfile>Profile47</TargetFrameworkProfile>
     <DefineConstants>$(DefineConstants);PROFILE47</DefineConstants>
   </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8'">
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Windows" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="FSharp.Core" Version="4.1.*" />
    <PackageReference Include="FSharp.Compiler.Tools" Version="4.1.*" PrivateAssets="All" 
    />
    <PackageReference Include="FSharp.NET.Sdk" Version="1.0.*" PrivateAssets="All" 
    />
  </ItemGroup>

  <ItemGroup>
    <Compile Include="YourModule1.fs" />
    <Compile Include="YourModule2.fs" />
  </ItemGroup>

</Project>
Другие вопросы по тегам