Compile Lua scripts to Windows executable

By Samir Tine, published on May 2023

rtc is an open source command line tool available with Luart that generates standalone executables from your Lua scripts.

Once compiled, an executable can be run on other Windows computers without the need to install Lua, facilitating the deployment of your applications.

In this tutorial, we will see how easy it is to make executables from Lua scripts, embed content, and deploy your applications on any Windows computer.

Your first executable

Create a simple hello.lua file containing this script :

print("Hello World !")

Now, open a command line prompt, go to the folder where you just saved the file, and type the following command to invoke rtc :

rtc hello.lua

Voila! You have just compiled your Lua script to a Windows executable hello.exe. You can run it like any other Windows program.

In fact, by default, your compiled executable is not really standalone, it needs the Lua runtime library lua54.dll, that can be found in the Luart bin\ folder. If you suppress the PATH environment variable, your program hello.exe won't execute as it won't be able to find the Lua runtime library anymore.

Sticky note

The hello.exe depends on the Lua dynamic library lua54.dll. This is called dynamic compilation.
Dynamic compilation is the standard way to run Lua, as it permits to load binary modules during runtime.

Let's go static

If you want to get ride of the lua54.dll dependency, you can use static compilation, by using the -s option :

rtc -s hello.lua

You can see that the new hello.exe has a bigger size. You guess it, that's because it contains the Lua runtime library. It can now be executed without the need of the lua54.dll library.

Sticky note

Static compilation may sound appealing, but it comes at a price: Binary Lua modules cannot be loaded at runtime.
Reserve this type of compilation for simple applications that do not depend on third-party binary modules.

Open a Window

By default, rtc decide to compile executables for console or desktop depending on the file extension :

  • Lua source file with a .lua extension are compiled for console
  • Lua source file with a .wlua extension are compiled for desktop

Let's go further and compile our first desktop application, by saving the following file to hello.lua :

local ui = require "ui" ui.info("Hello world !")

Now compile it :

rtc hello.lua

If you run hello.exe, by double clicking on it in the Windows explorer, a console window will show with an error message complaining that the ui module is not found...

This happens because we have named our Lua source file with the .lua extension, and rtc compiled our file as a console application (remember that the ui module is only available using desktop interpreter).

We have two possibilities to correct this: either rename our source file with the .wlua extension or force rtc to generate a desktop application. Let's use this last method with the -w option:

rtc -w hello.lua

Running hello.exe will show only the message box, without the console window. You just compiled your first Lua desktop application !

You are iconic

rtc provides default applications icons for your compiled executables, depending on console/desktop applications.

You can override this default behaviour and provide your own applications icons with the -i option. Let's use a specific icon for our previous hello.lua desktop application :

rtc.exe -i path/to/your/icon.ico -w hello.lua

Just replace the path/to/your/icon.ico with the path of the .ico file to use. Rather simple !

I got this baggage with me

Now imagine that your application is made up of several Lua files in the same directory and even in subdirectories. How to package everything in the executable ?

Once again rtc makes it easy. We just need to indicate, in addition to the main Lua source file, the directory to embed entirely in the executable. Yes, you read correctly. rtc is able to include in the compiled executable the entire contents of a directory with all these files and subdirectories.

Let's try to compile our desktop application with its entire directory content. To do this, open a command line prompt, got to the folder where our main Lua file hello.lua is and type the following command :

rtc.exe -w hello.lua .

The dot . means we ask rtc to embed the current directory with all its content inside the executable.

The embed module

But wait a minute, how to access our files once they are embedded in our executable ?

The embed module comes to the rescue. This module is only available to compiled scripts if embedded content is found inside the executable. This module contains :

  • A File object to interact with all the embedded files.
  • A Zip object instance to access the compressed embedded content.

If you want to use a Lua file or a Lua binary module in the embedded content, just use the global require() function seamlessly, without the need to extract files before.

Sticky note

rtc creates inside the executable a virtual file system that contains the directory content provided by the command line.
This allows access to embedded content transparently from your Lua scripts, both for accessing files and for loading Lua modules, whether binary or not.