cgo

ddatsh

dev #go

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作用

  1. Go 调 C 函数
  2. 导出Go函数,可以生成 生成静态或动态库,给C用

编译过程

  1. 预处理:将代码中的引用进行代码替换 main.c -> main.i
  2. 编译:main.i > 汇编 main.s
  3. 汇编:main.s > 可重定位的目标文件 main.o
  4. 链接: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

link

动态库显式调用

https://www.cnblogs.com/Anker/p/3746802.html

http://www.cnblogs.com/mydomain/archive/2012/10/06/2712833.html