问题描述
我想创建一个 NuGet 包,它可以同时明确地针对 .NET Framework 4.6.2 和 .Net Standard 1.5.这是来自 VS 2017 的缩写 .csproj 文件:
<Project Sdk="Microsoft.NET.Sdk"><属性组><TargetFrameworks>net462;netstandard1.5</TargetFrameworks>...</属性组></项目>
当我从本地 Windows 计算机执行 dotnet build 和 pack 命令时,NuGet 包的创建完全符合预期.
但是,当我尝试在 Linux 上执行相同的 dotnet 命令时,我收到以下错误:
<块引用>/opt/dotnet/sdk/1.0.4/Microsoft.Common.CurrentVersion.targets(1111,5):错误 MSB3644:框架的参考程序集未找到.NETFramework,Version=v4.6.2".为了解决这个问题,为此框架版本安装 SDK 或 Targeting Pack,或将您的应用程序重新定位到您所针对的框架版本已安装 SDK 或 Targeting Pack.请注意,程序集将从全局程序集缓存 (GAC) 中解析,并将用于参考组件的位置.因此您的程序集可能不是正确定位到您想要的框架.
然后我突然意识到 Linux 机器上没有任何常规的 .NET Framework 程序集(更不用说.因此,我似乎无法使用 Linux 来构建我的 NuGet 包.我四处搜索用于Targeting Pack",但它仅适用于 Windows.
冒着听起来幼稚的风险,是否有人在 Linux 上成功构建了可以针对 .NET Framework 的 NuGet 包?
.NET CLI 的分发不包含任何 .NET Framework 的参考程序集,因此其版本的 MSBuild 无法解析所需的编译时资产.这种情况是 在 GitHub 上跟踪的,并且在迁移到 MSBuild 之前已经工作(CLI 可以使用 mono 的参考程序集).
虽然有一些替代方案可用于在非 Windows 机器上构建库:
1.使用 mono 5+ 构建库.
这可能是最稳定的路径了.
Mono 5 及更高版本包含构建 .NET Standard 和 .NET Core 应用程序所需的构建逻辑.在 linux 上,mono 的 msbuild 可能需要作为单独的包安装.所以代替下面常用的命令
dotnet 恢复点网构建dotnet 发布 -c 发布
您可以使用 mono 的 msbuild 来执行以下操作:
msbuild/t:Restore构建msbuild/t:Publish/p:Configuration=Release
为单声道 < 打包解决方法5.2:
唯一的限制是单声道(<5.2)不能开箱即用地生成 NuGet 包,但是有一个 解决方法涉及在项目中使用 NuGet.Build.Tasks.Pack
NuGet 包,它允许您执行 msbuild/t:Pack/p:Configuration=Release
通过像这样修改项目文件(特别注意 <Project>
元素上删除的 Sdk="..."
属性):
<项目><属性组><NuGetBuildTasksPackTargets>垃圾值避免冲突</NuGetBuildTasksPackTargets></属性组><导入项目="Sdk.props" Sdk="Microsoft.NET.Sdk"/><!-- 您项目的所有其他内容都在这里 --><项目组><PackageReference Include="NuGet.Build.Tasks.Pack" Version="4.0.0" PrivateAssets="All"/></项目组><导入项目="Sdk.targets" Sdk="Microsoft.NET.Sdk"/></项目>
<强>2.使用 .NET CLI 并告诉 MSBuild 使用 mono 的参考程序集.
为 net*
目标框架构建时,您可以将 FrameworkPathOverride
属性设置为环境变量或 csproj 文件中的属性.它需要指向一组参考程序集——这里可以使用mono的参考程序集.但有些包含一个特殊文件(redist 列表),其中包含对 .NET CLI 中的 MSBuild 版本无法遵循的其他目录的引用.但它确实适用于很多场景:
export FrameworkPathOverride=/usr/lib/mono/4.5/dotnet 构建 -f net45
这是使用和 由 F# 团队记录.
3.使用包含引用程序集的 NuGet 包.
在某些 MyGet 源中,Microsoft 发布了包含参考程序集的 NuGet 包.虽然它们没有发布或官方",但这个过程可能会在某个时间点失败.但是,他们确实计划调查使这条路径正式化.
首先在您的解决方案目录中创建一个 NuGet.Config 文件,其中包含以下内容以添加提要:
<?xml version="1.0" encoding="utf-8"?><配置><包源><add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json"/></packageSources></配置>
然后您可以添加一个项目组以将 PackageReference
添加到目标包和一个 PropertyGroup
以设置引用程序集的路径,如下所示:
<Project Sdk="Microsoft.NET.Sdk"><属性组><OutputType>Exe</OutputType><TargetFrameworks>netcoreapp1.1;net461</TargetFrameworks></属性组><PropertyGroup 条件="'$(TargetFramework)' =='net461'"><RuntimeIdentifier>win7-x64</RuntimeIdentifier><FrameworkPathOverride>$(NuGetPackageFolders)microsoft.targetingpack.netframework.v4.6.11.0.1lib
et461</FrameworkPathOverride></属性组><ItemGroup 条件="'$(TargetFramework)' == 'net461' "><PackageReference Include="Microsoft.TargetingPack.NETFramework.v4.6.1" Version="1.0.1" ExcludeAssets="All" PrivateAssets="All"/></项目组></项目>
如果您使用本机资产(例如获取 linux 的 .so
文件),您可以针对不同平台更改 RuntimeIdentifier
或在构建库时将其完全删除.p>
I want to create a NuGet package that can simultaneously and explicitly target both .NET Framework 4.6.2 and .Net Standard 1.5. Here's an abbreviated .csproj file from VS 2017:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net462;netstandard1.5</TargetFrameworks>
...
</PropertyGroup>
</Project>
When I execute the dotnet build and pack commands from my local Windows machine, the NuGet package is created perfectly well as expected.
However, when I attempt to execute the same dotnet commands on Linux, I receive the following error:
/opt/dotnet/sdk/1.0.4/Microsoft.Common.CurrentVersion.targets(1111,5): error MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.6.2" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.
It then dawned on me that there aren't any regular .NET Framework assemblies on the Linux box (let alone . Thus, it appears that I won't be able to use Linux to build my NuGet package. I searched around for a "Targeting Pack", but it's only available for Windows.
At the risk of sounding nave, is anyone successfully building NuGet packages on Linux that can target .NET Framework?
The distribution of the .NET CLI doesn't contain any reference assemblies for .NET Framework so its version of MSBuild cannot resolve the needed compile-time assets. This scenario is tracked on GitHub though and has worked before the migration to MSBuild (the CLI could use mono's reference assemblies).
There are a few alternatives though that can be used to build your library on non-windows machines:
1. Use mono 5+ to build the library.
This is probably the most stable path.
Mono 5 and higher contains the needed build logic to build .NET Standar and .NET Core applications. On linux, mono's msbuild may need to be installed as a separate package. So instead of the following commonly used commands
dotnet restore
dotnet build
dotnet publish -c Release
you would use mono's msbuild to do the following:
msbuild /t:Restore
msbuild
msbuild /t:Publish /p:Configuration=Release
Pack workaround for mono < 5.2:
The only limitation is that mono (< 5.2) cannot produce NuGet packages out of the box but there is a workaround involving using the NuGet.Build.Tasks.Pack
NuGet package in the project which allows you to do msbuild /t:Pack /p:Configuration=Release
by modifying the project file like this (especially note the removed Sdk="..."
attribute on the <Project>
element):
<Project>
<PropertyGroup>
<NuGetBuildTasksPackTargets>junk-value-to-avoid-conflicts</NuGetBuildTasksPackTargets>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<!-- All your project's other content here -->
<ItemGroup>
<PackageReference Include="NuGet.Build.Tasks.Pack" Version="4.0.0" PrivateAssets="All" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>
2. Use the .NET CLI and tell MSBuild to use mono's reference assemblies.
When building for net*
target frameworks, you can set the FrameworkPathOverride
property both as an environment variable or as a property in the csproj file. It needs to point to a set of reference assemblies - mono's reference assemblies can be used here. But some contain a special file (redist list) containing references to other directories which the MSBuild version in the .NET CLI cannot follow. It does work in a lot of scenarios though:
export FrameworkPathOverride=/usr/lib/mono/4.5/
dotnet build -f net45
This was used and documented by the F# team.
3. Use a NuGet package containing reference assemblies.
On some MyGet feeds, Microsoft publishes NuGet packages containing reference assemblies. They are not published or "official" though so this process may fail at some point in time. However they do plan to investigate making this path official.
First create a NuGet.Config file in your solution's directory with to following contents to add the feed:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
</packageSources>
</configuration>
Then you can add an item group to add the PackageReference
to a targeting pack and a PropertyGroup
to set the path to the reference assemblies like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp1.1;net461</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net461' ">
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
<FrameworkPathOverride>$(NuGetPackageFolders)microsoft.targetingpack.netframework.v4.6.11.0.1lib
et461</FrameworkPathOverride>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<PackageReference Include="Microsoft.TargetingPack.NETFramework.v4.6.1" Version="1.0.1" ExcludeAssets="All" PrivateAssets="All" />
</ItemGroup>
</Project>
You can change the RuntimeIdentifier
for different platforms if you use native assets (e.g. to get .so
files for linux) or remove it entirely when building libraries.
这篇关于在 Linux 上构建面向 .NET Framework 的 NuGet 包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!