在 Linux 上构建面向 .NET Framework 的 NuGet 包

Posted

技术标签:

【中文标题】在 Linux 上构建面向 .NET Framework 的 NuGet 包【英文标题】:Build NuGet package on Linux that targets .NET Framework 【发布时间】:2021-03-18 15:59:43 【问题描述】:

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

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

  <PropertyGroup>
    <TargetFrameworks>net462;netstandard1.5</TargetFrameworks>
    ...
  </PropertyGroup>

</Project>

当我从本地 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 包?

【问题讨论】:

目前他们没有考虑这种情况。所以你必须使用 Windows。 这是由我几个月前打开的issue on GitHub 跟踪的。我根据那里发生的讨论发布了答案。 @MartinUllrich 感谢您提供的 GitHub 链接,它提供了非常丰富的信息。 【参考方案1】:

.NET CLI 的分发不包含任何 .NET Framework 的参考程序集,因此其 MSBuild 版本无法解析所需的编译时资产。这种情况是 tracked on GitHub,但在迁移到 MSBuild 之前已经有效(CLI 可以使用 mono 的参考程序集)。

虽然有一些替代方案可用于在非 Windows 机器上构建库:

1.使用 mono 5+ 构建库。

这可能是最稳定的路径了。

Mono 5 及更高版本包含构建 .NET Standard 和 .NET Core 应用程序所需的构建逻辑。在 linux 上,mono 的 msbuild 可能需要作为单独的包安装。所以代替下面常用的命令

dotnet restore
dotnet build
dotnet publish -c Release

您可以使用 mono 的 msbuild 来执行以下操作:

msbuild /t:Restore
msbuild
msbuild /t:Publish /p:Configuration=Release

单声道

唯一的限制是 mono (workaround involving using the NuGet.Build.Tasks.Pack NuGet package 允许您通过像这样修改项目文件来执行 msbuild /t:Pack /p:Configuration=Release(特别注意删除了 &lt;Project&gt; 元素上的 Sdk="..." 属性):

<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。使用 .NET CLI 并告诉 MSBuild 使用 mono 的参考程序集。

net* 目标框架构建时,您可以将FrameworkPathOverride 属性设置为环境变量或csproj 文件中的属性。它需要指向一组参考程序集——这里可以使用mono的参考程序集。但有些包含一个特殊文件(redist 列表),其中包含对 .NET CLI 中的 MSBuild 版本无法遵循的其他目录的引用。但它确实适用于很多场景:

export FrameworkPathOverride=/usr/lib/mono/4.5/
dotnet build -f net45

这是用过的和documented by the F# team。

3.使用包含引用程序集的 NuGet 包。

在某些 MyGet 源中,Microsoft 发布了包含参考程序集的 NuGet 包。虽然它们没有发布或“官方”,但这个过程可能会在某个时间点失败。但是他们确实plan to investigate making this path official。

首先在您的解决方案目录中创建一个 NuGet.Config 文件,其中包含以下内容以添加提要:

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

然后您可以添加一个项目组以将PackageReference 添加到目标包中,并添加一个PropertyGroup 以设置引用程序集的路径,如下所示:

<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.1\1.0.1\lib\net461\</FrameworkPathOverride>
  </PropertyGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
    <PackageReference Include="Microsoft.TargetingPack.NETFramework.v4.6.1" Version="1.0.1" ExcludeAssets="All" PrivateAssets="All" />
  </ItemGroup>

</Project>

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

【讨论】:

第三个选项现在应该是最终的解决方案,因为微软已将其正式化github.com/Microsoft/dotnet/tree/master/releases/…【参考方案2】:

您可以将以下内容添加到您的项目文件中:

  <ItemGroup Condition="$(TargetFramework.StartsWith('net4')) AND '$(MSBuildRuntimeType)' == 'Core' AND '$(OS)' != 'Windows_NT'">
    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
  </ItemGroup>

这将允许在非 Windows 系统上为 .NET Framework 构建和打包。 但是您只能在非 Windows 系统上使用 dotnet CLI 运行 .NET Core 目标。 所以你也应该准备好选择一个目标框架在非windows系统上运行,像这样:

dotnet run -f netcoreapp2.1

解决方案来源:https://github.com/dotnet/designs/pull/33#issuecomment-489264196。 这是一种解决方法,因此将来可能会发生变化。

【讨论】:

以上是关于在 Linux 上构建面向 .NET Framework 的 NuGet 包的主要内容,如果未能解决你的问题,请参考以下文章

[.net 面向对象程序设计深入].NET MVC 6.0 —— 构建跨平台.NET开发环境(Windows/Mac OS X/Linux)

Docker 构建失败,当前 .NET SDK 不支持面向 .NET Core 2.1

使用 CMake 在面向 Linux 的 Windows 下跨平台构建

无法使用 VS Code 在 Windows 机器上为 linux 构建 .Net core 3.0 项目

面向.NET开发人员的Dapr- actors 构建块

Jenkins 构建自动化 .NET Core 发布镜像