In a previous post, I made a recommendation of additionally targeting net461 in addition to netstandard2.0 in certain scenarios, however one of the nice things about targeting netstandard2.x is that on macOS you can install the .NET Core SDK, build it, and "it just works".

With net4x however, when you run dotnet build you might see this error:

error MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.6.1" were not found.

And that makes a lot of sense, because in order to compile for net461 in this case, we need the reference assemblies of that framework, these are dlls that are the same as the runtime assemblies, but just the signatures, no implementation. On Windows these are called "Targeting Packs" and you would have these ship with Visual Studio, or packaged via standalone installers called "Developer Packs".

On macOS, there are 2 ways to reference these reference assemblies that I know of;

1. Using the mono reference assemblies

If you have Visual Studio for Mac or Rider installed, then you probably already have this installed, and otherwise, it's a good idea to get the latest stable version installed from here. You will probably be able to find the reference assemblies located under version folders within /Library/Frameworks/Mono.framework/Versions/Current/lib/mono.

Now the MSBuild that comes with the .NET Core SDK needs know where to find the reference assemblies. I found a solution here, however I'm not sure where it originates from (maybe it was from there?).

You can include a file named netfx.props with this content, and import it into your project like this:

<Project Sdk="Microsoft.NET.Sdk">
<Import Project="netfx.props" />
<PropertyGroup>
<Description>...

And now you are good to go!

2. Obtain the reference assemblies via MyGet

An alternative approach that doesn't require having mono installed is to obtain them via nuget, however, they are not available on nuget.org as of today, there is a GitHub issue that can be tracked regarding this. They currently exist on a MyGet feed (from version 4.5 and up). These are official Microsoft packages, here's an example for 4.6.1.

First you need to add the feed like this:

<PropertyGroup>
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
<RestoreAdditionalProjectSources>
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json
</RestoreAdditionalProjectSources>
</PropertyGroup>

You may have also seen this done via NuGet.config (which is just less cool), or you may have seen this using the RestoreSources property, which would require you to append it to the existing source like this: <RestoreSources>$(RestoreSources);...</RestoreSources>
You can read more about that here.

Now we can import the package:

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

Finally, we need to point the FrameworkPathOverride to the assemblies from this package:

<PropertyGroup Condition="'$(TargetFramework)'== 'net461'">
<FrameworkPathOverride>$(NuGetPackageRoot)microsoft.targetingpack.netframework.v4.6.1/1.0.1/lib/net461/</FrameworkPathOverride>
</PropertyGroup>

Conclusion

And that's it. There is always the option of using msbuild shipped with mono too by running it just for the net4x tfm, and using dotnet build for other tfms, but where's the fun in that? Let me know if you have other ways of approaching this in the comments.