【导读】golang 如果依赖外部动态链接库要如何引入?本文做了详细介绍。
如果你有一个 c++做的动态链接库。so 文件,而你只有一些相关类的声明,那么你如何用 c 调用呢,
C++创始人在编写 C++的时候,C 语言正盛行,他不得不让 C++兼容 C。C++最大的特性就是封装,继承,多态,重载。而这些特性恰恰是 C 语言所不具备的。至于多态,核心技术是通过虚函数表实现的,其实也就是指针。而对于重载,与 C 语言相比,其实就是编译方式不同而已:C++编译方式和 C 编译方式。
对于函数调用,编译器只要知道函数的参数类型和返回值以及函数名就可以进行编译连接。那么为了让 C 调用 C++接口或者是说 C++调用 C 接口,就必须是调用者和被调用者有着同样的编译方式。
这既是 extern “C”的作用,extern “C”是的程序按照 C 的方式编译。
/var/www/cgo_test/student.h
#include <iostream>
using namespace std;
class Student {
public:
Student(){}
~Student(){}
void Operation();
void SetName(string name);
string name;
};
/var/www/cgo_test/student.cpp
using namespace std;
void Student::Operation()
{
cout << "Hi my name is " << name <<endl;
}
void Student::SetName(string name1)
{
name = name1;
}
/var/www/cgo_test/interface.h
#ifdef __cplusplus
extern "C"{
#endif
void *stuCreate();
void initName(void *, char* name);
void getStuName(void *);
void getName();
#ifdef __cplusplus
}
#endif
/var/www/cgo_test/interface.cpp
#include "student.h"
#include "interface.h"
#ifdef __cplusplus
extern "C"{
#endif
void *stuCreate()
{
return new Student(); //构造
}
void getStuName(void *p)
{
static_cast<Student *>(p)->Operation();
}
void initName(void *p, char* name1)
{
static_cast<Student *>(p)->SetName(name1);
}
void getName()
{
Student obj;
obj.Operation();
}
#ifdef __cplusplus
}
#endif
#include "interface.h"
int main()
{
void *p = stuCreate();
char *name = "test";
initName(p, name);
getStuName(p);
getName();
return 0;
}
g++ student.cpp interface.cpp -fPIC -shared -o libstu.so
gcc main.c -L. -lstu
到这里,c 已经成功调用 c++代码
执行结果
Hi my name is test Hi my name is
其中,上面步骤 2 时可以会报错
error while loading shared libraries: libstu.so: cannot open shared object file: No such file or directory
解决方法 more
vim /etc/ld.so.conf.d/test.conf
/var/www/cgo_test
/var/www/cgo_test/test.go
// +build linux
// +build amd64
// +build !noptlogin
package main
/*
#cgo CFLAGS: -I./
#cgo LDFLAGS: -L./ -lstu
#include <stdlib.h>
#include <stdio.h>
#include "interface.h" //非标准 c 头文件,所以用引号
*/
import "C"
import(
"unsafe"
)
func main() {
name := "test!"
cStr := C.CString(name)
defer C.free(unsafe.Pointer(cStr))
obj := C.stuCreate()
C.initName(obj, cStr)
C.getStuName(obj)
}
然后直接执行 go run test.go
时会报错
package main: build constraints exclude all Go files in /var/www/cgo_test
/usr/bin/ld: skipping incompatible ./lib/libstu.so when searching for -lstu
/usr/bin/ld: cannot find -lstu
collect2: error: ld returned 1 exit status
解决方法
go 可能默认不支持 cgo,go env
可查看相关配置,可通过显示指定 CGO_ENABLED=1
、GOARCH=amd64
解决
GOARCH=amd64 GOOS=linux CGO_ENABLED=1 go ru n test.go
执行结果
Hi my name is test!
转自:
aibenlin.com/golang/2019/09/05/golang-cgo_call_c++.html
- EOF -
Go 开发大全
参与维护一个非常全面的Go开源技术资源库。日常分享 Go, 云原生、k8s、Docker和微服务方面的技术文章和行业动态。
关注后获取
回复 Go 获取6万star的Go资源库
分享、点赞和在看
支持我们分享更多好文章,谢谢!