.NET 7 AOT 的使用以及 .NET 与 Go 互相调用( 四 )


CsharpExport.dll 复制到 CsharpAot 项目中 , 并配置 始终复制 。

.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
CsharpAotNative 中加上:
[LibraryImport("CsharpExport.dll", SetLastError = true)][return: MarshalAs(UnmanagedType.I4)]internal static partial Int32 Add(Int32 a, Int32 b);
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
然后在代码中使用:
static void Main(){var result = Native.Add(1, 2);Console.WriteLine($"1 + 2 = {result}");Console.ReadKey();}在 Visual Studio 里启动 Debug 调试:
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
可以看到,是正常运行的 。
接着,将 CsharpAot 项目发布为 AOT 后,再次执行:
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
可以看到,.NET AOT 调用 .NET AOT 的代码是没有问题的 。
Golang 部分Go 生成 Windows 动态链接库,需要安装 GCC,通过 GCC 编译代码生成对应平台的文件 。
安装 GCC需要安装 GCC 10.3,如果 GCC 版本太新,会导致编译 Go 代码失败 。
打开 tdm-gcc 官网,通过此工具安装 GCC,官网地址:
https://jmeubank.github.io/tdm-gcc/download/
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
下载后,根据提示安装 。
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
然后添加环境变量:
D:\TDM-GCC-64\bin
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
运行 gcc -v,检查是否安装成功 , 以及版本是否正确 。
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
Golang 导出函数本节的知识点是 cgo , 读者可以从这里了解更多:
https://www.programmerall.com/article/11511112290/
新建一个 Go 项目:
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
新建一个 main.go 文件 , 文件内容如下:
package mainimport ( "fmt")import "C"//export Startfunc Start(arg string) { fmt.Println(arg)}// 没用处func main() {}在 Golang 中 , 要导出此文件中的函数,需要加上 import "C",并且 import "C" 需要使用独立一行放置 。
//export {函数名称} 表示要导出的函数,注意,//export 之间 没有空格 。
main.go 编译为动态链接库:
go build -ldflags "-s -w" -o main.dll -buildmode=c-shared main.go
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
不得不说,Go 编译出的文件 , 确实比 .NETAOT 小一些 。
前面,笔者演示了 .NET AOT 调用 .NET AOT,那么,Go 调用 Go 是否可以呢?
答案是:不可以 。
因为 Go 编译出来的 动态链接库本身带有 runtime,Go 调用 main.dll 时 ,会出现异常 。
具有情况可以通过 Go 官方仓库的 Issue 了解:https://github.com/golang/go/issues/22192
这个时候,.NET 加 1 分 。
虽然 Go 不能调用 Go 的,但是 Go 可以调用 .NET 的 。在文章后面会介绍 。
虽然说 Go 不能调用自己,这里还是继续补全代码,进一步演示一下 。
Go 通过动态链接库调用函数的示例:
func main() { maindll := syscall.NewLazyDLL("main.dll") start := maindll.NewProc("Start") var v string = "测试代码" var ptr uintptr = uintptr(unsafe.Pointer(&v)) start.Call(ptr)}代码执行后会报错:
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
.NET C# 和 Golang 互调C# 调用 Golang将 main.dll 文件复制放到 CsharpAot 项目中,设置 始终复制 。
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
然后在 Native 中添加以下代码:
[LibraryImport("main.dll", SetLastError = true)]internal static partial void Start(IntPtr arg);
.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
调用 main.dll 中的函数:
static void Main(){string arg = "让 Go 跑起来";// 将申请非托管内存string转换为指针IntPtr concatPointer = Marshal.StringToHGlobalAnsi(arg);Native.Start(concatPointer);Console.ReadKey();}

推荐阅读