This is an example of Go code calling to a C++ library with a C wrapper.
go build # this only ensures it compiles
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); | |
}; |
I feel that there is no difference between this example and using C. Is there any code using
std::string
andstd::vector
?
obvious - in this example c++ code wrapped in c functions, therefore use conteiners in c++ part and wrap it in c code.
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
I feel that there is no difference between this example and using C. Is there any code using
std::string
andstd::vector
?