Skip to content

grant-wade/lua-wrap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lua-wrap

What's lua-wrap do? It wraps Lua/Fennel projects in a C executable with any libraries you want to include with your Lua project. Libraries are statically linked into the wrapper and any Lua sources are directly embedded into it and you are left with a single executable that only relies on your system C library. Included by default are a couple common Lua libraries to get projects started and give linking examples.

The goal is to allow easy embedding and distribution of applications written in Lua/Fennel. Who doesn't love shipping a project as a single executable with little to no dependencies?

This is something that I put together for some personal projects that I thought others might find useful. Feedback and pull requests are welcome!

Project Usage

Requirements

  • C Compiler
    • gcc (11.5.0+; tested on Alma Linux 9)
    • clang (17.0.0; tested on macOS 15.5)
    • MSVC (untested)
  • git

Clone the Project

This project has a few submodules, if you run into any build/linking issues make sure they are populated in vendor/.

git clone https://github.com/grant-wade/lua-wrap.git --recursive

Change to lua-wrap directory

cd lua-wrap

Setup cbuild

First we compile our driver. Feel free to take a look at build.c, it brings together some tools for us to put this project together. cbuild.h is a mostly declarative build system focused on C, but is adaptable enough to fit in as the compiler driver for lua-wrap.

cbuild is my, obviously biased, favorite C build system. This repo may or may not have a never version, I redeisgned some parts of it for the codegen file dependencies this projects build.c uses and have yet to test everything and update the live version.

gcc -o cbuild build.c

Build the Wrapper

cbuild does it all

The driver is configured to setup the build envrionment by first building a copy of Lua that it can use for some scripting and then it has everything it needs to build the project in src/ into a single executable.

The driver is configured to compile any Fennel code to Lua, copy Lua sources, then build a C source file with all the Lua embeded inline. These Lua files are loaded at start to the package preload before the main entrypoint. With any statically linked library having their load method exposed in the executable for Lua.

Checkout the scripts/ directory to see how Fennel is pre-compiled and how the wrapper.c is put together for the final executable.

./cbuild
Click to view output
COMPILE    vendor/lua/onelua.c
LINK       build/lua
COMPILE    vendor/lua/onelua.c
LINK       build/liblua_static.a
FILE_DEP   Updating/Ensuring file: build/wrapper.c
COMMAND    Compile:Fennel
COMMAND    Build fennel
Compiling src/fs.fnl -> build///fs.lua
Compiling src/main.fnl -> build///main.lua
Compilation complete!
COMMAND    Lua:CopySource
COMMAND    Lua:CopyLuaSocketLua
COMMAND    CodeGen:wrapper.c
COMMAND    Make wrapper.c
Generated C file: build/wrapper.c
FILE_DEP   build/wrapper.c (updated)
COMPILE    vendor/isocline/src/isocline.c
LINK       build/libisocline.a
COMPILE    vendor/luafilesystem/src/lfs.c
LINK       build/liblfs.a
COMPILE    vendor/lua-cjson/strbuf.c
COMPILE    vendor/lua-cjson/lua_cjson.c
COMPILE    vendor/lua-cjson/fpconv.c
LINK       build/libcjson.a
COMPILE    vendor/luasocket/src/auxiliar.c
COMPILE    COMPILE    vendor/luasocket/src/except.c
vendor/luasocket/src/compat.c
COMPILE    vendor/luasocket/src/buffer.c
COMPILE    vendor/luasocket/src/inet.c
COMPILE    vendor/luasocket/src/io.c
COMPILE    vendor/luasocket/src/luasocket.c
COMPILE    vendor/luasocket/src/mime.c
COMPILE    vendor/luasocket/src/options.c
COMPILE    vendor/luasocket/src/select.c
COMPILE    vendor/luasocket/src/serial.c
COMPILE    vendor/luasocket/src/tcp.c
COMPILE    vendor/luasocket/src/timeout.c
COMPILE    vendor/luasocket/src/udp.c
COMPILE    vendor/luasocket/src/unix.c
COMPILE    vendor/luasocket/src/unixdgram.c
COMPILE    vendor/luasocket/src/unixstream.c
COMPILE    vendor/luasocket/src/usocket.c
LINK       build/libluasocket.a
COMPILE    build/wrapper.c
LINK       build/wrapper
✔ Build succeeded.

Run the wrapper

You can run the wrapper with the driver as well using the run subcommand

./cbuild run
FILE_DEP   build/wrapper.c (up-to-date)
SUBCMD     Running 'run': build/wrapper
~ main.fnl starting: hello! ~

This is equivalent if there are no file changes:

./build/wrapper
~ main.fnl starting: hello! ~

Run the REPL(s)

The wrapper includes a Lua REPL as well as a Fennel REPL. It has similar caveots to the Lua REPL with global/local variables. Both run in the Lua environment after the entrypoint script has been evaluated.

Lua REPL

./build/wrapper --repl
~ main.fnl starting ~
its a string my dude
~ main.fnl ending ~
Lua REPL (type 'exit' to quit)
>>> socket = require "socket"
>>> sd = socket.bind("*", 0)
>>> print(sd)
tcp{server}: 0x55d2d1fe77f8
>>>

Fennel REPL

./build/wrapper --fennel
~ main.fnl starting ~
its a string my dude
~ main.fnl ending ~
Fennel REPL (type 'exit' or 'quit' to leave)
>>> (global socket (require :socket))
nil
>>> (global sd (socket.bind "*" 0))
nil
>>> (print sd)
tcp{server}: 0x560a0b78a618

Vendored Libraries

Right now this project only supports modern PUC Lua but plans to expand to other Lua versions and LuaJit/Luau in the future.

C Libraries

Lua Libraries (statically linked and included in the runtime)

All the following Lua libraries are aviable in the embedded runtime by require("name") in Lua or (require "name") in Fennel

Todo

  • Configure build.c for Windows builds (cbuild.h may need some changes as well as build.c)
  • Expand support to other Lua versions (LuaJit, Luau, Lua 5.1+)
  • Setup some docs on how to use this project as a template
  • Integrate Fennel REPL with Isocline for better scope handling (requires (global name val) right now in REPL)
  • Make statically linked Lua Libraries optional
  • Explore integrating LuaRocks into the environment

Acknowledgements

I found srlua and luastatic after building this project and they both look like good solutions that solve this same problem.

About

Build a single executable from a Lua/Fennel project

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors