在面向 .NET Framework 的 Linux 上构建 NuGet 包 [英] Build NuGet package on Linux that targets .NET Framework

查看:58
本文介绍了在面向 .NET Framework 的 Linux 上构建 NuGet 包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个 NuGet 包,它可以同时明确地针对两者 .NET Framework 4.6.2 和 .Net Standard 1.5.这是来自 VS 2017 的缩写 .csproj 文件:

<属性组><TargetFrameworks>net462;netstandard1.5</TargetFrameworks>...</PropertyGroup></项目>

当我从本地 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 包.我四处搜索用于目标包",但仅适用于 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:Restoremsbuildmsbuild/t:Publish/p:Configuration=Release

单声道 < 的打包解决方法5.2:

唯一的限制是单声道 (< 5.2) 不能立即生成 NuGet 包,但有一个 解决方法涉及在项目中使用 NuGet.Build.Tasks.Pack NuGet 包,它允许您执行 msbuild/t:Pack/p:Configuration=Release 通过像这样修改项目文件(特别注意删除 元素上的 Sdk="..." 属性):

<属性组><NuGetBuildTasksPackTargets>junk-value-to-avoid-conflicts</NuGetBuildTasksPackTargets></PropertyGroup><导入项目="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 文件,其中包含以下内容以添加提要:

然后您可以添加一个项目组以将 PackageReference 添加到目标包和一个 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"/></项目组></项目>

如果您使用本机资产(例如为 Linux 获取 .so 文件),您可以针对不同平台更改 RuntimeIdentifier 或在构建库时将其完全删除.>

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 naïve, 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.

这篇关于在面向 .NET Framework 的 Linux 上构建 NuGet 包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆