Build NuGet package on Linux that targets .NET Framework

You can just add the following to your project file:

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

This will allow to build and pack on non-windows systems for .NET Framework. But you can only run .NET Core targets using dotnet CLI on non-windows systems. So you should also be ready to select a target framework to run on non-windows systems, like this:

dotnet run -f netcoreapp2.1

Source of the solution: https://github.com/dotnet/designs/pull/33#issuecomment-489264196. This is a workaround, so it is subject to change in the future.


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

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.