.NET 多目标与 .NET Standard 和可移植库 MSBuild 15

.NET Multi-Target with .NET Standard and Portable Library MSBuild 15

移植到 .NET 标准版本,您的源代码可能与可移植库相同,但支持的平台可能不同。

例如 .NET standard 1.6 可能是您的 api 可从便携式 Profile47 获得的最低版本。 Profile47支持.net 4.5或更高版本,nut.NET Standard 1.6仅支持4.6.1及更高版本!

使用新的msbuild 15csproj/fsproj(还有VS2017)是否可以编译同时使用 Portable Library.Net Standard 以使转换更容易?

,但它不像交叉编译 .netstandard.net45.net40 那样明显,因为它们不是简单的名字您预定义的可移植库。

在新的 sdk 中 Microsoft.NET.TargetFrameworkInference.targets 它说:

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>

TargetFrameworkProfile 你从旧的 csproj/fsproj 得到的。那是您的便携式图书馆的配置文件标识符。您也可以从 Nuget Target Frameworks 中查找。

TargetFrameworkIdentifier 很简单,就是 .NETPortable

TargetFrameworkProfile 大概也可以从你的老csproj/fsprog得到。但您也可以检查 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\ 并检查 v4.0v4.5v4.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# 目前需要 Mac 或 Visual Studio 2017 预览版 15.3 的 Mono Beta 版本用于此 fsproj。 examples 的更改还包括对 FSharp.Compiler.Tools 的 PackageReference 和 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>

之前的答案是准确的,但实际上还不够。您需要引用可移植语言目标以获得正确的行为。也可能有其他 SDK 参考,您可能需要隐式定义 ifdefs,例如 PROFILE328

我写了一个 NuGet 包,您可以在此处 "does the right thing" 添加到您的项目:

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>