BastenGao's Blog - Web, Rails, Ruby, Java

在 Go 语言中调用 C++ 代码


go cgo c c++ cpp 写于2017-12-26, 最后修改 2023-07-25 14:50

上篇博客讲到Go 如何调用 C, 这篇主要讲 Go 如何调用 C++ 。C++ 的代码目前没法内联在 Go 代码里,只能通过外部库方式引用,同时 cgo 也没办法直接调用 C++ 代码, 类也没法 new, 除了 extern “C” 方式声明的函数。所以 Go 要想调用 C++ 代码,可以通过 C 代码调 C++, 然后通过 Go 调 C 代码来实现。下面讲一个具体的例子。

example/
  main.go
  foo/
    foo.h
	foo.cpp
	bridge.h
	bridge.c

foo.h

class Foo {

public:
  Foo();
  ~Foo();

  void bar();
};

foo.cpp

#include <stdio.h>
#include "foo.h"

Foo::Foo() {
}
Foo::~Foo() {
}

void Foo::bar() {
    printf("hello bar\n");
}

bridge.h

#ifdef __cplusplus
extern "C" {
#endif

    void bar();

#ifdef __cplusplus
}
#endif

bridge.c

#include "foo.h"
#include "bridge.h"

void bar() {
    Foo* foo = new Foo();
    foo->bar();
}

以上 foo.h 和 foo.cpp 是 C++ 代码,我们使用 C 语言写个 bridge , 封装下 C++ 调用。

编译静态链接库

cd foo/
g++ -c foo.cpp
g++ -c bridge.c
ar -crs libfoo.a foo.o bridge.o

main.go

package main

// #cgo CFLAGS: -I${SRCDIR}/foo
// #cgo LDFLAGS: -lstdc++ -L${SRCDIR}/foo -lfoo
// #include "bridge.h"
import "C"

func main() {
    C.bar()
}

配置 #cgo 指令和调用 C 外部库一样,唯一需要注意的是 LDFLAGS 参数要加 -lstdc++。另外一个需要注意的地方是 C 语言调用 C++ 的时候头文件需要配置 extern "C" { ... } 大意是按照 C 语言的规范来编译和连接,我的主要工作语言不是 C/C++ 详细参考这篇博客。最后使用 go build 编译 Go 代码。

go build -o out
./out
comments powered by Disqus