marcman marcman - 3 months ago 18
C++ Question

How do you load a custom module into Lua?

This has been driving me nuts for a long time now. I have followed every tutorial I could find on the internet (here are couple examples[ [1], [2] of the maybe half dozen good ones found via Google search), and still no clear explanation. Although it seems it must be something fairly simple as that lack of a documented explanation implies that it's something most people would take for granted.

How do I load a custom module into Lua?

On the advice of questions like this one, I have written a module that builds a shared library with the expectation that I would be able to load it through a

require
call. However, when I do that I get undefined symbol errors, despite those exact symbols appearing in the list from the command
nm -g mylib.so
.

Those two tutorials I linked before aim to create executables that look wrappers of the
*.lua
file. That is, the built
*.exe
file should be called to run the Lua program with the custom module.

I understand that these types questions are asked here fairly frequently (as noted in this answer), but I am still at a loss. I tried some of the binding packages (Luabind and OOLua), but those didn't work out great (e.g. my earlier question--which I did ultimately figure out, sort of).


  1. I have implemented a class in C++

  2. I have wrapped the constructors, destructors, and functions with thunks

  3. I have built it errorless-ly as a shared library



Yet no matter what I get
undefined symbol: ...
errors when I try to load it as
mod = require('mylib.so')
. How do I do this?




Working Example of a Library of Functions

For the record, just registering a basic function works fine. The below code, when built as
libluatest.so
, can be run in Lua using the commands:

> require('libluatest')
> greet()
hello world!


libluatest.cpp

extern "C"
{
#include <lualib.h>
#include <lauxlib.h>
#include <lua.h>
}

#include <iostream>

static int greet(lua_State *L)
{
std::cout << "hello world!" << std::endl;
return 0;
}

static const luaL_reg funcs[] =
{
{ "greet", greet},
{ NULL, NULL }
};


extern "C" int luaopen_libluatest(lua_State* L)
{
luaL_register(L, "libluatest", funcs);
return 0;
}





Failing Example of a Class

This is what I am stuck on currently. It doesn't seem to want to work.

myObj.h

#include <string>
class MyObj
{
private:
std::string name_;

public:
MyObj();
~MyObj();

void rename(std::string name);
};


myObj.cpp

extern "C"
{
#include <lualib.h>
#include <lauxlib.h>
#include <lua.h>
}
#include <iostream>
#include "myObj.h"

void MyObj::rename(std::string name)
{
name_ = name;
std::cout << "New name: " << name_ << std::endl;
}

extern "C"
{
// Lua "constructor"
static int lmyobj_new(lua_State* L)
{
MyObj ** udata = (MyObj **)lua_newuserdata(L, sizeof(MyObj));
*udata = new MyObj();
luaL_getmetatable(L, "MyObj");
lua_setmetatable(L, -1);
return 1;
}

// Function to check the type of an argument
MyObj * lcheck_myobj(lua_State* L, int n)
{
return *(MyObj**)luaL_checkudata(L, n, "MyObj");
}

// Lua "destructor": Free instance for garbage collection
static int lmyobj_delete(lua_State* L)
{
MyObj * obj = lcheck_myobj(L, 1);
delete obj;
return 0;
}

static int lrename(lua_State* L)
{
MyObj * obj = lcheck_myobj(L, 1);
std::string new_name = luaL_checkstring(L, 2);
obj->rename(new_name);
return 0;
}

int luaopen_libmyObj(lua_State* L)
{
luaL_Reg funcs[] =
{
{ "new", lmyobj_new }, // Constructor
{ "__gc", lmyobj_delete }, // Destructor
{ "rename", lrename }, // Setter function
{ NULL, NULL } // Terminating flag
};

luaL_register(L, "MyObj", funcs);
return 0;
}
}


Compiled into
libmyObj.so
using a simple CMake build with C++11 standard flags on.

Error

> require('libmyObj')



error loading module 'libmyObj' from file './libmyObj.so':
./libmyObj.so: undefined symbol: _ZN5MyObjC1Ev stack traceback: [C]:
? [C]: in function 'require' stdin:1: in main chunk [C]: ?





I am dealing with Lua 5.1 on Ubuntu 14.04.

I am wondering if it has something to do with the mix of C and C++...

zzn zzn
Answer
  1. It seems that you do not implement:

    MyObj() ; ~MyObj();

  2. and be careful with luaopen_* function, since module name is myObj, function name should be luaopen_libmyObj.