AaronRobinsonMSFT / DNNE

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

C99Type (or DNNE namespace/class) not found. When implemented manually, /* SUPPLY TYPE */ appears instead of the specified type, and compilation fails. #49

Closed darkguy2008 closed 3 years ago

darkguy2008 commented 3 years ago

Hello!

First of all thanks a lot for this awesome project, it's opening a lot of doors in regards of native/managed library development, thanks!

I'm facing a small issue here which I'd love to get some help from you: See, when creating a class like this:

using System;
using System.Runtime.InteropServices;

namespace Native
{
    public unsafe class Sample
    {
        [Serializable]
        public struct SAMPLE
        {
            public int a;
            public float b;
        }

        [UnmanagedCallersOnlyAttribute(EntryPoint = nameof(Void))]
        public static void Void()
        {
            Console.WriteLine($"{nameof(Void)}");
        }

        [UnmanagedCallersOnlyAttribute(EntryPoint = nameof(Ints))]
        public static void Ints(int a, int b)
        {
            Console.WriteLine($"{nameof(Ints)} {a} {b}");
        }

        [UnmanagedCallersOnlyAttribute(EntryPoint = nameof(Floats))]
        public static void Floats(float a, float b)
        {
            Console.WriteLine($"{nameof(Floats)} {a} {b}");
        }

        [UnmanagedCallersOnlyAttribute(EntryPoint = nameof(RecvStruct))]
        public static void RecvStruct([DNNE.C99Type("struct T*")] SAMPLE* arg)
        {
            Console.WriteLine($"{nameof(RecvStruct)}");
            arg->a = 1;
            arg->b = 2;
        }
    }
}

I get an error in [DNNE.C99Type("struct T*")] where it says The type or namespace name 'DNNE' could not be found (are you missing a using directive or an assembly reference?). I say, alright, let's implement it like so:

   internal class C99TypeAttribute : System.Attribute
        {
            public C99TypeAttribute(string code) { }
        }

But when I compile, I get a lot of compile errors:

dnne\Native.g.c(27): error C2143: syntax error: missing ')' before '*' [Native.csproj]
dnne\Native.g.c(27): error C2143: syntax error: missing '{' before '*' [Native.csproj]
dnne\Native.g.c(27): error C2059: syntax error: ')' [Native.csproj]
dnne\Native.g.c(106): error C2143: syntax error: missing ')' before '*' [Native.csproj]
dnne\Native.g.c(106): error C2143: syntax error: missing '{' before '*' [Native.csproj]
dnne\Native.g.c(106): error C2059: syntax error: ')' [Native.csproj]
dnne\Native.g.c(107): error C2143: syntax error: missing ')' before '*' [Native.csproj]
dnne\Native.g.c(107): error C2143: syntax error: missing '{' before '*' [Native.csproj]
dnne\Native.g.c(107): error C2059: syntax error: ')' [Native.csproj]
dnne\Native.g.c(108): error C2054: expected '(' to follow 'arg' [Native.csproj]

Mainly because in Native.g.c, I see this:

// Computed from Native.Sample.RecvStruct
DNNE_API void DNNE_CALLTYPE RecvStruct(/* SUPPLY TYPE */* arg);

Notice it says /* SUPPLY TYPE */ instead of struct T*.

This is my .csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <EnableDynamicLoading>true</EnableDynamicLoading>
    <DnneAddGeneratedBinaryToProject>true</DnneAddGeneratedBinaryToProject>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="DNNE" Version="1.*" />
  </ItemGroup>

</Project>

Any ideas? :)

darkguy2008 commented 3 years ago

Nevermind, fixed it by adding the full code of the Dnne.Attributes.cs file:

namespace DNNE
{
    internal class ExportAttribute : System.Attribute
    {
        public ExportAttribute() { }
        public string EntryPoint { get; set; }
    }

    internal class C99TypeAttribute : System.Attribute
    {
        public C99TypeAttribute(string code) { }
    }

    internal class C99DeclCodeAttribute : System.Attribute
    {
        public C99DeclCodeAttribute(string code) { }
    }
}

I find it weird that it works, considering the type should come from your namespace (to avoid different types of the same name...?) but hey, it's a solution.

Thanks and sorry for opening the bug :)

AaronRobinsonMSFT commented 3 years ago

@darkguy2008 It is expected for you to define the DNNE attributes if you need them. A design principle of the DNNE project was to avoid adding arbitrary assembly references that increase deployment sizes. The attributes in questions are needed only at code gen time and not used at all at run time. Since attribute look up is typically just string compare they can be defined anywhere - yay. This means as a consumer there is no need to define them unless desired and if used don't need to be deployed since they are a code gen concept and serve no purpose at run time. If`DNNE did provide them then you would need to also deploy another assembly to handle resolution at run time.

Note that the type name look up requires namespace + type name to match what the tooling is looking for.