在Windows环境下,我们可以将Go语言编译为DLL并供.Net等其他语言的代码调用,需要用到Mingw64的gcc编译器(请注意,不是MinGW)。
一、环境信息
1、Go
Go语言版本需要大于1.10,否则会报错:
1 |
-buildmode=shared not supported on windows/amd64 |
具体可参见:https://golang.org/doc/go1.10#compiler
2、Mingw64
Mingw64是gcc官方唯一支持的环境,可从http://www.mingw-w64.org/doku.php/download下载,安装时的架构选择x86_64即可,在安装完成后将Mingw64的bin目录(如D:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin)加入到PATH环境变量中,然后可以查看Go、Mingw64、gcc的版本:

查看Go、Mingw64及gcc版本
请注意,Mingw64的平台应和GOARCH的平台一致。例如,笔者的64位Win10下编译出的DLL文件为x64架构的:

注意Mingw架构
二、编写代码
在代码中导出要导出的函数,以下的代码被抄得到处都是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package main import "C" import "fmt" //export PrintBye func PrintBye() { fmt.Println("From DLL: Bye!") } //export Sum func Sum(a int, b int) int { return a + b; } func main() { // Need a main function to make CGO compile package as C shared library } |
其中://export的注释是必须的;main函数也是必须的,即使main函数是空的;如有必要,依然可以加入init函数。
三、编译为DLL
使用命令:
1 |
go build -buildmode=c-shared -o exportgo.dll main.go |
即可直接将main.go编译为exportgo.dll。
我们可以使用《在Java中进行中文繁体简体转换,基于OpenCC(Open Chinese Convert)方案》中描述的dumpbin工具或Dependency Walker查看导出的DLL是否正确:

使用dumpbin查看DLL文件
我们会发现除了PrintBye和Sum函数外,Go语言中自带的大量package中的函数也被导出了,多达17000余个。
此外,还可以通过
-ldflags 指定链接器参数去除符号表及调试信息等。
此外,如果要编译为静态库,可以使用:
1 |
go build -buildmode=c-archive main.go |
执行完毕后会在当前目录生成main.a和main.h文件。
四、交叉编译
我们可以使用命令:
1 |
go tool dist list |
查看当前支持的交叉编译环境(GOOS/GOARCH):

查看Go支持的交叉编译环境
然后使用命令:
1 2 3 4 |
set GOOS=linux set GOARCH=386 set CGO_ENABLED=0 go build |
配合对应的交叉编译链即可实现交叉编译。
五、.Net调用Go编译出的DLL
根据导出函数定义进行声明:
1 2 3 4 5 |
[DllImport("exportgo.dll", EntryPoint = "PrintBye")] static extern void PrintBye(); [DllImport("exportgo.dll", EntryPoint = "Sum")] static extern int Sum(int a, int b); |
然后调用:
1 2 3 4 5 6 7 |
private void button_SaveSetting_Click(object sender, EventArgs e) { Console.WriteLine("Call go dll test"); PrintBye(); Console.WriteLine(Sum(33, 22)); } |
将DLL文件与.Net编译出的可执行文件放在一起执行,并观察stdout的输出:

.Net调用Go语言DLL测试
参考资料:
1、https://stackoverflow.com/questions/40573401/building-a-dll-with-go-1-7
2、https://my.oschina.net/bfbd/blog/1622767
3、https://blog.csdn.net/rtduq/article/details/80340461
4、https://blog.csdn.net/xulingyun20032003/article/details/81220098
转载时请保留出处,违法转载追究到底:进城务工人员小梅 » Windows环境下将Go语言编译为DLL并供.Net调用