Wednesday, June 14, 2017

SWIG for Lua: Reflection

For this blog entry, we show that it is possible for Lua to know about the fields and methods of a C++ struct. This ability for inspection is known as reflection in the programming world. Only basic reflection is demonstrated here; that is, only basic information is extracted from the C++ struct.

First, we define the C++ struct in the header file, example.hpp:

struct Point
{
int x;
int y;
void greet();
};
view raw example.hpp hosted with ❤ by GitHub
The struct implementation is defined in example.cpp:

#include "example.hpp"
#include <cstdio>
void Point::greet()
{
printf("x=%d, y=%d\n", x, y);
}
view raw example.cpp hosted with ❤ by GitHub
We then define the interface file, example.i, to be used by SWIG:

%module example
%{
/* Includes the header in the wrapper code */
#include "example.hpp"
%}
/* Parse the header file to generate wrappers */
%include "example.hpp"
view raw example.i hosted with ❤ by GitHub
After which, we use SWIG to generate the wrapper file:

% swig -lua -c++ example.i

We then compile the C++ source files and create the shared object to be used by our Lua script:

% g++ -fPIC -I/usr/include/lua5.2 -c example_wrap.cxx -o example_wrap.o
% g++ -fPIC -c example.cpp -o example.o
% g++ -shared -I/usr/include/lua5.2 example.o example_wrap.o -o example.so

We then write a Lua script, test.lua, for testing:

#!/usr/bin/lua
package.loadlib('./example.so', 'luaopen_example')()
A = example.Point()
A.x = 101
A.y = 202
print(A.x)
print(A.y)
A:greet()
print(swig_type(A.x))
print(swig_type(A.y))
print(swig_type(A.greet))
m = getmetatable(A)
print('/***** struct metatable *****/')
for k, v in pairs(m) do
print(k, v)
end
g = m['.get']
print('/***** struct fields *****/')
for k, v in pairs(g) do
print(k, v)
end
fn = m['.fn']
print('/***** struct methods *****/')
for k, v in pairs(fn) do
print(k, v)
end
view raw test.lua hosted with ❤ by GitHub
When run:

% ./test.lua
101
202
x=101, y=202
number
number
function
/***** struct metatable *****/
.type Point
__gc function: 0x7fced2eaf0a1
.get table: 0xf14c60
__tostring function: 0x7fced2eaf140
__newindex function: 0x7fced2eaef9f
.static table: 0xf15010
__eq function: 0x7fced2eaf29b
__index function: 0x7fced2eaeb93
.set table: 0xf15060
.fn table: 0xf150a0
.bases table: 0xf14c20
/***** struct fields *****/
y function: 0x7fced2eb1f9b
x function: 0x7fced2eb1b2f
/***** struct methods *****/
__disown function: 0x7fced2eaf234
greet function: 0x7fced2eb219a
view raw output.txt hosted with ❤ by GitHub
Lines 20-24 of test.lua print the names of the fields of the struct. Note that the order of the printing of the field names (lines 21-22 of output.txt) may not be the same as the order of declaration of the fields in the C++ struct definition in example.hpp (lines 3-4).

Lines 26-30 print the names of the methods of the struct.

Hope this helps the world.

SWIG for Lua: Class demonstration

In this entry, we demonstrate how to expose a C++ class to Lua using SWIG. The environment I use is Ubuntu 16.04.

First, we define the C++ class in example.hpp:

class MyClass
{
public:
MyClass(int a, int b);
void greet();
private:
int x;
int y;
};
view raw example.hpp hosted with ❤ by GitHub
The class implementation is defined in example.cpp:

#include <example.hpp>
#include <ctime>
#include <cstdio>
MyClass::MyClass(int a, int b): x(a), y(b) {}
void MyClass::greet()
{
printf("Hello, world: x=%d y=%d\n", x, y);
}
view raw example.cpp hosted with ❤ by GitHub
Then, we define the interface file, example.i, to be used by SWIG:

%module example
%{
/* Includes the header in the wrapper code */
#include "example.hpp"
%}
/* Parse the header file to generate wrappers */
%include "example.hpp"
view raw example.i hosted with ❤ by GitHub
We then use SWIG to generate the wrapper file, example_wrap.cxx:

% swig -lua -c++ example.i

Next, we compile the C++ source files:

% g++ -fPIC -I/usr/include/lua5.2 -c example_wrap.cxx -o example_wrap.o
% g++ -fPIC -I. -c example.cpp -o example.o

Then, we create the shared object, example.so:

% g++ -shared -I/usr/include/lua5.2 example_wrap.o example.o -o example.so

We write a Lua script to test if SWIG works:

#!/usr/bin/lua
package.loadlib('./example.so', 'luaopen_example')()
A = example.MyClass(6, 7)
A:greet()
view raw test.lua hosted with ❤ by GitHub
When run:

% ./test.lua
Hello, world: x=6 y=7

Hope this helps the world.

Compiling and running SWIG for Lua in Ubuntu 16.04 using C++

This blog entry is quite similar to my previous entry. The difference is that this entry uses C++ source files instead of C.

We first start with the C++ header file:

extern double My_variable;
int fact(int n);
int my_mod(int x, int y);
char *get_time();
view raw example.hpp hosted with ❤ by GitHub
Notice the use of extern for the declaration of the global variable, since we are dealing with C++ here and not C.

We then create the C++ implementation file:

#include <example.hpp>
#include <ctime>
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);
}
view raw example.cpp hosted with ❤ by GitHub
Then we create the interface file for SWIG:

%module example
%{
/* Includes the header in the wrapper code */
#include "example.hpp"
%}
/* Parse the header file to generate wrappers */
%include "example.hpp"
view raw example.i hosted with ❤ by GitHub
We then call SWIG to generate the wrapper file:

% swig -lua -c++ example.i

Notice the use of the -c++ argument.

Next, we compile the wrapper file:

% g++ -fPIC -I/usr/include/lua5.2 -c example_wrap.cxx -o example_wrap.o

Notice that the generated wrapper file has the file suffice .cxx

We then compile the C++ implementation file:

% g++ -fPIC -I. -c example.cpp -o example.o

Finally, we create the shared object to be used by our Lua script:

% g++ -shared -I/usr/include/lua5.2 example_wrap.o example.o -o example.so

We write a Lua script for testing:

package.loadlib('./example.so', 'luaopen_example')()
print(example.My_variable)
print(example.fact(5))
print(example.my_mod(5, 3))
print(example.get_time())
view raw test.lua hosted with ❤ by GitHub
When run:

% lua test.lua
3
120
2
Wed Jun 14 16:41:11 2017

Hope this helps the world. :)

Compiling and running SWIG for Lua in Ubuntu 16.04 for the truly lazy

Previously, we were able to compile and run SWIG for Lua in Ubuntu 16.04 using a C source file. In this blog entry, we want to do something very similar except that we use a C header file.

We begin with the files needed starting with the header file, example.h:

double My_variable;
int fact(int n);
int my_mod(int x, int y);
char *get_time();
view raw example.h hosted with ❤ by GitHub
Then, we create the C implementation file, example.c:

#include <example.h>
#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);
}
view raw example.c hosted with ❤ by GitHub
Finally, we create the interface file, example.i, which is needed by SWIG:

%module example
%{
/* Includes the header in the wrapper code */
#include "example.h"
%}
/* Parse the header file to generate wrappers */
%include "example.h"
view raw example.i hosted with ❤ by GitHub
Notice how much simpler this interface file is compared to the previous one. This is why this entry has a subclause "for the truly lazy".

We then call SWIG to create the wrapper file, example_wrap.c:

% swig -lua example.i

Then we compile the generated wrapper file:

% gcc -fPIC -I/usr/include/lua5.2 -c example_wrap.c -o example_wrap.o

We also compile the C source file, example.c:

% gcc -fPIC -I. -c example.c -o example.o

Finally, we create the shared object which is to be used by our Lua script:

% gcc -shared -I/usr/include/lua5.2 example_wrap.o example.o -o example.so

The Lua script is just the same as our previous blog entry. For convenience:

package.loadlib('./example.so', 'luaopen_example')()
print(example.My_variable)
print(example.fact(5))
print(example.my_mod(5, 3))
print(example.get_time())
view raw test.lua hosted with ❤ by GitHub
When run:

% lua test.lua
3
120
2
Wed Jun 14 14:56:54 2017

Hope this helps the world. :)

Compiling and running SWIG for Lua in Ubuntu 16.04

As a disclaimer, this blog entry is adapted from:

http://www.swig.org/tutorial.html
http://www.swig.org/Doc2.0/Lua.html#Lua_nn5

Let's begin. first, you need to have SWIG installed:

% sudo apt-get install swig

You also need to have Lua installed. Say, Lua 5.2:

% sudo apt-get install lua5.2

Let us consider the following file, example.c, whose functions and variable we wish to use in Lua:

#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);
}
view raw example.c hosted with ❤ by GitHub
Then, we need to create an interface file, say, example.i:

%module example
%{
/* 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();
view raw example.i hosted with ❤ by GitHub
After creating the files, we use SWIG to create a wrapper file:

% swig -lua example.i

This creates a wrapper file named example_wrap.c.

Now it is time to compile the C files:

% gcc -fPIC -I/usr/include/lua5.2 -c example_wrap.c -o example_wrap.o
% gcc -fPIC -c example.c -o example.o

Then we create the shared object which shall be used by our Lua script:

% gcc -shared -I/usr/include/lua5.2 example_wrap.o example.o -o example.so

This creates the shared object, example.so.

Finally, we create our Lua script to test if Lua can call the C functions and variable:

package.loadlib('./example.so', 'luaopen_example')()
print(example.My_variable)
print(example.fact(5))
print(example.my_mod(5, 3))
print(example.get_time())
view raw test.lua hosted with ❤ by GitHub

When run, this is the output:

% lua test.lua
3
120
2
Wed Jun 14 14:56:54 2017

Hope this helps the world. :)