cgo
ddatsh
cgo 相关
热身
基于C标准库
// demo.go
package main
//#include <stdio.h>
import "C"
func main() {
C.puts(C.CString("Hello, World\n"))
}
go build demo.go
import "C"
启用CGO,并包含<stdio.h>
CGO包的
C.CString将Go字符串转C字符串
调C的
C.puts 输出转换后的C字符串
使用自己的C函数
1. 直接在 go 源码中
package main
/*
#include <stdio.h>
void SayHello(const char* s) {
puts(s);
}
*/
import "C"
func main() {
C.SayHello(C.CString("Hello, World\n"))
}
2. 拆分到 c
// hello.c
#include <stdio.h>
void SayHello(const char* s) {
puts(s);
}
package main
//void SayHello(const char* s);
import "C"
func main() {
C.SayHello(C.CString("Hello, World\n"))
}
cgo作用
- Go 调 C 函数
- 导出Go函数,可以生成 生成静态或动态库,给C用
编译过程
- 预处理:将代码中的引用进行代码替换 main.c -> main.i
- 编译:main.i > 汇编 main.s
- 汇编:main.s > 可重定位的目标文件 main.o
- 链接:main.o 和其他依赖模块组合成可执行文件
编译器编译动态链接 .so 时,用延迟绑定
延迟绑定两个关键数据结构:全局偏移量表(Global Offset Table, GOT)和过程链接表(Procedure Linkage Table, PLT)
c
// dd.h
int Foo(int a,int b);
int Bar();
dd.c
// dd.c
#include "dd.h"
#include <stdio.h>
int Foo(int a,int b) {
return a+b;
}
int Bar() {
printf("hello, I am dd");
return 42
}
main.c
// main.c
#include "dd.h"
#include "stdio.h"
int main() {
printf("1+2=%d\n",Foo(1,2));
Bar();
return 0;
}
静态
gcc main.c dd.c -o main.exe
动态库
gcc -shared -fpic -o dd.dll dd.c
gcc main.c -o main2.exe dd.dll
go
// dd.go
package main
import "C"
import (
"fmt"
)
//export Foo
func Foo(a, b int) int {
return a + b
}
//export Bar
func Bar() {
fmt.Println("I am bar, not foo!")
}
func main() {}
动态库
go build -o ddgo.dll -buildmode=c-shared dd.go
gcc main.c -o main2.exe ddgo.dll
静态库
go build -o ddgo.a -buildmode=c-archive dd.go
gcc main.c -o main4.exe ddgo.a -l winmm -l ntdll -l Ws2_32
Go 的八种 Build Mode
exe
(静态编译)exe
(动态链接libc
)exe
(动态链接libc
和非 Go 代码)pie
地址无关可执行文件(安全特性)c-archive
C 的静态链接库c-shared
C 的动态链接库shared
Go 的动态链接库plugin
Go 的插件
动态库显式调用
https://www.cnblogs.com/Anker/p/3746802.html
http://www.cnblogs.com/mydomain/archive/2012/10/06/2712833.html