静态库可以链接到.NET AOT编译的可执行文件吗?

问题描述 投票:0回答:2

如所见,例如在这里[1],我们可以从.NET导出一个函数,以便稍后静态链接到另一个可执行文件。

using System;
using System.Runtime.InteropServices;

public static class NativeExports
{
    [UnmanagedCallersOnly(EntryPoint = "multiply")]
    public static int Multiply(int a, int b)
    {
        return a * b;
    }
}

其他方向也可以吗?

像这样的东西(伪代码),就是我正在寻找的:

using System;
using System.Runtime.InteropServices;

public static class NativeImports
{
    [UnmanagedImpl(EntryPoint = "multiply")]
    public static extern int Multiply(int a, int b);
}

稍后与此静态链接:

// multiply.c
int multiply(int a, int b)
{
    return a*b;
}

总体目标是拥有一个单一、静态链接、无依赖的可执行文件,主要用 C# 编写。

我了解 P/Invoke 等。等人。这是我目前的解决方法。

[1] https://ericsink.com/native_aot/mul_cs.html

.net static lib aot
2个回答
1
投票

在获得一些帮助后回答我自己的问题(https://github.com/dotnet/runtime/issues/89044):

使用静态链接直接 P/Invoke 调用的最小示例

这是我们想要静态链接到用 C# 编写的可执行文件的函数

#include <stdio.h>
#include <string.h>

double UnmanagedTest (const char* name, double num)
{
    printf("Hello, %s\n", name);
    return num * strlen(name);
}

这是我们的 C# 应用程序。要静态链接的外部函数的声明方式与普通 P/Invoke 函数相同。

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");
    }
}

项目文件的这一部分负责生成直接调用并静态链接到用 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>

参考文献


0
投票

我实际上找到了一种方法来做到这一点......但它利用了一种非常利基的互操作方法。您基本上可以将委托传递到您的 C# 代码中!不幸的是,这可能有一些限制,但我不确定。我也只尝试动态链接已编译的 C#,但我确信您也可以静态链接它。无论如何,这是一个例子:

main.c

typedef int(*FunctionPointer)(int, int);

extern void InitializeLib(FunctionPointer ptr);
extern void CSMain();

int multiply(int a , int b)
{
     return a * b;
}

int main()
{
     InitializeLib(&multiply);
     CSMain();
}

然后你的 C# 文件将如下所示:

程序.cs

using System.Runtime.InteropServices;

namespace MyProgram;

unsafe class Program
{
     public static delegate*<int, int, int>multiply { get; set; }

     [UnmanagedCallersOnly(EntryPoint = "InitializeLib")]
     public static void InitializeLib(delegate*<int, int, int> ptr)
     {
           multiply = ptr;
     }

     [UnmanagedCallersOnly(EntryPoint = "CSMain")]
     public static void CSMain()
     {
           int val = multiply(5, 5);
     }
}

我写完这段代码后没有测试。但我相信这会起作用......无论如何,这里的想法是编译 C 并将 C# 静态链接到 C 二进制文件。从那里您可以调用您的 C# 主函数,也可以将委托传递到您的 C# 代码中。

我已经写了一个简单的概念证明以及如何在我的 github 上构建它的说明:

https://github.com/YendisFish/CS2C/

© www.soinside.com 2019 - 2024. All rights reserved.