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?
. NET is an open source software framework for building cross-platform applications on Linux, Windows, and macOS.
The . nuget/nuget. targets was an old "integration" of NuGet with Visual Studio between Visual Studio 2010 to Visual Studio 2013. Visual Studio 2015 onwards no longer has the feature to create this file, because NuGet's integration is more direct.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With