AaronRobinsonMSFT / DNNE

Prototype native exports for a .NET Assembly.
MIT License
394 stars 41 forks source link

.net framework support #151

Closed jmecosta closed 1 year ago

jmecosta commented 1 year ago

Hi,

is there a reason why we cant use DNNE if we are targeting .net 48? Basically the step to migrate a big app is to remove C++ CLI so it would be convenient to use DNNE to create the wrapper headers

thanks

AaronRobinsonMSFT commented 1 year ago

is there a reason why we cant use DNNE if we are targeting .net 48?

@jmecosta DNNE is focused on .NET Core because the hosting API is substantially easier to work with in C and the resulting scenarios are simply optimized better in .NET Core (For example, UnmanagedCallersOnly). This isn't to say DNNE couldn't be imbued with support for .NET Framework, it absolutely could.

You mentioned C++/CLI and that means you've increased the priority of this request. I'd really like to discuss this more to understand your needs. if you are willing, feel free to email me directly, my microsoft.com email is in my github profile. I'd be very interested in talking offline about your needs.

AaronRobinsonMSFT commented 1 year ago

/cc @elinor-fung @jkoritzinsky

jmecosta commented 1 year ago

@AaronRobinsonMSFT thanks. So basically our end goal is to target net5.0 since we are on a journey of making components able to run on linux/cloud. However we must remain backwards compatible for the time being so we dont break all our clients plugins and applications. So we, for a while will target what we can on .net standard and .net framework.

Our biggest problem is C++ / CLI we have it everywhere and the only way i see this going forward is totally removing it and use something that can make our life as easier as the c++ cli. DNNE sound a nice way of doing for doing the interop.

So we want to use it to help us get rid of the c++ cli and finally have native and manage stack that can be run both on net6.0 and net6.0 windows.

Let me know if can clarify it further, thanks... Or if you have some other alternatives those would be great...

AaronRobinsonMSFT commented 1 year ago

Our biggest problem is C++ / CLI we have it everywhere and the only way i see this going forward is totally removing it and use something that can make our life as easier as the c++ cli. DNNE sound a nice way of doing for doing the interop.

Agree on this perspective. DNNE can help a lot here.

So we want to use it to help us get rid of the c++ cli and finally have native and manage stack that can be run both on net6.0 and net6.0 windows.

Perfect. I am onboard. What is your timeframe for this work? I would need to figure out some time to slot this work into my schedule.

jmecosta commented 1 year ago

Well, actually we need it already yesterday 😅. Luckily we have week holidays coming up so nothing will move forward. In about a month we will have a update on how the work is going would be nice by then to have a full picture of the work need and what we will use going forward

By the way I was checking to code out, isn't the work need only to add a few more msbuild conditions? The tool that creates the header files can still stay .net right?

On Fri, Feb 17, 2023, 21:55 Aaron Robinson @.***> wrote:

Our biggest problem is C++ / CLI we have it everywhere and the only way i see this going forward is totally removing it and use something that can make our life as easier as the c++ cli. DNNE sound a nice way of doing for doing the interop.

Agree on this perspective. DNNE can help a lot here.

So we want to use it to help us get rid of the c++ cli and finally have native and manage stack that can be run both on net6.0 and net6.0 windows.

Perfect. I am onboard. What is your timeframe for this work? I would need to figure out some time to slot this work into my schedule.

— Reply to this email directly, view it on GitHub https://github.com/AaronRobinsonMSFT/DNNE/issues/151#issuecomment-1435166824, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH6HSCLIMYGK7KFAKHVLYTWX7JTBANCNFSM6AAAAAAU7PYQUY . You are receiving this because you were mentioned.Message ID: @.***>

AaronRobinsonMSFT commented 1 year ago

By the way I was checking to code out, isn't the work need only to add a few more msbuild conditions? The tool that creates the header files can still stay .net right?

A few MSBuild things need to be updated, but the real logic that needs to change is in platform.c. The MSBuild side is going to be annoying because we need to thread the needle of making sure when "net472", "net48" or another .NET Framework is targeted the proper flags are passed.

I actually have been working on this for about an hour and the new "platform" native code is working as expected. Now all I need to do is ensure it can be chained into the MSBuild logic and add some tests - that is the part I am most worried about. Basically, I would say within a few days I should be able to have a solution working. A few questions:

1) Are you okay with declaring and marking appropriate functions as described here. Defining a new Delegate won't be needed.

2) What style of project is being used? I assume SDK and defining TargetFramework, please confirm.

3) What version of .NET Framework is your project targeting? I am asking because I plan to only provide support for .NET Framework 4.x.

AaronRobinsonMSFT commented 1 year ago

@jmecosta I was able to make this work without a ton of effort. Testing is a bit sparse, but it compiles and I've tested it locally for .NET v4. The branch is pushed up if you liked to try it out - https://github.com/AaronRobinsonMSFT/DNNE/tree/v2.

I'm about to push up the final release of version 1, 1.1 and then branch to 2. Only version 2 will have support for .NET Framework.

JeremyAnsel commented 1 year ago

Hello, In the sample project you have:

public class Exports
{
#if NETFRAMEWORK
    [DNNE.Export(EntryPoint = "FancyName")]
#else
    [UnmanagedCallersOnly(EntryPoint = "FancyName")]
#endif // !NETFRAMEWORK
    public static int MyExport(int a)
    {
        return a;
    }
}

For net4.x the attribute is DNNE.Export. For net6.0 the attribute is UnmanagedCallersOnly.

Is it possible to define the UnmanagedCallersOnly attribute for net 4.x? Something like that:

#if NETFRAMEWORK
namespace System.Runtime.InteropServices
{
    [AttributeUsage(AttributeTargets.Method, Inherited = false)]
    public sealed class UnmanagedCallersOnlyAttribute : Attribute
    {
        public UnmanagedCallersOnlyAttribute()
        {
        }

        public Type[]? CallConvs;

        public string? EntryPoint;
    }
}
#endif

This way we could have the same attribute for both net4.0 and net6.0:

public class Exports
{
    [UnmanagedCallersOnly(EntryPoint = "FancyName")]
    public static int MyExport(int a)
    {
        return a;
    }
}

Is it possible?

AaronRobinsonMSFT commented 1 year ago

Is it possible?

It is possible, but I wouldn't advise it because in .NET 6 the UnmanagedCallersOnlyAttribute type has a lot of semantic meaning and I'd like to avoid confusing the behavior with what is going on in .NET Framework. Right now, it wouldn't work due to the source generated, via dnne-gen, and the implementation of get_fast_callable_managed_function() in platform_v4.cpp. Either dnne-gen would need to change for .NET Framework or get_fast_callable_managed_function() would need to be implemented. The former isn't something I think is a good idea and the latter is lying because both get_fast_callable_managed_function() and get_callable_managed_function() would return the same thing.

From an ease of use perspective I get the desire. I'm simply leery of asking people to define a .NET 6+ type that when used in .NET 6 has profoundly different behavior than it would on .NET Framework.

JeremyAnsel commented 1 year ago

Thank you for the answer.

To date my projects where I export a function are targeting net48. So I don't have to use both attributes. In the future when I will eventually upgrading these projects to net6.0, I will eventually multitargetting net6.0 and net48 to be backward compatible. For projects targetting net6.0 only I will use the UnmanagedCallersOnly attribute. For projects targettting net4.8 only I will use the DNNE.Export attribute. For projects targetting net6.0 and net48 I will use both attributes. Having to use 2 different attributes when multitargetting is not a big problem for me.

Thank you very much for this great project.

jmecosta commented 1 year ago

On Sun, Feb 19, 2023, 04:12 Aaron Robinson @.***> wrote:

By the way I was checking to code out, isn't the work need only to add a few more msbuild conditions? The tool that creates the header files can still stay .net right?

A few MSBuild things need to be updated, but the real logic that needs to change is in platform.c https://github.com/AaronRobinsonMSFT/DNNE/blob/master/src/platform/platform.c. The MSBuild side is going to be annoying because we need to thread the needle of making sure when "net472", "net48" or another .NET Framework is targeted the proper flags are passed.

I actually have been working on this for about an hour and the new "platform" native code is working as expected. Now all I need to do is ensure it can be chained into the MSBuild logic and add some tests - that is the part I am most worried about. Basically, I would say within a few days I should be able to have a solution working. A few questions:

Actually it would be ok also if you let customers do the msbuild logic. That is it might not be a good idea to let a msbuild task handle this. We might want to do the generation in a custom target before all the build. So if you have a command line tool and some arguments that would be useful also

1.

Are you okay with declaring and marking appropriate functions as described here https://github.com/AaronRobinsonMSFT/DNNE#experimental-attribute. Defining a new Delegate won't be needed.

Should be ok. How about types? For example lists? We have some logic in the c++ cli that converts list to vector.

1.

What style of project is being used? I assume SDK and defining TargetFramework https://learn.microsoft.com/dotnet/standard/frameworks, please confirm.

Yep. And u probably should support only sdk. Migration to it is simple enough

1.

What version of .NET Framework is your project targeting? I am asking because I plan to only provide support for .NET Framework 4.x.

Yep 40 and above.

— Reply to this email directly, view it on GitHub https://github.com/AaronRobinsonMSFT/DNNE/issues/151#issuecomment-1435818442, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH6HSEEZTVR7V33Q6UBNETWYF6Q3ANCNFSM6AAAAAAU7PYQUY . You are receiving this because you were mentioned.Message ID: @.***>

jmecosta commented 1 year ago

On Sun, Feb 19, 2023, 14:48 Jérémy Ansel @.***> wrote:

Hello, In the sample project you have:

public class Exports {

if NETFRAMEWORK

[DNNE.Export(EntryPoint = "FancyName")]

else

[UnmanagedCallersOnly(EntryPoint = "FancyName")]

endif // !NETFRAMEWORK

public static int MyExport(int a)
{
    return a;
}

}

For net4.x the attribute is DNNE.Export. For net6.0 the attribute is UnmanagedCallersOnly.

Is it possible to define the UnmanagedCallersOnly attribute for net 4.x? Something like that:

if NETFRAMEWORKnamespace System.Runtime.InteropServices

{ [AttributeUsage(AttributeTargets.Method, Inherited = false)] public sealed class UnmanagedCallersOnlyAttribute : Attribute { public UnmanagedCallersOnlyAttribute() { }

    public Type[]? CallConvs;

    public string? EntryPoint;
}

}

endif

This way we could have the same attribute for both net4.0 and net6.0:

public class Exports { [UnmanagedCallersOnly(EntryPoint = "FancyName")] public static int MyExport(int a) { return a; } }

Is it possible?

Yep i an put the type in a lower level library so we don't if Def stuff all over the place.

— Reply to this email directly, view it on GitHub https://github.com/AaronRobinsonMSFT/DNNE/issues/151#issuecomment-1435980326, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH6HSGGOMGOFFI4JEDCPFLWYIJDLANCNFSM6AAAAAAU7PYQUY . You are receiving this because you were mentioned.Message ID: @.***>

jmecosta commented 1 year ago

Excellent I let you know how it goes. Thank you a lot.

On Sun, Feb 19, 2023, 08:44 Aaron Robinson @.***> wrote:

@jmecosta https://github.com/jmecosta I was able to make this work without a ton of effort. Testing is a bit sparse, but it compiles and I've tested it locally for .NET v4. The branch is pushed up if you liked to try it out - https://github.com/AaronRobinsonMSFT/DNNE/tree/v2.

I'm about to push up the final release of version 1, 1.1 and then branch to 2. Only version 2 will have support for .NET Framework.

— Reply to this email directly, view it on GitHub https://github.com/AaronRobinsonMSFT/DNNE/issues/151#issuecomment-1435907140, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH6HSBO7GHFQND36EE6QRTWYG6NPANCNFSM6AAAAAAU7PYQUY . You are receiving this because you were mentioned.Message ID: @.***>

AaronRobinsonMSFT commented 1 year ago

Should be ok. How about types? For example lists? We have some logic in the c++ cli that converts list to vector.

This will need to be done manually. DNNE is about providing the lightest weight export possible. This means only types that can naturally be expressed in C can be arguments for an export. See the readme.md for further details.

david-bouyssie commented 1 year ago

Hi. Do you think this could work on Linux as well? I was trying to target the framework 4.7.2 using the examples but without success so far.

Thanks!

AaronRobinsonMSFT commented 1 year ago

I was trying to target the framework 4.7.2 using the examples but without success so far.

@david-bouyssie There seems to be a confusion here. .NET Framework is exclusive to Windows. .NET (that is, 5+) is the cross-platform offering for .NET. This support was added for users of DNNE to have a simple native export scenario when targeting .NET Framework without having to use C++/CLI.

jmecosta commented 1 year ago

@AaronRobinsonMSFT/DNNE @.***> feel free to close the ticket. We have a working poc using done. Thank you again

On Tue, May 23, 2023, 20:24 Aaron Robinson @.***> wrote:

I was trying to target the framework 4.7.2 using the examples but without success so far.

@david-bouyssie https://github.com/david-bouyssie There seems to be a confusion here. .NET Framework is exclusive to Windows. .NET (that is, 5+) is the cross-platform offering for .NET. This support was added for users of DNNE to have a simple native export scenario when targeting .NET Framework without having to use C++/CLI.

— Reply to this email directly, view it on GitHub https://github.com/AaronRobinsonMSFT/DNNE/issues/151#issuecomment-1559861719, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH6HSDHVEOK3ASZR4GF4KTXHTXENANCNFSM6AAAAAAU7PYQUY . You are receiving this because you were mentioned.Message ID: @.***>

david-bouyssie commented 1 year ago

@AaronRobinsonMSFT thank you for your quick reply Well I have some assemblies targeting net472 and I would like to use them from Linux through a DNNE wrapper. Do you think that should be feasible? Currently I'm using embeddinator-4000 and Mono but I would like to get rid of this. I was currently investigating this https://andrewlock.net/using-reference-assemblies-to-build-net-framework-libararies-on-linux-without-mono/

But was not successful so far.

AaronRobinsonMSFT commented 1 year ago

Well I have some assemblies targeting net472 and I would like to use them from Linux through a DNNE wrapper.

The best approach here is to retarget your assemblies to netstandard2.0. These libraries can then be used running on .NET Framework 4.7.2 or .NET 6+.

If you have further questions please open a new issue and reference this one if needed. Thanks.