marcman
marcman

Reputation: 3393

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++...

Upvotes: 3

Views: 2662

Answers (1)

zzn
zzn

Reputation: 2465

  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.

Upvotes: 2

Related Questions