As seen e.g. here, we can export a function from .NET to be statically linked to another executable later.
using System;
using System.Runtime.InteropServices;
public static class NativeExports
{
[UnmanagedCallersOnly(EntryPoint = "multiply")]
public static int Multiply(int a, int b)
{
return a * b;
}
}
Is the other direction also possible?
Something like this (pseudo code), is what I'm looking for:
using System;
using System.Runtime.InteropServices;
public static class NativeImports
{
[UnmanagedImpl(EntryPoint = "multiply")]
public static extern int Multiply(int a, int b);
}
Later on linked with this statically:
// multiply.c
int multiply(int a, int b)
{
return a*b;
}
The overall goal is to have a single, statically linked, dependency-free executable mainly written in C#.
I know about P/Invoke et. al. — that's my current workaround.
Answering my own question after getting some help (https://github.com/dotnet/runtime/issues/89044):
This is the function we would like to statically link against our executable written in C#
#include <stdio.h>
#include <string.h>
double UnmanagedTest (const char* name, double num)
{
printf("Hello, %s\n", name);
return num * strlen(name);
}
This is our C# application. External functions to be linked statically are declared like normal P/Invoke functions.
using System.Runtime.InteropServices;
internal static class App
{
[DllImport("nativelib", EntryPoint = "UnmanagedTest", CallingConvention = CallingConvention.Cdecl)]
public static extern double UnmanagedTest ([MarshalAs(UnmanagedType.LPStr)] string name, double num);
public static void Main()
{
Console.WriteLine("Hello, World!");
var val = UnmanagedTest("World!", 7);
Console.WriteLine($"I got the number '{val}' back");
}
}
This part of the project file is responsible for generating the direct calls and linking statically against the library written in C:
app.csproj
<ItemGroup>
<!-- Generate direct PInvokes for Dependency -->
<DirectPInvoke Include="nativelib" />
<!-- Specify library to link against -->
<NativeLibrary Include="nativelib.lib" Condition="$(RuntimeIdentifier.StartsWith('win'))" />
<!-- Specify the path to search for libraries -->
<LinkerArg Include="/LIBPATH:..\\clib" Condition="$(RuntimeIdentifier.StartsWith('win'))" />
</ItemGroup>