Skip to content

Instantly share code, notes, and snippets.

@nmarley
Last active April 4, 2024 16:47
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save nmarley/6d4dadc002ff99dd4835bd34c6b025c7 to your computer and use it in GitHub Desktop.
Save nmarley/6d4dadc002ff99dd4835bd34c6b025c7 to your computer and use it in GitHub Desktop.
Go / C++ bindings example

Go / C++ bindings example

This is an example of Go code calling to a C++ library with a C wrapper.

Build

go build  # this only ensures it compiles

Test

go test  # actually runs tests
// num.cpp
#include "nummer.hpp"
#include "num.h"
Num NumInit() {
cxxNum * ret = new cxxNum(1);
return (void*)ret;
}
void NumFree(Num n) {
cxxNum * num = (cxxNum*)n;
delete num;
}
void NumIncrement(Num n) {
cxxNum * num = (cxxNum*)n;
num->Increment();
}
int NumGetValue(Num n) {
cxxNum * num = (cxxNum*)n;
return num->GetValue();
}
package num
// #cgo LDFLAGS: -L. -lstdc++
// #cgo CXXFLAGS: -std=c++14 -I.
// #include "num.h"
import "C"
import "unsafe"
type GoNum struct {
num C.Num
}
func New() GoNum {
var ret GoNum
ret.num = C.NumInit()
return ret
}
func (n GoNum) Free() {
C.NumFree((C.Num)(unsafe.Pointer(n.num)))
}
func (n GoNum) Inc() {
C.NumIncrement((C.Num)(unsafe.Pointer(n.num)))
}
func (n GoNum) GetValue() int {
return int(C.NumGetValue((C.Num)(unsafe.Pointer(n.num))))
}
// num.h
#ifdef __cplusplus
extern "C" {
#endif
typedef void* Num;
Num NumInit(void);
void NumFree(Num);
void NumIncrement(Num);
int NumGetValue(Num);
#ifdef __cplusplus
}
#endif
package num
import (
"reflect"
"testing"
)
func TestNum(t *testing.T) {
num := New()
num.Inc()
if num.GetValue() != 2 {
t.Error("unexpected value received")
}
num.Inc()
num.Inc()
num.Inc()
if num.GetValue() != 5 {
t.Error("unexpected value received")
}
value := num.GetValue()
num.Free()
typ := reflect.TypeOf(value)
if typ.Name() != "int" {
t.Error("got unexpected type")
}
}
#include <iostream>
#include "nummer.hpp"
void cxxNum::Increment(void) {
this->value++;
}
int cxxNum::GetValue(void) {
return this->value;
}
class cxxNum {
private:
int value;
public:
cxxNum(int _num):value(_num){};
~cxxNum(){};
void Increment(void);
int GetValue(void);
};
@danhhuynh1-Tiki
Copy link

Thank you so much. It is great example for me

@januwA
Copy link

januwA commented Dec 8, 2022

I feel that there is no difference between this example and using C. Is there any code using std::string and std::vector?

@paveltrpn
Copy link

I feel that there is no difference between this example and using C. Is there any code using std::string and std::vector?

obvious - in this example c++ code wrapped in c functions, therefore use conteiners in c++ part and wrap it in c code.

@kuoruan
Copy link

kuoruan commented Jul 20, 2023

How can I make it work if I put the nummer.hpp and nummer.cpp file to a sub folder?

├── go.mod
└── num
    ├── num.cpp
    ├── num.go
    ├── num.h
    ├── nummer
    │   ├── nummer.cpp
    │   └── nummer.hpp
    └── num_test.go

The num.cpp is like:

#include "nummer/nummer.hpp"
#include "num.h"

// ......

I get some error:

/usr/lib/go-1.20/pkg/tool/linux_amd64/link: running g++ failed: exit status 1
/usr/bin/ld: /tmp/go-link-1235907040/000002.o: in function `NumIncrement':
/Go/cpp/num/num.cpp:16: undefined reference to `cxxNum::Increment()'
/usr/bin/ld: /tmp/go-link-1235907040/000002.o: in function `NumGetValue':
/Go/cpp/num/num.cpp:21: undefined reference to `cxxNum::GetValue()'
collect2: error: ld returned 1 exit status

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment