Switching between Lua and LuaJIT using CMake

August 26, 2013

The more I work with Lua, the more I get addicted to it. Lua itself is a formidable language and additionally it is (somewhat) fun to write wrappers to C/C++ code.

Lua itself is fast, but it can be made even faster by using LuaJIT, which is one of the fastest scripting language implementations available. The nice thing about LuaJIT is, that it is both API and ABI compatible to the standard Lua 5.1 implementation. This means that you simply need to link against the LuaJIT library instead of the Lua library and you get increased performance for free*!

For most of my C/C++ code I am using CMake as a build tool, which is does its job most of the time, albeit its language and syntax is rather cumbersome (especially compared to Lua). There is premake, a build system using Lua, which looks very interesting, however right now I have too little time to move my stuff over to it.

CMake comes with scripts to find Lua 5.0 and 5.1 but not to find LuaJIT. So I wrote my own FindLua.cmake script that searches for Lua 5.1 or LuaJIT depending on the value of the variable LUA_USE_LUAJIT option. Adjusting this variable allows easy switching between the standard Lua and LuaJIT.

CMake caches most of its variables and therefore you cannot change the type of Lua implementation using the CMake GUI. To alleviate this you can use the following lines, that ensure the invalidation of the cached CMake variables and nice and snappy switching between the implementations from the CMake GUI:

OPTION (LUA_USE_LUAJIT "Use LuaJIT instead of default Lua" OFF)
UNSET(Lua_FOUND CACHE)
UNSET(LUA_INCLUDE_DIR CACHE)
UNSET(LUA_LIBRARY CACHE)
FIND_PACKAGE (Lua REQUIRED)

Here is full FindLua.cmake script:

# Copyright (c) 2013 Martin Felis <martin@fysx.org>
# License: Public Domain (Unlicense: http://unlicense.org/)
#
# Try to find Lua or LuaJIT depending on the variable LUA_USE_LUAJIT.
# Sets the following variables:
#   Lua_FOUND
#   LUA_INCLUDE_DIR
#   LUA_LIBRARY
#
# Use it in a CMakeLists.txt script as:
#
#   OPTION (LUA_USE_LUAJIT "Use LuaJIT instead of default Lua" OFF)
#   UNSET(Lua_FOUND CACHE)
#   UNSET(LUA_INCLUDE_DIR CACHE)
#   UNSET(LUA_LIBRARY CACHE)
#   FIND_PACKAGE (Lua REQUIRED)
 
SET (Lua_FOUND FALSE)
 
SET (LUA_INTERPRETER_TYPE "")
 
IF (LUA_USE_LUAJIT)
    SET (LUA_INTERPRETER_TYPE "LuaJIT")
    SET (LUA_LIBRARY_NAME luajit-5.1)
    SET (LUA_INCLUDE_DIRS /usr/include/luajit-2.0 /usr/local/include/luajit-2.0)
ELSE (LUA_USE_LUAJIT)
    SET (LUA_INTERPRETER_TYPE "Lua")
    SET (LUA_LIBRARY_NAME lua5.1)
    SET (LUA_INCLUDE_DIRS /usr/include/lua5.1 /usr/local/include/lua5.1)
ENDIF(LUA_USE_LUAJIT)
 
FIND_PATH (LUA_INCLUDE_DIR lua.h ${LUA_INCLUDE_DIRS} )
FIND_LIBRARY (LUA_LIBRARY NAMES ${LUA_LIBRARY_NAME} PATHS /usr/lib /usr/local/lib)
 
IF (LUA_INCLUDE_DIR AND LUA_LIBRARY)
    SET (Lua_FOUND TRUE)
ENDIF (LUA_INCLUDE_DIR AND LUA_LIBRARY)
 
IF (Lua_FOUND)
    IF (NOT Lua_FIND_QUIETLY)
        MESSAGE(STATUS "Found ${LUA_INTERPRETER_TYPE} library: ${LUA_LIBRARY}")
    ENDIF (NOT Lua_FIND_QUIETLY)
ELSE (Lua_FOUND)
   IF (Lua_FIND_REQUIRED)
       MESSAGE(FATAL_ERROR "Could not find ${LUA_INTERPRETER_TYPE}")
   ENDIF (Lua_FIND_REQUIRED)
ENDIF (Lua_FOUND)
 
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua  DEFAULT_MSG LUA_LIBRARY LUA_INCLUDE_DIR)
 
MARK_AS_ADVANCED ( LUA_INCLUDE_DIR LUA_LIBRARY)

* the only “downside” of using LuaJIT instead of Lua that I faced so far is that you have ensure all your wrappers actually return an integer. Otherwise LuaJIT crashes when it calls a wrapped function. But you should return an from a integer function anyways, so it just encourages better code.