1

I am new to SWIG and I am trying some tutorials but running into compilation issues.

The functions I am trying to wrap (ex.cxx) :

 #include <time.h>
 double My_variable = 3.0;
 
 int fact(int n) {
     if (n <= 1) return 1;
     else return n*fact(n-1);
 }
 
 int my_mod(int x, int y) {
     return (x%y);
 }
    
 char *get_time()
 {
     time_t ltime;
     time(&ltime);
     return ctime(&ltime);
 }

the SWIG wrapper definition (ex.i) :

%module ex
 %{
 /* Put header files here or function declarations like below */
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();
 %}
 
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();

the minimal setup to call the wrappers (min.cxx) :

#include <stdio.h>
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#include <string.h>
//#include "ex_wrap.cxx"

extern "C" {
extern int luaopen_ex(lua_State* L); // declare the wrapped module
}

int main(int argc,char* argv[]) {
  char buff[256];
  int error;
    
  lua_State *L;
  if (argc<2) {
    printf("%s: <filename.lua>\n",argv[0]);
    return 0;
  }
  L=luaL_newstate();    // https://stackoverflow.com/questions/8552560/embedding-lua-in-c
  luaL_openlibs(L); // load basic libs (eg. print)
  luaopen_ex(L);    // load the wrappered module
  if (luaL_loadfile(L,argv[1])==0) // load and run the file
    lua_pcall(L,0,0,0);
  else
    printf("unable to load %s\n",argv[1]);
  /*while (fgets(buff, sizeof(buff), stdin) != NULL) {
    error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
            lua_pcall(L, 0, 0, 0);
    if (error) {
      fprintf(stderr, "%s", lua_tostring(L, -1));
      lua_pop(L, 1);  // pop error message from the stack
    }
  }*/
    
  lua_close(L);
  return 0;
}

and the compile commands :

swig -debug-symtabs -debug-symbols -debug-csymbols -o ex_wrap.cxx -c++ -lua ex.i 
clang -std=c++11 -I/usr/local/include/lua -c min.cxx -o min.o
clang -std=c++11 -fvisibility=default -I/usr/local/include/lua -c ex_wrap.cxx -o ex_wrap.o
clang -std=c++11 -c ex.cxx -o ex.o
clang -std=c++11 -I/usr/local/include/lua -L/usr/local/lib/lua -llua ex_wrap.o min.o ex.o -o mylua
clang -shared -std=c++11 -I/usr/local/include/lua -L/usr/local/lib/lua -llua min.o ex.o -o ex.so

The last command fails with

Undefined symbols for architecture x86_64:
  "_luaopen_ex", referenced from:
      _main in min.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

luaopen_ex() is defined in the ex_wrap.cxx generated by the swig command, but the linker cannot seem to find it. BTW, if I include ex_wrap.cxx directly into min.cxx, it compiles and I can run Lua code with this mini interpreter afterwards. Any ideas, thank you.

ihi
  • 107
  • 1
  • 9

2 Answers2

0

it's a linking failure error, and it happens because it can't link luaopen_example, but why it happens? luaopen_example is to load the wrapped module as you mentioned and it's named "example" only if the module name is the same.

in swig and lua wrapper, the wrapper name depends on the file to be wrapped name, but if you don't want to go this way, you can use the option -o, then the wrappered module will export one function "int luaopen_example(lua_State* L)" which must be called to register the module with the Lua interpreter. The name "luaopen_example" depends upon the name of the module.

so i suggest you just keep the name of the wrapper derived from the module, or you can adjust the loading function luaopen_xxxx to your wrapper name.

for full resource you can take a look at SWIG and Lua

walid barakat
  • 455
  • 1
  • 6
  • 17
  • The wrappered module seems to export luaopen_ex as a #define SWIG_init. The link you posted is out of date for Lua > 5.0 (see my code). – ihi Jun 13 '21 at 03:12
  • i saw your code. there's no "luaopen_ex". i'm not sure if you posted the whole code, and the link i posted not outdated because it talks about SWIG implementation for lua 5.0.x and 5.1.x. and you need to have relative files and module names. so you either use "ex" or "example". in addition if you want to compile and link using g++, you need to use cxx extension not c. – walid barakat Jun 13 '21 at 12:20
  • ok, my mistake, "luaopen_example" (my understanding is that the exported function would be called "luaopen_module", where "module" would the name of the exported SWIG module). I tried both .cxx and .c, same issue. – ihi Jun 17 '21 at 15:12
  • but you make sure about the names of modules are related and still the same issue? if yes, can you please update the code in question and the same error message? it'll look the same for you but it may have hidden hints in it – walid barakat Jun 18 '21 at 07:29
0

luaopen_example is defined in an extern "C" {} block in ex_wrap.cxx, but compiling ex.c with g++ declares luaopen_example as a C++ function, so the linker looks for a C++ mangled name to resolve luaopen_example(lua_State*) and not simply luaopen_example

Change your declaration in ex.c to

extern "C" {
 extern int luaopen_example(lua_State* L); // declare the wrapped module
}

and the code will compile.

( You might be also be interested in the answer to this question, which explains name mangling: What is the effect of extern "C" in C++? )

Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83
  • This is the answer - with the observation that luaopen_example() is #define'd as SWIG_init and SWIG_init() is actually inside an extern "C" block. Thank you. – ihi Jun 27 '21 at 21:19
  • Nordic Mainframe posted the answer while the bounty was still valid, how do I still award him the reputation points ? Thank you. – ihi Jun 27 '21 at 21:21