Multitarget plugin Rhino/Grasshopper

Hi all,

I’m doing late update of our internal Rhino and Grasshopper plugin to work for Rhino 8, and looking through the forum it seems like the move has been pretty seamless for most.

I’ll however have to multitarget the plugin for both Mac and Windows, which during a transition period will be using both Rhino 7 and 8.

From what I gather most then just targeting both .Net 7.0 and .Net Framework 4.8, but in one post (linked below) @visose wrote that you can also just target .NET Standard 2.0 and all should work fine. So I am a bit confused, why would I target them individually instead? Is there any upsides to that?

And another question, if I multitarget the “Moving to .NET 7”-guide says only the net 4.8 version should be distributed for Windows. Why? I thought core 7.0 would work for both Windows and Mac, so was considering only targeting .Net Core when all users have moved to Rhino 8.

https://discourse.mcneel.com/t/moving-plugin-to-rhino-8/17068519

1 Like

netstandard2.0 can consume net48 (in a compatibility mode), but cannot consume dotnet core. Rhino will also not load your plugin in my testing (at least on Mac, I haven’t tried Windows, but I’d gamble it’s the same).

As netstandard2.0 is not an option, you’ll need to specify both net7.0 and net48 as below.

<TargetFrameworks>net7.0;net48</TargetFrameworks>

A tangible advantage of course is that your editor will tell you what is and is not supported by both net48/netcore which is very useful.

Can you link to this guide? It might mean only windows can use net48, which is true, mac will only use net7.0.

This link goes nowhere for me, I’d be curious to read it. Is it this thread Moving plugin to Rhino 8 - #9 by visose?

2 Likes

Thanks for your very clear response!

Yes sorry, donno what happened to my copy-pasting there, but that’s the thread I was referring to, where targeting netstandard 2.0 is discussed.

In this guide - Rhino - Moving to .NET 7 - it says that:

If you multi-target your project to both .NET 4.8 and .NET 7.0, you can find compatibility issues during compilation. Keep in mind you should only distribute the .NET 4.8 version on Windows.

Which made me wonder why I should only distribute the 4.8 version for Windows - and if that ment I can’t target only .NET 7.0, even when all users have Rhino 8, as I’ll always have to account for both Windows and Mac.

I’ve re-worded this a little bit, as it can be interpreted in two ways and is a little ambiguous. Thank you for raising this @jmhannu I’m sure it’ll prevent further confusion :slight_smile:

If you multi-target your project to both .NET 4.8 and .NET 7.0, you can easily find and resolve compatibility issues during compilation. Keep in mind that .NET 4.8 only needs to be included for Windows and not Mac.

2 Likes

Great, thanks - this makes total sense now! :slight_smile:

Hi, just to clarify a few things:

netstandard2.0 can consume net48 (in a compatibility mode), but cannot consume dotnet core.

This statement is not correct, .NET Standard was introduced on purpose to create a set of APIs that intersect both .NET Framework and .NET Core. See: .NET Standard - .NET | Microsoft Learn
I can load an .rhp compiled as .net standard 2.0 in both Rhino 7 and Rhino 8 for Windows. I haven’t tried for Mac, but there shouldn’t be a reason for it not to load.

The crux of the problem really is how to handle APIs that are available in both Windows and Mac but are outside of the intersection that NET Standard provides, mainly System.Drawing.

The way McNeel handles this, is really not what Microsoft recommends, but it’s how it was done during the Mono times, before .NET Core. This is, lets just target .NET Framework, and if the code uses any APIs not available on Mac, let it compile anyways and it will just fail at runtime.

They have kept this way and just added the suggestion to also target .net 7 to have some way to identify this intersection of APIs.

Ideally, McNeel should have made RhinoCommon also target .NET Standard and include something like System.Drawing.Common to fill the System.Drawing gap. It is possible they tried something similar and didn’t work for some reason or was too much work and decided to leave things as they are, but I’m just speculating.

If you target .NET Standard on a Rhino plugin project, besides getting a warning saying that RhinoCommon is not compatible (like with .net 7) since it targets .net framework. You will need to add a package like System.Drawing.Common to cover the missing APIs mentioned above if you need them. And even so it might still be difficult to get it to compile if you use RhinoCommon APIs that return System.Drawing types.

So the path of least resistance might be to target .net framework and make sure you don’t use APIs that are not available on Mac, but this is not ideal and is not what Microsoft would recommend.

If your project is split into several projects with a main .rhp and multiple .dlls, those dlls can target .net standard if they don’t use System.Drawing.

I’m making several presumptions about why things are the way they are, it would be great if @curtisw could correct these.

1 Like

I’m always happy to be proven wrong, but if I create a project in netstandard2.0, then create a new project in net7.0 or above, I cannot reference the core project from standard.

I’ve found this can be done if I run the debugger in netfx, but not netcore on windows, which might explain Mac not working and make sense when combined with above.

Are you testing it by launching Rhino from Visual Studio with the debugger? In that case what will happen is that the debugger will default to .NET Framework and will error. Try launching Rhino without the debugger and then attach the debugger separately, it will detect that Rhino is using .NET Core and use the appropiate debugger.
I find this more convenient also since Rhino will load faster as the debugger is not attached while loading.

if I create a project in netstandard2.0, then create a new project in net7.0 or above, I cannot reference the core project from standard.

Not sure if I understand: you are trying to reference a .NET 7 project as a dependency of a net standard project?
It makes sense that this would not be allowed. NET Standard is the more restrictive set of APIs. It would only be expected to work the other way around, a .NET 7 project referencing a net standard one. But you only need one project that compiles to a .rhp.

Yep, it works in .NET Framework for me, but not dotnet core.

Yes, I thought you were saying this was possible which was news to me :slight_smile: .

Yep, it works in .NET Framework for me, but not dotnet core.

You mean it still doesn’t work after trying what I suggested above?

Yes, I thought you were saying this was possible which was news to me

When you said “netstandard2.0 can consume net48 (in a compatibility mode), but cannot consume dotnet core.” I assumed you meant that a library compiled targeting net standard cannot run on the .NET Core runtime. Interpreting it as the reverse made little sense in that context.

The way to think about it is that Rhino 7 itself is like a top .net framework project, Rhino 8 a top .net 7 project, and a plugin is like adding a project reference to them.