Goodbye snake, I go to the moon
Lua in the sky
NASA is not the only one going to the moon — Lua, (pronounced LOO-ah) meaning "Moon" in Portuguese, is a multiple-paradigm scripting language. Created in 1993 by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, and Waldemar Celes, members of the Computer Graphics Technology Group (Tecgraf) at the Pontifical Catholic University of Rio de Janeiro in Brazil.
Initially overlooked by me as "just another scripting language", it caught my eye when I was looking for an alternative for Python. Having growing frustrations with the Snake for different reasons, I wanted a small and simple to use language. One of my criteria was that I can embed it into a projects build system; making setup and management easier, sparing the need for specific version installations, or handling local installed language environments with one of too many tools. Speed was another factor, neglected far too often with script languages.
Lua ticked many boxes for me, and grew on to become a favourite of mine, from small scripts to large tools; a language as a general toolset for my daily tasks, running really everywhere. In this article I will show an overview of how and with what I personally use Lua, no exhaustive guide. Nevertheless, I will publish a multipart series on Lua going in-depth on many parts of the language; more on this at the end.
You maybe already have Lua installed on your system! You can check
lua -v in a terminal.
If this is not the case there are different ways to get Lua, one way on macOS is using brew.
Having Lua installed you can start a
LuaRocks can be seen as the de facto standard package manager for Lua. If not already installed, on macOS you can use brew to install LuaRocks.
Similar to NPM, I want to keep packages
local and inside the project, rather than global or
in my user directory. A global installation is the default, using
--local will install packages in a folder in the users
I will install all packages inside a
in the root of a project, using the
--tree option of
the LuaRocks CLI. As an
example, installing the
For Lua to find any local package on require, the search paths need
to be set. This can be done by defining a setup module (can have any
name), that will be loaded when executing a script through the
-l option of the Lua
Creating a script file …
… and running it with the
-l option will find
inspect package from the local folder and execute
This will now work for any package installed inside the local
luarocks install --tree=lua_modules <package>.
Setting up a project would not be complete without testing, lint tooling and code formatting.
For unit tests I use LuaUnit, installed via LuaRocks.
Tests are just Lua files importing LuaUnit. I define test files with
.test.lua extension and use
TAP (Test Anything Protocol)
as output format, an amazing output format I also use in
The test can than be executed via Lua, printing the result in the terminal.
To lint I use LuaCheck, again installed via LuaRocks.
Using the default options, running it on a whole folder, for example
Auto formatting Lua code happens via LuaFormatter.
For the checker I will use a small set of custom options, defined in
.lua-format file (the format is YAML), in
the project root.
Running it on all files in a folder and formatting them.
C++, CMake, and Lua
Having established a base working with Lua, how about embedding it into other software? Lua is also known as "extensible extension language", referring to it being created with the idea to have a scripting language that can extend and customise applications.
I will use
Sol2, a header only C++ library providing Lua bindings in combination
C++ base template
I created in my
basic C++ setup with CMake article. Having that set up, I first need to add Lua to the project;
creating a new CMake file
build Lua as it does not come with CMake support.
This will set up Lua as a C project and create a library under the
lua. Next, extending the dependency list in
Sol2 can be added as dependency by creating a new
file, rather short as it comes with CMake support.
Again, adding it to the dependency list in
That's it getting Lua and Sol2 into the project. Next up, adding the libraries to the application by linking them to the target.
Now that everything is ready, trying a small test program in
This will indeed print
Some value is now: 1. A
different example, using a Lua script file with a
simple function for demonstration.
With CMake, any non build files need to be copied to the build
output directory, using the
file function this can be
done on the CMake configure step.
The script file can than be loaded, extracting the defined Lua
hello to call it from C++.
Running this will print
Result: Hello, Mr. Anderson.
This example project is also available on GitHub as embedding-lua-in-cpp-example repository. How to inject new functions and values into Lua, as well as many other things, can be found at the official Sol2 documentation.
What comes next
This just showed some basics using Lua, and parts of how I use Lua personally, only scratching the surface. To extend this topic, and shine an even brighter light on the Moon, I will create a series of articles covering many topics of Lua in-depth. Some of those will be:
- In-depth Project setup using LuaRocks and git
- All about dependencies and creating your own modules
- Testing, debugging, and profiling
- Building and extending C++ applications with embedded Lua
- Scaling Lua applications and large Lua projects
And maybe more, if I find more things to cover. Until then 👋🏻