dotnet / runtimelab

This repo is for experimentation and exploring new ideas that may or may not make it into the main dotnet/runtime repo.
MIT License
1.43k stars 200 forks source link

"Unresolved external symbol" when trying to P/Invoke exported function from separate library #1959

Closed Michael-Kelley closed 2 years ago

Michael-Kelley commented 2 years ago

I am currently writing a minimal CoreLib designed to be easily portable to use in my C# OS, and I would like to split platform-specific code into its own library.

I have 3 projects:

In bbCoreLib, I have some code like this:

[DllImport("*")]
static extern unsafe void bbPrint(char* message, int length);

public static unsafe void WriteLine(string message) {
    fixed (char* pMessage = message) {
        bbPrint(pMessage, message.Length);
    }
}

bbPrint is implemented in bbCoreLib.Desktop like so:

[UnmanagedCallersOnly(EntryPoint = "bbPrint")]
[RuntimeExport("bbPrint")]
public static unsafe void bbPrint(char* message, int length) {
    Win32.WriteConsoleW(Win32.GetStdHandle(-11), message, length, out int _, null);
}

Test.Desktop references both bbCoreLib and bbCoreLib.Desktop and contains no code besides this:

static int Main() {
    Console.WriteLine("Hello from bbCoreLib Tests.Desktop!");

    return 0;
}

The problem is that the ILC compiler can't seem to find bbPrint, resulting in this linker error: Tests.Desktop.obj : error LNK2001: unresolved external symbol bbPrint [D:\Projects\VS2022\bbCoreLib\Tests.Desktop\Tests .Desktop.csproj]

Does NativeAOT support P/Invoke calls like this? If so, what am I doing wrong?

MichalStrehovsky commented 2 years ago

The compiler only looks for RuntimeExport methods in the input modules (inputs to ilc.exe without any switches). It won't look at them in references (whatever is passed as -r:). I assume bbCoreLib.Desktop is passed as -r:.

MAG-MichaelK commented 2 years ago

I would assume so, yes, as it's only referenced by Test.Desktop. Can I add bbCoreLib.Desktop to @(IlcCompileInput), or do I need to specify it in a different way?

Michael-Kelley commented 2 years ago

Can I add bbCoreLib.Desktop to @(IlcCompileInput)

I can! This seems to work. It's not the most elegant solution, but it's something. I'll see if I can find a better way of doing this, maybe by outputting the dependency output path to a text file and reading from it:

<ItemGroup>
    <ProjectReference Include="..\bbCoreLib.Desktop\bbCoreLib.Desktop.csproj" />
    <ProjectReference Include="..\bbCoreLib\bbCoreLib.csproj" />
</ItemGroup>

<ItemGroup>
    <IlcCompileInput Include="$([System.IO.Path]::GetFullPath($(SolutionDir)bbCoreLib.Desktop\bin\$(Configuration)\bbCoreLib.Desktop.dll))"/>
</ItemGroup>