Binding C++ to Lua Using Swig

Scripts are great. They’re a means of creating executable functionality without the burden of compilation and linking. Sure, that’s a simplification because there’s always some kind of setup required to get scripts going, but compared with working with much lower level languages like C/C++, scripting languages like Lua and Javascript are a refreshing departure from dependency hell.

So why not just use a scripting language all the time?

Answer: Raw, low level, unadulterated power! Okay, so that’s an exaggeration, and there are always tradeoffs when dealing with languages so close to the bits and bytes and hopefully that’s where a scripting language can help us out.

Binding two worlds

For the following examples I’m going to use C++ with Lua, just because I’m a C++ guy and Lua is something that I’ve been meaning to play with for a while. To bind the two together, I’ll be using swig. (Note that swig’s official lua documentation is here)

Here is an analogy to do with building a house. No, let’s make it a skyscraper; a 100 story high skyscraper. Now, that skyscraper isn’t built 100% on site. Much of it is prefabricated off site, and many of the floors are likely to be identical to each others. In summary, there are the following features.

  • The skyscraper is made of prebuilt components
  • The building components could have been made at anytime, by any manufacturer.
  • The building is scalable; so many of the floors are just repeated. Design one floor then stack 99 more on top (let the interior designers do all the showy stuff like paint it lime green or whatever the fashion is for those guys on level 17).

…Okay, so this is starting to look like an example in Object Oriented programming, but bear with me…

Your perfectly modular code that you’ve created in C++ land (because, you know, we all make perfectly modular code) is the equivalent of the components that make up the skyscraper.

So here’s a Skyscraper and Floor class followed by a super basic C++ program that uses them.

#ifndef Skyscraper_H
#define Skyscraper_H

#include <vector>
#include <string>

#include "Floor.h"

class Skyscraper
{
public:
	Skyscraper();
	virtual ~Skyscraper();
	
	void setName(std::string name);
	std::string getName();
	
	const Floor* getFloor(unsigned int floorNumber);
	Floor& addFloor();
	
	void print();
private:
	std::string mName;
	std::vector<Floor> mFloors;
};

#endif // Skyscraper_H
#include "Skyscraper.h"

#include <iostream>

Skyscraper::Skyscraper(){}
Skyscraper::~Skyscraper(){}

void Skyscraper::setName(std::string name)
{
	mName = name;
}

std::string Skyscraper::getName()
{
	return mName;
}

const Floor* Skyscraper::getFloor(unsigned int floorNumber)
{
	if (floorNumber < mFloors.size())
		return &mFloors[floorNumber];
	else
		return NULL;
}

Floor& Skyscraper::addFloor()
{
	mFloors.push_back( Floor() );
	return mFloors[mFloors.size()-1];
}

void Skyscraper::print()
{
	for (int i=0; i<mFloors.size(); i++)
	{
		Floor floor = mFloors[i];
		std::cout << "Storey: " << i << " Fibre: " << (floor.getHasFibre() ? "y" : "n") << " Carpet Colour: " << floor.getCarpetColour() << std::endl;
	}
}
#ifndef Floor_H
#define Floor_H

#include <iostream>
#include <string>

class Floor
{
public:
	Floor();
	
	unsigned int getCarpetColour();
	void setCarpetColour(unsigned int colour);
	bool getHasFibre();
	void setHasFibre(bool hasFibre);

private:
	std::string mTenant;	
	unsigned int mCarpetColour;
	bool mHasFibre;
};

#endif /* defined(Floor_H) */
#include "Floor.h"

Floor::Floor() : mCarpetColour(0x00FF0000), mHasFibre(true)
{
}

unsigned int Floor::getCarpetColour()
{
	return mCarpetColour;
}

void Floor::setCarpetColour(unsigned int colour)
{
	mCarpetColour = colour;
}

bool Floor::getHasFibre()
{
	return mHasFibre;
}

void Floor::setHasFibre(bool hasFibre)
{
	mHasFibre = hasFibre;
}

If one were to make use of these objects, some C++ code may look like the following.


#include <iostream>
#include <time.h>
#include <stdio.h>

#include "Skyscraper.h"

int main(int argc, const char * argv[])
{
	srand ( time(NULL) );
	Skyscraper skyscraper;
	skyscraper.setName("Cloud Hugger");
	
	for (int i=0; i<99; i++)
	{
		Floor& floor = skyscraper.addFloor();
		floor.setCarpetColour( rand() % 0x1000000 );
		floor.setHasFibre(false);
	}
	
	Floor& floor = skyscraper.addFloor();
	floor.setHasFibre(true);
	floor.setCarpetColour(0xFF);
	skyscraper.print();
}

Basically we’ve just created a 100 floor skyscraper where the top most penthouse has a red carpet and a fibre optic internet connection. Awesome.

So where does lua and Swig fit in?

Swig is a tool that creates the wrapper/”glue” between our C++ classes and Lua. Here are the basic steps which will be elaborated upon next.

  • Install/Compile swig (http://www.swig.org/)
  • Compile Lua and link its lib file to your C++ project
  • Outside of your project, make a new markup file that exposes the parts of your C++ classes you want to be used with Lua. This is going to create a lua module. For our example, lets call it building_contruction.i
  • Run swig on that building_construction.i file. This will create a building_construction_wrap.cxx
  • Add building_construction_wrap.cxx to your C++ project.
  • Add some lua setup code to your C++ project so that lua is initialised and can find the module that swig has created for us (more on this further down).
  • Create a lua script
  • Compile and run

The basic way to create the Swig file is just to expose all your class to it (rather than just individual methods and member variables). Notice the need for including some standard template library header files. These are built into swig for our convenience (phew).

/* File : building_construction.i */

%module building_construction
%include "std_string.i"
%include "std_vector.i"

%{
#include "Floor.h"
#include "Skyscraper.h"
%}

/* Let's just grab the entire header files here */
%include "Skyscraper.h"
%include "Floor.h"

To create our wrapper/binding code, run this with Swig using something like:

<path_to_swig_binary>/swig -c++ -lua <path_to_module_file>/building_construction.i

This will create a building_construction_wrap.cxx file. Add this to your project.

Now, the following is the modified main.cpp with all the lua setup code. Note that this app requires a command line argument that points to your .lua script.

#include <iostream>
#include <time.h>
#include <stdio.h>

#include "lua.hpp"
#include "lualib.h"
#include "lauxlib.h"

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

#define LUA_EXTRALIBS {"building_construction",luaopen_building_construction},

int main(int argc, const char * argv[])
{
	lua_State *L;
	if (argc<2)
	{
		printf("%s: <filename.lua>\n",argv[0]);
		return 0;
	}
	
	L=luaL_newstate();
	luaopen_base(L);  // load basic libs (eg. print)
	luaL_openlibs(L); // load all the lua libs (gives us math string functions etc.)
	luaopen_building_construction(L);	// load the wrapped 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]);
	lua_close(L);
	return 0;
}

Almost there. Now for the .lua file. That code above that created our 100 story skyscraper, here it in in lua form.

-- Assemble a 100 floor skyscraper made up
-- of 100 floors where the topmost floor is a
-- penthouse.

skyscraper = building_construction.Skyscraper()
skyscraper:setName("Cloud Hugger")

print( skyscraper:getName() )

-- Add 99 floors with random carpet colour and no
-- optical cables (gutted)
for i=0,99 do
	floor = skyscraper:addFloor()
	floor:setCarpetColour( math.random(0,255) )
	floor:setHasFibre(false)
end

-- Build the penthouse which has red carpet (think Palpatine)
-- and with fibre, because Palpatine likes fast internet.
floor = skyscraper:addFloor()
floor:setCarpetColour(255)
floor:setHasFibre(true)

-- Print the result
skyscraper:print()

…and that’s it. Hopefully something printed out the console.

Essentially we’ve coded the start of an amazing “skyscraper building app” that no longer has to be compiled and linked every time we wish to tweak some attributes to our skyscrapers. Hopefully this promotes good modularity of your C++ code and aides productivity by being able to tweak functionality via the scripts.

For more thorough documentation on using swig with lua, please refer to their documentation here: http://www.swig.org/Doc2.0/Lua.html#Lua_nn12

One thought on “Binding C++ to Lua Using Swig

  1. Thanks for the great article. I was studying SWIG and already knew pretty much of what you said, but it helped me to see it in the big picture.

    Ps.: Since you’re not exposing vectors to the Lua side, there is no need to include std_vector.i

Leave a comment