I'm using C++ classes in Lua which I wrapped using SWIG.
Since I'm using a single Lua_State, I would like to be able to free variables in a specific chunk of Lua script without calling lua_close(L).
I decided to use package.preload['name'] so a chunk can be accessed from other chunk by using require 'name' when needed.
And I was told that the variables inside package.preload function are freed after I do the following:
package.preload['name'] = nil
package.loaded['name'] = nil
However, it seems my custom C++ classes are not destructed even after this.
Here's my full example code:
In Main.cpp
#include "Main.h"
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
lua_settop(L, 0);
luaL_dostring(L, "package.preload['test'] = function ()\n"
"local test = {}\n"
"local class = my.Class()\n"
"return test\n"
"end\n");
luaL_dostring(L, "require 'test'");
luaL_dostring(L, "package.preload['test'] = nil\n"
"package.loaded['test'] = nil\n");
}
In Main.h
#include "lua.hpp"
extern "C"
{
int luaopen_my(lua_State *L);
}
int main();
In MyBindings.h
#include "Main.h"
class Class
{
public:
Class()
{
std::cout << "Class Constructed" << std::endl;
};
~Class()
{
std::cout << "Class Destructed" << std::endl;
};
};
In MyBindings.i (SWIG interface to generate MyBindings.cpp)
%module my
%{
#include "MyBindings.h"
%}
%include <stl.i>
%include <typemaps.i>
%include "MyBindings.h"
Result :
Class Constructed
Why is class destructor not called and how to correctly destruct classes and variables inside package.preload function?
I cannot reproduce your problem but you have other shortcomings in your code, most notably the absence of header guards. The file Main.h is not necessary and even less so in the MyBindings.h file because it doesn't make use of it. I don't know which compiler you are using but void main() is not valid C++, the standard dictates int main().
Main.cpp
#include "lua.hpp"
extern "C" int luaopen_my(lua_State *L);
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
lua_settop(L, 0);
luaL_dostring(L, "package.preload['test'] = function ()\n"
"local test = {}\n"
"local class = my.Class()\n"
"return test\n"
"end\n");
luaL_dostring(L, "require 'test'");
luaL_dostring(L, "package.preload['test'] = nil\n"
"package.loaded['test'] = nil\n");
lua_close(L);
}
MyBindings.h
#pragma once
#include <iostream>
class Class
{
public:
Class()
{
std::cout << "Class Constructed" << std::endl;
};
~Class()
{
std::cout << "Class Destructed" << std::endl;
};
};
MyBindings.i
%module my
%{
#include "MyBindings.h"
%}
%include "MyBindings.h"
Example invocation:
$ swig -c++ -lua MyBindings.i
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 -fPIC -shared MyBindings_wrap.cxx -o my.so -llua5.2
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 -L . Main.cpp -l:my.so -llua5.2
$ LD_LIBRARY_PATH=. ./a.out
Class Constructed
Class Destructed
Also you should note that Lua is a garbage collected language, i.e. destructors will run when the garbage collector thinks it is necessary. You can run the garbage collector manually using lua_gc in C or using collectgarbage in Lua but I strongly advise against running the garbage collector manually as this usually impacts performance negatively (even though you ran it manually hoping to increase performance). It only pays off to use the garbage collector manually when you are running in an environment with very limited memory and you have just pruned a table or something like that.
Anyway, I have prepared an example in Lua for you using the my.so module compiled above.
local my = require("my")
local x = my.Class()
print("Info: Deleting x")
x = nil
print("Info: Collecting garbage")
collectgarbage()
print("Info: Done :-)")
$ lua5.2 test.lua
Class Constructed
Info: Deleting x
Info: Collecting garbage
Class Destructed
Info: Done :-)
You can always call the d'tor explicitly byt obj.~class().
If you are using external classes in Lua wrapper, I'm not sire they can follow the correct nested d'tor paradigm which exists in C++.
Related
I am trying to implement some unit tests for a C++ library that does not use OO (all functions are declared at namespace level)
For that purpose, I am trying to create a test binary that mocks (simulate) some functions.
I have achieved the above for functions that I call directly, but I have been unable to replace the calls that the library's functions do. The example below explains this:
Production code
Lets suppose this is the production code, the one that uses the real functions instead of the simulated ones:
CameraHandler.H
namespace Cam {
int myFunc();
int myFunc2();
}
CameraHandler.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc() {
// Imagine this is the function I want to simulate with a mock
// Its mangled name is _ZN3Cam6myFuncEv
return 1;
}
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
Testing code
This is the code for the unit testing. As you can see in the Makefile, it generates a binary called testsMain.
CameraHandlerMock.h
extern "C" {
int __wrap__ZN3Cam6myFuncEv(); // mangled name of Cam::myFunc(), with the __wrap_ prefix.
}
CameraHandlerMock.cpp
#include "CameraHandlerMock.h"
int __wrap__ZN3Cam6myFuncEv(){
// As you can see, the mocked function returns 999 instead of 1.
return 999;
}
UnitTestsMain.cpp
#include <iostream>
#include <typeinfo>
#include "CameraHandler.h"
#include "CameraHandlerMock.h"
extern "C" int _ZN3Cam6myFuncEv();
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
The Makefile
WRAP=-Wl,--wrap,_ZN3Cam6myFuncEv
all: production unitTests
production: // does not matter for this example
g++ main.cpp CameraHandler.cpp -o main
unitTests:
g++ ${WRAP} UnitTestsMain.cpp CameraHandlerMock.cpp CameraHandler.cpp -o testsMain
The problem
If I execute the testsMain program, I obtain the following result:
999 // call to Cam::myFunc()
12 // Cam::myFunc2(), which is Cam::myFunc() + 11.
Taking into account that Cam::myFunc2() calls to Cam::myFunc1(), and I have replaced it by __wrap__ZN3Cam6myFuncEv, what I expect is that t he result of calling Cam::myFunc2() is 999 + 11 = 1010. Nevertheless, Cam::myFunc2() is still calling the non-wrapped Cam::myFunc1(), so the result is 12.
Is there any way to wrap functions that are internally called by the library I want to test?
Let's lint a little bit of fluff first. In UnitTestsMain.cpp,
the declaration:
extern "C" int _ZN3Cam6myFuncEv();
is redundant. It simply instructs the C++ compiler that references to the function
of that prototype whose mangled name is _ZN3Cam6myFuncEv are references to
an externally defined function of that name. This is exactly the same information,
just expressed differently, that that the compiler has already got from:
namespace Cam {
int myFunc();
...
}
when it #include-ed CameraHandler.h, because _ZN3Cam6myFuncEv() is the mangled
form of Cam::myFunc. The extern "C" redeclaration of Cam::myFunc is harmless
but contributes nothing either to compilation or linkage.
On to the main question: Why does your mock
int __wrap__ZN3Cam6myFuncEv() get called instead of int Cam::myFunc in UnitTestsMain.cpp:
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
as you want; but your mock is not called for int Cam::myFunc in CameraHandler.cpp:
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
The answer lies in the documentation of the --wrap linker option:
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be
resolved to __wrap_symbol. Any undefined reference to __real_symbol will be
resolved to symbol.
Maybe you read it and didn't grok the significance of undefined reference.
This means that when --wrap=symbol is in effect, and the linker applies it
to an object file containing undefined references to symbol, it will replace them
with references to __wrap_symbol, and undefined references to __real_symbol,
in that object file, will be replaced with symbol.
Now in UnitTestsMain.o, compiled from UnitTestsMain.cpp, the references to both Cam::myFunc()
and Cam::myFunc2() are undefined. These functions are both defined in CameraHandler.cpp,
compiled in CameraHandler.o.
Therefore in the linkage of UnitTestsMain.o, --wrap ZN3Cam6myFuncEv will take effect and
replace the call to Cam::myFunc ( = ZN3Cam6myFuncEv) with a call to __wrap_ZN3Cam6myFuncEv.
The call to Cam::myFunc2() ( = ZN3Cam7myFunc2Ev) is not wrapped and is unaffected: it will be
resolved to the definition to be found in CameraHandler.o
But in the linkage of CameraHandler.o, both functions are defined, so --wrap has
no effect. When Cam::myFunc2() calls Cam::myFunc(), it calls ZN3Cam6myFuncEv, not
__wrap_ZN3Cam6myFuncEv.
That explains why the program outputs:
999
12
and not:
999
1010
Can you make your mocking work as expected?
Yes. You just have to ensure that every call to Cam::myFunc that you want to be
mocked is compiled into an object file that does not contain the (real) definition
of Cam::myFunc. The obvious way to do that is to define Cam::myFunc in its own
source file. Here's your example fixed:
CameraHandler.h
#ifndef CAMERAHANDLER_H
#define CAMERAHANDLER_H
namespace Cam {
int myFunc();
int myFunc2();
}
#endif
CameraHandlerMock.h
#ifndef CAMERAHANDLERMOCK_H
#define CAMERAHANDLERMOCK_H
extern "C" {
int __wrap__ZN3Cam6myFuncEv();
}
#endif
CameraHandler_myFunc.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc() {
return 1;
}
CameraHandler_myFunc2.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
CameraHandlerMock.cpp
#include "CameraHandlerMock.h"
int __wrap__ZN3Cam6myFuncEv() {
return 999;
}
UnitTestsMain.cpp
#include <iostream>
#include "CameraHandler.h"
#include "CameraHandlerMock.h"
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
Makefile
SRCS := UnitTestsMain.cpp CameraHandler_myFunc.cpp \
CameraHandler_myFunc2.cpp CameraHandlerMock.cpp
OBJS := $(SRCS:.cpp=.o)
LDFLAGS := -Wl,--wrap,_ZN3Cam6myFuncEv
.PHONY: unitTests clean
unitTests: testsMain
testsMain: $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
UnitTestsMain: CameraHandler.h CameraHandlerMock.h
CameraHandler_Func.o CameraHandler_Func2.o: CameraHandler.h
CameraHandlerMock.o: CameraHandlerMock.h
clean:
rm -f $(OBJS) testsMain
(Your production build is not considered at all in this example makefile)
With this, the test build runs like:
$ make
g++ -c -o UnitTestsMain.o UnitTestsMain.cpp
g++ -c -o CameraHandler_myFunc.o CameraHandler_myFunc.cpp
g++ -c -o CameraHandler_myFunc2.o CameraHandler_myFunc2.cpp
g++ -c -o CameraHandlerMock.o CameraHandlerMock.cpp
g++ -Wl,--wrap,_ZN3Cam6myFuncEv -o testsMain UnitTestsMain.o \
CameraHandler_myFunc.o CameraHandler_myFunc2.o CameraHandlerMock.o
and testsMain does what you expect:
$ ./testsMain
999
1010
You can simplify both source files and the makefile somewhat if you rewrite
CameraHandlerMock.cpp as just:
extern "C" {
int __wrap__ZN3Cam6myFuncEv() {
return 999;
}
}
Then you have no need for the mock header file CameraHandlerMock.h at all.
If you have a lot of functions you need to mock in this low-level way, it
may get tedious to define each one in its own source file. You may be aware
that there are higher-level, framework-supported mocking options, e.g. googlemock,
that have rich mocking capabilities and don't entail this tedium. It's fair to say, however, that they may
replace it with more complicated kinds of tedium.
I need to provide data structure pointer in my main program, where I have Lua state defined, to the dynamically loaded Lua module created by wrapping a c++ code using SWIG.
This is my code example:
in SimpleStruct.h:
#pragma once
struct SimpleStruct
{
int a;
double b;
};
in exmaple.h (this one is compiled with SWIG) to Lua library:
#pragma once
#include "SimpleStruct.h"
#include <iostream>
class TestClass
{
public:
TestClass()
{
std::cout<<"TestClass created"<<std::endl;
}
~TestClass() {}
void ReadSimpleStruct(void * tmp)
{
std::cout<<"reading pointer: "<<std::endl;
SimpleStruct * pp = reinterpret_cast< SimpleStruct * >(tmp);
std::cout<<"Simple Struct: " << pp->a << " " << pp->b << std::endl;
}
};
in example.cpp only:
#include "example.h"
and this is my main program (LuaTest.cpp):
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <iostream>
#include "SimpleStruct.h"
int main(int argc, char ** argv)
{
lua_State * L = luaL_newstate();
luaL_openlibs(L);
SimpleStruct * ss = new SimpleStruct();
ss->a = 1;
ss->b = 2;
lua_pushlightuserdata(L,ss);
lua_setglobal( L, "myptr");
int s = luaL_dostring(L, "require('example')");
s = luaL_dostring(L, "mc = example.TestClass()");
s = luaL_dostring(L, "mc:ReadSimpleStruct(myptr)");
if(s)
{
printf("Error: %s \n", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
std::cout<<"done"<<std::endl;
return 0;
}
example.i (copied from Lua examples in SWIG):
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Let's just grab the original header file here */
%include "example.h"
and I compile everything as follows:
swig -c++ -lua example.i
g++ -c -fpic example.cpp example_wrap.cxx -I/usr/local/include -I/usr/include/lua5.2/
g++ -shared example.o example_wrap.o -o example.so
g++ LuaTest.cpp -o luatest -llua5.2 -I/usr/include/lua5.2/ -Wall
on Ubuntu 16.04 (and on osx, with different paths and the same result).
In the last line of Lua script I've got segmentation fault (when I try to access pp->a in "mc:ReadSimpleStruct(myptr)").
So my question is: how can I provide a pointer to c++ object to the loaded Lua library using Lua light userdata?
In general: I have in my main program a class with game parameters and objects, and I would like to provide a pointer to that class to other loaded Lua libraries compiled with a SWIG.
With use of a debugger (or just printing a little extra inside TestClass::ReadSimpleStruct) we can see at least the superficial cause of the segfault quite quickly. The value of the tmp argument to your function is 0x20 on my test setup. That's clearly not right, but understanding why and how to fix it takes a little more investigation.
As a starting point I added one more call to luaL_dostring(L, "print(myptr)") and used a debugger to check that the global variable was indead working as intended. For good measure I added some assert statements after each call to luaL_dostring, because you're actually only checking the return value of the last one, although here that didn't really make any difference.
Having not exactly written much Lua in my life I looked a the documentation for 'Light userdata', which I saw you were using but didn't know what it was. It sounds ideal:
A light userdatum is a value that represents a C pointer (that is, a void * value)
The problem is though that if we inspect the generated example_wrap.cxx file we can see that SWIG is actually trying to be more clever than that and, if we trace the code for arg2 before the generated call to (arg1)->ReadSimpleStruct(arg2) we can see that it's calling SWIG_ConvertPtr (which eventually calls SWIG_Lua_ConvertPtr), which then does:
lua_touserdata(L, index);
//... Some typing stuff from the macro
*ptr=usr->ptr; // BOOM!
I.e. what you're doing is not what SWIG expects to see for void *, SWIG is expecting to manage them all through its typing system as return values from other functions or SWIG managed globals. (I'm slightly surprised that SWIG let this get as far as a segfault without raising an error, but I think it's because void* is being special cased somewhat)
This old question served as quite a nice example to confirm my understanding of lua_pushlightuserdata. Basically we will need to write our own typemap to make this function argument get handled the way you're trying to use it (if you really do want to not let SWIG manage this?). What we want to do is very simple though. The usage case here is also substantially similar to the example I linked, except that the variable we're after when we call lua_touserdata is a function argument. That means it's at a positive offset into the stack, not a negative one. SWIG in fact can tell us what the offset inside our typemape with the $input substitution, so our typemap doesn't only work for the 1st argument to a member function.
So our typemap, which does this for any function argument void * tmp inside our modified example.i file becomes:
%module example
%{
#include "example.h"
%}
%typemap(in) void * tmp %{
$1 = lua_touserdata(L, $input);
%}
%include "example.h"
And that then compiles and runs with:
swig -c++ -lua example.i
g++ -fPIC example_wrap.cxx -I/usr/local/include -I/usr/include/lua5.2/ -shared -o example.so && g++ -Wall -Wextra LuaTest.cpp -o luatest -llua5.2 -I/usr/include/lua5.2/
./luatest
TestClass created
userdata: 0x11d0730
reading pointer: 0x11d0730
Simple Struct: 1 2
done
In continuation to question
how to pass enum values from TCL script to C++ class using Swig
I have following code
1) File : example.i
%module example
%{
/* Put header files here or function declarations like below */
#include "example.h"
%}
%include "example.h"
2 File example.h
class myClass {
public:
enum Type {one,two};
myClass() {}
static bool printVal(int val);
static bool printEnum(Type val);
};
3) File example.cpp
#include "example.h"
#include <iostream>
using namespace std;
bool myClass::printVal(int val) {
cout << " Int Val = " << val << endl;
return 0;
}
bool myClass::printEnum(type val) {
cout << " Enum Val = " << val << endl;
return 0;
}
If I link the swig files in the form of shared library it is working fine
swig -c++ -tcl example.i
g++ -c -fpic example_wrap.cxx example.cpp -I/usr/local/include
g++ -shared example.o example_wrap.o -o example.so
setenv LD_LIBRARY_PATH /pathtoexample.so:$LD_LIBRARY_PATH
tclsh
% load example.so
% myClass_printVal $myClass_one
But if the swig code and example.* files are linked statically I am getting following error
% myClass_printVal $myClass_one
can't read "myClass_one": no such variable
Looking forward for guidance/help
Firstly, if you use more of the path to the shared library, you don't need to alter the LD_LIBRARY_PATH variable. In the case that it's in the current directory (convenient for testing) you can just do this:
load ./example.so
When it's in the same directory as the current script, you instead do this rather longer version:
load [file join [file dirname [info script]] example.so]
# This also probably works:
#load [file dirname [info script]]/example.so
Secondly, you should check what the example has actually created; it might simply be using a different name to what you expect. You can use info commands, info vars and namespace children to find this out; they list the commands, variables and namespaces currently visible.
[EDIT from comments for visibility]: The variables are in the ::swig namespace.
I am embedding a Lua interpreter in a C++ application.
I want to setup an 'environment' for running scripts, such that certain variables are made available to all scripts.
For example, I want to expose READ ONLY objects Foo and FooBar to scripts, such that Foo and FooBar are available to all running scripts.
Does anyone know how I can do this?. A snippet to show how to so this would be very useful.
I haven't heard of read-only variables in Lua but you can prevent modification by making the environment available via a function call instead.
If the C++ application is large, you will probably want to use a tool to generate an interface you can call from Lua. I have used tolua++ in the past with some luck:
Suppose demo.hpp is a header file of the C++ application:
#ifndef SO_DEMO_HPP
#define SO_DEMO_HPP
namespace demo
{
class Foo
{
double x;
public:
Foo(double x) : x(x) {}
double getX() const { return x; }
};
Foo* getFoo();
}
#endif
Implement demo::getFoo() in demo.cpp.
demo.pkg lists the things that should be callable from Lua:
$#include "demo.hpp"
namespace demo
{
class Foo
{
double getX() const;
};
Foo* getFoo();
}
Generate demo_stub.cpp and demo_stub.hpp files containing our Lua module:
$ tolua++5.1 -o demo_stub.cpp -H demo_stub.hpp demo.pkg
main.cpp is a Lua interpreter that loads the demo module:
#include "demo.hpp"
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <tolua++.h>
}
#include "demo_stub.hpp"
int main()
{
lua_State *L = lua_open();
luaL_openlibs(L);
tolua_demo_open(L);
if (luaL_dofile(L, NULL) != 0)
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_close(L);
return 0;
}
The tolua_demo_open() function was generated by tolua++ and is declared in demo_stub.hpp.
Build a Lua interpreter named demo:
$ g++ -I/usr/include/lua5.1 demo.cpp demo_stub.cpp main.cpp -ltolua++5.1 -llua5.1 -o demo
Construct a demo.lua script
print("Hello, world!")
print(tolua.type(demo.getFoo()))
print(demo.getFoo():getX())
and feed the script to the interpreter:
$ ./demo < demo.lua
Hello, world!
demo::Foo
42
lua_setglobal.
As for 'read only', do you mean that that Foo will not be overwritable (e.g. Foo = 10), or that the value Foo reverse will be immutable (e.g. Foo.x = 10)?
In the new Go language, how do I call C++ code? In other words, how can I wrap my C++ classes and use them in Go?
Update: I've succeeded in linking a small test C++ class with Go
If you wrap you C++ code with a C interface you should be able to call your library with cgo (see the example of gmp in $GOROOT/misc/cgo/gmp).
I'm not sure if the idea of a class in C++ is really expressible in Go, as it doesn't have inheritance.
Here's an example:
I have a C++ class defined as:
// foo.hpp
class cxxFoo {
public:
int a;
cxxFoo(int _a):a(_a){};
~cxxFoo(){};
void Bar();
};
// foo.cpp
#include <iostream>
#include "foo.hpp"
void
cxxFoo::Bar(void){
std::cout<<this->a<<std::endl;
}
which I want to use in Go. I'll use the C interface
// foo.h
#ifdef __cplusplus
extern "C" {
#endif
typedef void* Foo;
Foo FooInit(void);
void FooFree(Foo);
void FooBar(Foo);
#ifdef __cplusplus
}
#endif
(I use a void* instead of a C struct so the compiler knows the size of Foo)
The implementation is:
//cfoo.cpp
#include "foo.hpp"
#include "foo.h"
Foo FooInit()
{
cxxFoo * ret = new cxxFoo(1);
return (void*)ret;
}
void FooFree(Foo f)
{
cxxFoo * foo = (cxxFoo*)f;
delete foo;
}
void FooBar(Foo f)
{
cxxFoo * foo = (cxxFoo*)f;
foo->Bar();
}
with all that done, the Go file is:
// foo.go
package foo
// #include "foo.h"
import "C"
import "unsafe"
type GoFoo struct {
foo C.Foo;
}
func New()(GoFoo){
var ret GoFoo;
ret.foo = C.FooInit();
return ret;
}
func (f GoFoo)Free(){
C.FooFree(unsafe.Pointer(f.foo));
}
func (f GoFoo)Bar(){
C.FooBar(unsafe.Pointer(f.foo));
}
The makefile I used to compile this was:
// makefile
TARG=foo
CGOFILES=foo.go
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
foo.o:foo.cpp
g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $# -c $(CGO_CFLAGS) $<
cfoo.o:cfoo.cpp
g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $# -c $(CGO_CFLAGS) $<
CGO_LDFLAGS+=-lstdc++
$(elem)_foo.so: foo.cgo4.o foo.o cfoo.o
gcc $(_CGO_CFLAGS_$(GOARCH)) $(_CGO_LDFLAGS_$(GOOS)) -o $# $^ $(CGO_LDFLAGS)
Try testing it with:
// foo_test.go
package foo
import "testing"
func TestFoo(t *testing.T){
foo := New();
foo.Bar();
foo.Free();
}
You'll need to install the shared library with make install, then run make test. Expected output is:
gotest
rm -f _test/foo.a _gotest_.6
6g -o _gotest_.6 foo.cgo1.go foo.cgo2.go foo_test.go
rm -f _test/foo.a
gopack grc _test/foo.a _gotest_.6 foo.cgo3.6
1
PASS
Seems that currently SWIG is best solution for this:
https://www.swig.org/Doc4.0/Go.html
It supports inheritance and even allows to subclass C++ class with Go struct so when overridden methods are called in C++ code, Go code is fired.
Section about C++ in Go FAQ is updated and now mentions SWIG and no longer says "because Go is garbage-collected it will be unwise to do so, at least naively".
As of go1.2+, cgo automatically incorporates and compiles C++ code:
http://golang.org/doc/go1.2#cgo_and_cpp
You can't quite yet from what I read in the FAQ:
Do Go programs link with C/C++ programs?
There are two Go compiler implementations, gc (the 6g program and friends) and gccgo. Gc uses a different calling convention and linker and can therefore only be linked with C programs using the same convention. There is such a C compiler but no C++ compiler. Gccgo is a GCC front-end that can, with care, be linked with GCC-compiled C or C++ programs.
The cgo program provides the mechanism for a “foreign function interface” to allow safe calling of C libraries from Go code. SWIG extends this capability to C++ libraries.
I've created the following example based on Scott Wales' answer. I've tested it in macOS High Sierra 10.13.3 running go version go1.10 darwin/amd64.
(1) Code for library.hpp, the C++ API we aim to call.
#pragma once
class Foo {
public:
Foo(int value);
~Foo();
int value() const;
private:
int m_value;
};
(2) Code for library.cpp, the C++ implementation.
#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;
}
(3) Code for library-bridge.h the bridge needed to expose a C API implemented in C++ so that go can use it.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void* LIB_NewFoo(int value);
void LIB_DestroyFoo(void* foo);
int LIB_FooValue(void* foo);
#ifdef __cplusplus
} // extern "C"
#endif
(4) Code for library-bridge.cpp, the implementation of the bridge.
#include <iostream>
#include "library-bridge.h"
#include "library.hpp"
void* LIB_NewFoo(int value) {
std::cout << "[c++ bridge] LIB_NewFoo(" << value << ")" << std::endl;
auto 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();
}
(5) Finally, library.go, the go program calling the C++ API.
package main
// #cgo LDFLAGS: -L. -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 main() {
foo := NewFoo(42)
defer foo.Free() // The Go analog to C++'s RAII
fmt.Println("[go]", foo.value())
}
Using the following Makefile
liblibrary.so: library.cpp library-bridge.cpp
clang++ -o liblibrary.so library.cpp library-bridge.cpp \
-std=c++17 -O3 -Wall -Wextra -fPIC -shared
I can run the example program as follows:
$ make
clang++ -o liblibrary.so library.cpp library-bridge.cpp \
-std=c++17 -O3 -Wall -Wextra -fPIC -shared
$ go run library.go
[c++ bridge] LIB_NewFoo(42)
[c++] Foo::Foo(42)
[c++ bridge] LIB_NewFoo(42) will return pointer 0x42002e0
[c++ bridge] LIB_FooValue(0x42002e0)
[c++] Foo::value() is 42
[go] 42
[c++ bridge] LIB_DestroyFoo(0x42002e0)
[c++] Foo::~Foo(42)
Important
The comments above import "C" in the go program are NOT OPTIONAL. You must put them exactly as shown so that cgo knows which header and library to load, in this case:
// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"
Link to GitHub repo with the full example.
Looks it's one of the early asked question about Golang . And same time answers to never update . During these three to four years , too many new libraries and blog post has been out . Below are the few links what I felt useful .
SWIG and Go
Calling C++ Code From Go With SWIG
On comparing languages, C++ and Go
GoForCPPProgrammers
There's talk about interoperability between C and Go when using the gcc Go compiler, gccgo. There are limitations both to the interoperability and the implemented feature set of Go when using gccgo, however (e.g., limited goroutines, no garbage collection).
You're walking on uncharted territory here. Here is the Go example for calling C code, perhaps you can do something like that after reading up on C++ name mangling and calling conventions, and lots of trial and error.
If you still feel like trying it, good luck.
You might need to add -lc++ to the LDFlags for Golang/CGo to recognize the need for the standard library.
The problem here is that a compliant implementation does not need to put your classes in a compile .cpp file. If the compiler can optimize out the existence of a class, so long as the program behaves the same way without it, then it can be omitted from the output executable.
C has a standardized binary interface. Therefore you'll be able to know that your functions are exported. But C++ has no such standard behind it.
Funny how many broader issues this announcement has dredged up. Dan Lyke had a very entertaining and thoughtful discussion on his website, Flutterby, about developing Interprocess Standards as a way of bootstrapping new languages (and other ramifications, but that's the one that is germane here).
This can be achieved using command cgo.
In essence
'If the import of "C" is immediately preceded by a comment, that comment, called the preamble, is used as a header when compiling the C parts of the package. For example:'
source:https://golang.org/cmd/cgo/
// #include <stdio.h>
// #include <errno.h>
import "C"