用golang调用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))
}
编译:
- 在cpp文件夹下运行
g++ -o liba.so -shared -fPIC a.cpp
有其他cpp源文件需要编译加后面即可
重要:拷贝.so到main.go同级目录 - 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