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


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

经验总结扩展阅读