.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.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# 目前需要 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>
移植到 .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.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# 目前需要 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>