目录结构

[root@localhost example03]# tree
.
├── library
│   ├── library-bridge.cpp
│   ├── library-bridge.h
│   ├── library.cpp
│   ├── library.hpp
└── main.go

各文件对应的代码

library.hpp

#pragma once
#include <string>
using namespace std;
class Foo {
 public:
  Foo(int value);
  ~Foo();
  int value() const;
  string testString(string params);  
 private:
  int m_value;
};

library.cpp

#include "library.hpp"
#include <iostream>

Foo::Foo(int value) : m_value(value) {
  std::cout << "[c++] Foo::Foo(" << m_value << ")" << std::endl;
}

Foo::~Foo() { std::cout << "[c++] Foo::~Foo(" << m_value << ")" << std::endl; }

int Foo::value() const {
  std::cout << "[c++] Foo::value() is " << m_value << std::endl;
  return m_value;
}

string Foo::testString(string params) {
  std::cout << "[c++] testString params is " << params << std::endl;
  return params + " world!";
}

library-bridge.h

#pragma once
#ifdef __cplusplus
extern "C" {
#endif

void* LIB_NewFoo(int value);
void LIB_DestroyFoo(void* foo);
int LIB_FooValue(void* foo);
const char* LIB_TestString(char* params);

#ifdef __cplusplus
}  // extern "C"
#endif

library-bridge.cpp

#include <iostream>

#include "library-bridge.h"
#include "library.hpp"

void* LIB_NewFoo(int value) {
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ")" << std::endl;
  Foo* foo = new Foo(value);
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ") will return pointer "
            << foo << std::endl;
  return foo;
}

// Utility function local to the bridge's implementation

Foo* AsFoo(void* foo) { return reinterpret_cast<Foo*>(foo); }

void LIB_DestroyFoo(void* foo) {
  std::cout << "[c++ bridge] LIB_DestroyFoo(" << foo << ")" << std::endl;
  AsFoo(foo)->~Foo();
}

int LIB_FooValue(void* foo) {
  std::cout << "[c++ bridge] LIB_FooValue(" << foo << ")" << std::endl;
  return AsFoo(foo)->value();
}

const char* LIB_TestString(char* params) {
  std::cout << "[c++ bridge] LIB_TestString params is " << params << std::endl;
  Foo foo(1);
  return foo.testString(params).c_str();
  //return const_cast<char*>(foo.testString(params).c_str());
  //return new Foo()->testString(params);
}

main.go

package main

// #cgo CFLAGS: -I${SRCDIR}/library
// #cgo LDFLAGS: -lstdc++ -L./library -llibrary
// #include "./library-bridge.h"
import "C"
import "unsafe"
import "fmt"

type Foo struct {
    ptr unsafe.Pointer
}

func NewFoo(value int) Foo {
    var foo Foo
    foo.ptr = C.LIB_NewFoo(C.int(value))
    return foo
}

func (foo Foo) Free() {
    C.LIB_DestroyFoo(foo.ptr)
}

func (foo Foo) value() int {
    return int(C.LIB_FooValue(foo.ptr))
}

func (foo Foo) testString(params string) string {
    return C.GoString(C.LIB_TestString(C.CString(params)))
}

func main() {
    foo := NewFoo(42)
    defer foo.Free() // The Go analog to C++'s RAII
    fmt.Println("[go]", foo.value())
    fmt.Println("----------------------")  
    params := "gohello"
    result := foo.testString(params)
    fmt.Println("string result = ", result)
}

方式一:调用静态链接库

编译静态链接库

cd library/
g++ -c library.cpp
g++ -c library-bridge.cpp
ar -crs liblibrary.a library.o library-bridge.o

编译完成后代码结构如下所示:

[root@localhost example03]# tree
.
├── library
│   ├── liblibrary.a
│   ├── library-bridge.cpp
│   ├── library-bridge.h
│   ├── library-bridge.o
│   ├── library.cpp
│   ├── library.hpp
│   └── library.o
└── main.go

运行

go run main.go

可得到如下结果:

[root@localhost example03]# go run main.go 
[c++ bridge] LIB_NewFoo(42)
[c++] Foo::Foo(42)
[c++ bridge] LIB_NewFoo(42) will return pointer 0x236d2d0
[c++ bridge] LIB_FooValue(0x236d2d0)
[c++] Foo::value() is 42
[go] 42
----------------------
[c++ bridge] LIB_TestString params is gohello
[c++] Foo::Foo(1)
[c++] testString params is gohello
[c++] Foo::~Foo(1)
string result =  gohello world!
[c++ bridge] LIB_DestroyFoo(0x236d2d0)
[c++] Foo::~Foo(42)
[root@localhost example03]# 

方式二:调用动态链接库

生成动态链接库

gcc -fpic -shared library.cpp library-bridge.cpp -o liblibrary.so

运行

go run main.go

注意:调用动态库会有加载不到的情况

error while loading shared libraries: liblibrary.so: cannot open shared object file: No such file or directory

可以结合这篇文章来设置:https://blog.csdn.net/kenkao/article/details/93026902
配置完成后,需要运行ldconfig

参考文章

  • https://stackoverflow.com/questions/1713214/how-to-use-c-in-go
  • https://bastengao.com/blog/2017/12/go-cgo-cpp.html
  • https://blog.csdn.net/Eric_zhang929/article/details/104926330
  • https://blog.csdn.net/kenkao/article/details/93026902