golang cgo call c/c++

1. golang call c

目录结构 home/go/src/go-call-c
.
├── a.c
├── a.h
└── main.go

  • a.h
#if !defined(_A_H_)
#define _A_H_
int add(int a, int b);
#endif // _A_H_
  • a.c
#include "a.h"
int add(int a, int b) {
    return a + b;
}
  • main.go
package main

// #cgo CFLAGS: -std=c11
// #cgo LDFLAGS: -L .
// #include "a.h"
import "C"
import "fmt"

func main() {
	fmt.Println("helo")
	fmt.Println(C.add(1, 2))
}

编译:先 go build, 再 run
解析:

  • CFLAGS: -std=c11
    这里可以引入头文件,-I path/to/headers。由于此处都在同一层目录,无需引入
  • #cgo LDFLAGS: -L .
    代表链接当前目录下所编译的库。后面会讲到用-lxxx,表示链接第三方/或自己手动gcc/g++出来的libxxx.so
  • #include “a.h”
    正常引入.h头文件,否则找不到C.add方法

2. golang call c++

这次将c++文件放在单独的文件夹中
目录结构 home/go/src/go-call-cpp
.
├── cpp
│ ├── a.cpp
│ ├── a.h
│ └── build.txt
└── main.go

  • a.h
#if !defined(_A_H_)
#define _A_H_

#ifdef __cplusplus
extern "C" {
#endif

typedef struct Student {
    int age;
    char* name;
} Student;

int add(int a, int b);

void set_name_init(Student* stu);

#ifdef __cplusplus
  }
#endif

#endif // _A_H_

解析(☆重要):cpp中的方法必须 extern “C”,go才能调用,这点和Java/Python一致。

  • a.cpp
#include "a.h"
#include <stdio.h>

int add(int a, int b) {
    printf("%02d%02d\n", a, b);
    return a + b;
}

void set_name_init(Student* stu) {
    stu->age = 10;
    stu->name = "Jim Green";
}
  • build.txt
    这是后面编译.so库的命令,顺手就记在这儿了
g++ -o liba.so -shared -fPIC a.cpp
  • main.go
package main

// #cgo LDFLAGS: -L. -la
// #include "cpp/a.h"
import "C"
import "fmt"

func main() {
	fmt.Println("helo")
	fmt.Println(C.add(1, 2))

	stu := new(C.Student)
	C.set_name_init(stu)
	// stu.name = C.CString("tom")
	fmt.Println(stu.name)
	fmt.Println(C.GoString(stu.name))
}

编译:

  1. 在cpp文件夹下运行
    g++ -o liba.so -shared -fPIC a.cpp
    有其他cpp源文件需要编译加后面即可
    重要:拷贝.so到main.go同级目录
  2. go build

解析:

  • #cgo LDFLAGS: -L. -la
    链接当前目录下(-L.)名叫a的库。库名liba.so,取a;名叫libxxx.so的话,取xxx,即-lxxx

3. golang call c++ 复杂

目录结构 home/go/src/pj-name
.
├── SPP3
│ ├── advmath-impl.h
…各种库源文件
├── main.go
├── nparsecpp
├── stages.cpp
└── stages.h

解析:第三方库头/源文件单独放在SPP3文件夹中,暴露stages.h, stages.cpp给go使用。
注意stages.h中要extern “C”

  • ☆重要main.go
package main

// #cgo CXXFLAGS: -I ./SPP3
// #cgo LDFLAGS: -L .
// #include "stages.h"
import "C"
import "fmt"

func main() {
	fmt.Println("helo")
	fmt.Println(C.add(1, 2))
	o := new(C.spo2_analysis_t)
	fmt.Println(o)
}
  • #cgo CXXFLAGS: -I ./SPP3
    注意是CXXFLAGS,不是CFLAGS,因为编译的是cpp。-I (大写的i) 是引入头文件

  • #cgo LDFLAGS: -L .
    由于所暴露的c源文件和go在同一级,因此可以免去build shared,直接 -L .当前目录即可

编译:go build

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值