Not logged in

Programming with Lua and or C

1. Development Tools
1.1 Introduction
1.2 Programming with Lua and or C
1.3 Working with Premake
1.4 Bmake
1.5 Debugging
1.6 Using Fossil (DVCS)
1.7 Further Reading

Using C Library's in Pure Lua (Simple)

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.


local ffi = require("ffi")
ffi.cdef

[[ int printf(const char *fmt, ...); ]] ffi.C.printf("Hello %s!", "world")


Using C Library's in Pure Lua (Advanced)

The following code shows how to access the zlib compression library from Lua code.


local ffi = require("ffi")
ffi.cdef[[
unsigned long compressBound(unsigned long sourceLen);
int compress2(uint8_t *dest, unsigned long *destLen,
	      const uint8_t *source, unsigned long sourceLen, int level);
int uncompress(uint8_t *dest, unsigned long *destLen,
	       const uint8_t *source, unsigned long sourceLen);
]]

local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")

C++ and Lua Hybrid Application

The following example uses LuaWrapper and Luajit.

LuaWrapper is a library designed to help bridge the gab between Lua and C++. It is designed to be small (a single header file), simple, fast, and typesafe. It has no external dependencies other than the lua library itself, and does not need to be precompiled; the header can simply be dropped into a project and used immediately. It even supports class inheritance to a certain degree. Objects can be created in either Lua or C++, and passed back and forth.

The nice thing about LuaWrapper is that we can develop our C++ and Lua frameworks side by side and still keep them separate.

main.cpp

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

#include "LuaBankAccount.hpp"

using namespace std;

int main(int argc, const char *argv[])
{
    if (argc == 2)
    {
        lua_State* L = luaL_newstate();
        luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
        luaL_openlibs(L);
        luaopen_BankAccount(L);
        if (luaL_dofile(L, argv1))
            cout << lua_tostring(L, -1) << endl;
        lua_close(L);
    }
    return 0;
}

BankAccount.cpp

#include <BankAccount.hpp>

float BankAccount::s_totalMoneyInBank = 0;

BankAccount::BankAccount(const char* owner, float balance) 
    : m_owner(owner)
    , m_balance(balance)
{
    s_totalMoneyInBank += balance;
}

const char* BankAccount::getOwnerName() const
{
    return m_owner;
}

void BankAccount::deposit(float amount)
{
    s_totalMoneyInBank += amount;
    m_balance += amount;
}

void BankAccount::withdraw(float amount)
{
    s_totalMoneyInBank -= amount;
    m_balance -= amount;
}

float BankAccount::checkBalance() const
{
    return m_balance;
}

float BankAccount::checkTotalMoneyInBank()
{
    return s_totalMoneyInBank;
}

BankAccount.hpp

#ifndef EXAMPLE_HPP_
#define EXAMPLE_HPP_

#include <string>
#include <iostream>

class BankAccount
{
public:
    BankAccount(const char* owner, float balance);

    const char* getOwnerName() const;
    void deposit(float amount);
    void withdraw(float amount);
    float checkBalance() const;
    
    static float checkTotalMoneyInBank();
    
private:
    const char* m_owner;
    float m_balance;
    static float s_totalMoneyInBank;
};

#endif // EXAMPLE_HPP_

LuaBankAccount.cpp

#include <iostream>
#include <string>

extern "C"
{
#include "lua.h"
#include "lauxlib.h"
}
#include "luawrapper.hpp"

#include "BankAccount.hpp"

using namespace std;

//
// Allocator
//
// Types that do not have a default contructor require you to write an allocator function.
// This function is passed to luaW_register.
//

BankAccount* BankAccount_new(lua_State *L)
{
    const char* owner = luaL_checkstring(L, 1);
    float balance = luaL_checknumber(L, 2);
    return new BankAccount(owner, balance);
}

//
// Static Functions
//
// These functions can be called directly from the BankAccount table in lua
//

int BankAccount_checkTotalMoneyInBank(lua_State *L)
{
    lua_pushnumber(L, BankAccount::checkTotalMoneyInBank());
    return 1;
}

//
// Member Functions
//
// These functions are stored on the BankAccount.metatable table.
// All BankAccount objects in Lua have access to the functions defined there
// by the use of special a __index metatmethod that is set up by LuaWrapper.
//

int BankAccount_getOwnerName(lua_State *L)
{
    BankAccount* account = luaW_check(L, 1);
    lua_pushstring(L, account->getOwnerName());
    return 1;
}

int BankAccount_deposit(lua_State *L)
{
    BankAccount* account = luaW_check(L, 1);
    float amount = luaL_checknumber(L, 2);
    account->deposit(amount);
    return 0;
}

int BankAccount_withdraw(lua_State *L)
{
    BankAccount* account = luaW_check(L, 1);
    float amount = luaL_checknumber(L, 2);
    account->withdraw(amount);
    return 0;
}

int BankAccount_checkBalance(lua_State *L)
{
    BankAccount* account = luaW_check(L, 1);
    lua_pushnumber(L, account->checkBalance());
    return 1;
}

static luaL_Reg BankAccount_table[] =
{
    { "checkTotalMoneyInBank", BankAccount_checkTotalMoneyInBank },
    { NULL, NULL }
};

static luaL_Reg BankAccount_metatable[] =
{
    { "getOwnerName", BankAccount_getOwnerName },
    { "deposit", BankAccount_deposit },
    { "withdraw", BankAccount_withdraw },
    { "checkBalance", BankAccount_checkBalance },
    { NULL, NULL }
};

int luaopen_BankAccount(lua_State* L)
{
    luaW_register(L,
        "BankAccount",
        BankAccount_table,
        BankAccount_metatable,
        BankAccount_new // If your class has a default constructor you can omit this argument,
                        // LuaWrapper will generate a default allocator for you.
    );
    return 1;
}

LuaBankAccount.hpp

#ifndef LUAEXAMPLE_HPP_
#define LUAEXAMPLE_HPP_

struct lua_State;

int luaopen_BankAccount(lua_State*);

#endif // LUAEXAMPLE_HPP_

example1.lua

alicesaccount = BankAccount.new("Alice", 100)

alicesaccount:deposit(20);
alicesaccount:deposit(30);
alicesaccount:deposit(40);

bobsaccount = BankAccount.new("Bob", 200)

bobsaccount:withdraw(10);
bobsaccount:withdraw(15);
bobsaccount:withdraw(20);

function printaccountbalance(account)
    local name = account:getOwnerName()
    local balance = account:checkBalance()
    print(string.format("%s has $%d", name, balance))
end

printaccountbalance(alicesaccount)
printaccountbalance(bobsaccount)

print(string.format("The bank has $%d", BankAccount.checkTotalMoneyInBank()))