1

I have the following c++ code for testing:

#include <lua.hpp>
#include <iostream>

static int dummy(lua_State * L)
{
   std::cout << "Test";
   return 0;
} 

int luaopen_testlib(lua_State * L)
{
   lua_register(L,"dummy",dummy);
   return 0;
}

I compile it with commands and it gives me no errors:

g++  -Wextra -O2 -c -o testlib.o main.cpp
g++ -shared -o testlib.so testlib.o 

But when i try to load it in lua i get undefined symbol error as this:

Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> require"testlib"
error loading module 'testlib' from file './testlib.so':
./testlib.so: undefined symbol: _Z16lua_pushcclosureP9lua_StatePFiS0_Ei

It seems for me that there is something missing in the g++ commands, but i have been searching solution for whole morning and can't get this simple example to compile.

EDIT:

after few recompilations it returned to:

error loading module 'testlib' from file './testlib.so':
./testlib.so: undefined symbol: luaopen_testlib

which was solved by adding :

extern "C" 
{
int luaopen_testlib(lua_State *L)
{
  lua_register(L,"dummy",dummy);
  return 0;
}
}
3
  • 4
    I wonder if it might be a name-mangling problem...are you building your code with the same compiler as Lua? Commented Sep 16, 2012 at 7:17
  • Both, lua and gcc, are from archlinux repos. Ou, and i tried simple example from tecgraf.puc-rio.br/~lhf/ftp/lua and it worked fine. Commented Sep 16, 2012 at 7:19
  • possible duplicate of how do I extend Lua with a static c++ library? Commented Sep 16, 2012 at 16:46

3 Answers 3

4
+100

The Lua binary is compiled as C code, the library tries to use it as C++. That will not work as C++ does name mangling to support overloading. As C does not support overloading it does not need the name mangling and will not understand mangled names.

The solution to this is to tell the C++ compiler that the Lua functions it is going to interact with are straight C and they need no name mangling.

Also the luaopen_testlib function must be extern "C" as it will be called from C code with no mangling.

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

static int dummy(lua_State * L)
{
    (void)L;
    std::cout << "Test"<<std::endl;
        return 0;
}

extern "C"
int luaopen_testlib(lua_State * L)
{
    lua_register(L,"dummy",dummy);
        return 0;
}

I ran my test with Lua 5.4.2 and used the following commands to build the library:

g++ -Wall -Wextra -O2 -Isrc -c -fPIC -o testlib.o testlib.cpp
g++ -shared -o testlib.so testlib.o

Note the -Isrc is needed to find lua.h in my test setup and -fPIC was required to use cout in the library (but that may depend on the compiler version used).

and the result is:

Lua 5.4.2  Copyright (C) 1994-2020 Lua.org, PUC-Rio
> require 'testlib'
true    ./testlib.so
> dummy
function: 0x7ff07d2a0aa0
> dummy()
Test
> 

The Lua version used will, in this case, not make any difference.

Sign up to request clarification or add additional context in comments.

2 Comments

Exactly right with the name mangling. Note: if you are writing a Lua library in C, but see the need to potentially compile it as C++ at some point, you can use preprocessor macros to conditionally include the extern "C" {—e.g.: #if defined(__cplusplus) extern "C" #endif /* defined(__cplusplus) */. Just remember to include the closing bracket later on below your functions and type declarations.
Nitpick: Actually, dummy should be an extern "C" function as well, because it is passed as a function pointer to a C API function (lua_register()). Obviously, C API functions can only take extern "C" function pointers, not extern "C++" function pointers. "Fortunately", many compilers are buggy in this regard, so this will work ok at the moment. See e.g. this bug report for g++ for details.
0

Try to use Luabind. Here is the Hello World example

#include <iostream>
#include <luabind/luabind.hpp>

void greet()
{
    std::cout << "hello world!\n";
}

extern "C" int init(lua_State* L)
{
    using namespace luabind;

    open(L);

    module(L)
    [
        def("greet", &greet)
    ];

    return 0;
}

Comments

0

This is how i would compile lua, is not exacly gcc but cmake can use gcc.

.
├── CMakeList.txt (A)
├── main.cpp
├── lua_535
│   ├── CMakeLists.txt (B)
│   └── * lua_content *

main.cpp | Just checks if it works

#include <iostream>
#include <string>

#include "lua.hpp"

int main(){

    lua_State * lua = luaL_newstate();

    std::string str_acction = "a = 5";
    int res = luaL_dostring(lua, str_acction.c_str());
    std::cout << "DS State > " << res << std::endl;

    lua_close(lua);
    return 0;
}

CMakeList.txt (A) | Creates the executable and links the library

cmake_minimum_required(VERSION 3.12)
project(lua_test)

add_executable(main main.cpp)

add_subdirectory("lua_535")
target_link_libraries(main PUBLIC lua_lib)

CMakeList.txt (B) | Joins Lua files into a library

  1. Get the latest lua source files
  2. Extract the content into a sub folder
  3. Add this file into the folder
cmake_minimum_required(VERSION 3.12)
project( lua_lib )

set ( LUA_EMBEDDED ON )
set ( LUA_RUNTIME_MAIN "src/luac.c" )

set (LUA_RUNTIME_SOURCES
    "src/lapi.c"
    "src/lapi.h"
    "src/lauxlib.c"
    "src/lauxlib.h"
    "src/lbaselib.c"
    "src/lbitlib.c"
    "src/lcode.c"
    "src/lcode.h"
    "src/lcorolib.c"
    "src/lctype.c"
    "src/lctype.h"
    "src/ldblib.c"
    "src/ldebug.c"
    "src/ldebug.h"
    "src/ldo.c"
    "src/ldo.h"
    "src/ldump.c"
    "src/lfunc.c"
    "src/lfunc.h"
    "src/lgc.c"
    "src/lgc.h"
    "src/linit.c"
    "src/liolib.c"
    "src/llex.c"
    "src/llex.h"
    "src/llimits.h"
    "src/lmathlib.c"
    "src/lmem.c"
    "src/lmem.h"
    "src/loadlib.c"
    "src/lobject.c"
    "src/lobject.h"
    "src/lopcodes.c"
    "src/lopcodes.h"
    "src/loslib.c"
    "src/lparser.c"
    "src/lparser.h"
    "src/lprefix.h"
    "src/lstate.c"
    "src/lstate.h"
    "src/lstring.c"
    "src/lstring.h"
    "src/lstrlib.c"
    "src/ltable.c"
    "src/ltable.h"
    "src/ltablib.c"
    "src/ltm.c"
    "src/ltm.h"
    "src/lua.c"
    "src/lua.h"
    "src/lua.hpp"
    "src/luaconf.h"
    "src/lualib.h"
    "src/lundump.c"
    "src/lundump.h"
    "src/lutf8lib.c"
    "src/lvm.c"
    "src/lvm.h"
    "src/lzio.c"
    "src/lzio.h"
)
  
add_library( lua_lib "${LUA_RUNTIME_SOURCES}" )

if( NOT LUA_EMBEDDED)
    add_library( lua_lib "${LUA_RUNTIME_MAIN}")
endif()

target_include_directories ( lua_lib PUBLIC "${PROJECT_SOURCE_DIR}/src")

If lua is enbedded src/luac.c should be excluded because conteins a int main(){}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.