Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keeping everything in a single lua bytecode chunk?

I've embedded lua together with a bytecode chunk into a project written in C. Now when I extend my lua code base by adding .lua files, is there a way to keep this code in a single bytecode chunk?

(I know how to load multiple bytecode chunks. But making it load a single chunk and then forgetting about the glue code would just seem comfortable.)

I tried to use textual inclusion, but it seems there's no keyword for this in Lua. "Require" and "dofile" look at the files at run time, so the resulting bytecode after running "lua -b ..." won't include the code of those files.

And there's no way for combining bytecode files either, is there? I mean so that, when creating a bytecode file, the "require" command would add the code of all those files into one bytecode file.

PS: Michal Kottman's answer works for Lua, which is what I asked for. I thought Lua and LuaJIT would work the same way. They don't. To combine multiple .lua files to one LuaJIT bytecode file, should one

  • use "LuaJIT -b" (seems not to work)
  • compile Lua's luac.c with LuaJIT sources
  • emulate luac.c with lua commands (without C API) ?
like image 202
John Avatar asked Mar 06 '12 08:03

John


People also ask

What does luac do?

DESCRIPTION. luac is the Lua compiler. It translates programs written in the Lua programming language into binary files that can be later loaded and executed. The main advantages of precompiling chunks are: faster loading, protecting source code from accidental user changes, and off-line syntax checking.

Does Lua compile to bytecode?

Pre-compiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed.

What is Lua bytecode?

Instruction Summary Lua bytecode instructions are 32-bits in size. All instructions have an opcode in the first 6 bits. Instructions can have the following fields: 'A' : 8 bits 'B' : 9 bits 'C' : 9 bits 'Ax' : 26 bits ('A', 'B', and 'C' together) 'Bx' : 18 bits ('B' and 'C' together) 'sBx' : signed Bx.


2 Answers

You can combine multiple files into a single file using luac. When run, all the chunks from the source files are executed in the order they were added to the compiled file:

$ echo "x=1"         > l1.lua
$ echo "y=2"         > l2.lua
$ echo "print(x, y)" > l3.lua
$ luac -o run.luac l1.lua l2.lua l3.lua
$ lua run.luac
1   2

You can load this file into Lua from C using luaL_loadfile, which places a function on the top of the stack if it loaded succesfully. Then you can just run this function using lua_call to run all the combined compiled files.

Note that you can embed the contents of the compiled file as a string into your project, no need to keep it in external file.

Update for LuaJIT 2

As you have found, you can use the Lua Compiler in Lua to get a combined file which can be loaded as previously noted. This is a simplified version, which outputs to stdout:

-- http://lua-users.org/wiki/LuaCompilerInLua
-- compile the input file(s) passed as arguments and output them combined to stdout
local chunk = {}
for _, file in ipairs(arg) do
  chunk[#chunk + 1] = assert(loadfile(file))
end
if #chunk == 1 then
  chunk = chunk[1]
else
  -- combine multiple input files into a single chunk
  for i, func in ipairs(chunk) do
    chunk[i] = ("loadstring%q(...);"):format(string.dump(func))
  end
  chunk = assert(loadstring(table.concat(chunk)))
end
io.write(string.dump(chunk))

For the previous sample, you can use it as follows:

$ luajit combine.lua l1.lua l2.lua l3.lua > out.ljc
$ luajit out.ljc
1   2
like image 71
Michal Kottman Avatar answered Oct 14 '22 16:10

Michal Kottman


Another alternative is to use a tool like Mathew Wild's squish to collect all your Lua sources into a single .lua file. One nice feature of squish is that it supports a variety of filters to help make the squished package smaller than the total of the source files.

After applying squish, you could run the result through luac to get bytecode. However, bytecode is often larger than the source code, and almost certainly larger if a more aggressive filter (such as gzip) is used in squish.

If your bytecode file were stored separately from the executable (or worse, transmitted over the network), I'd also bring up security concerns related to bytecode that don't apply to Lua source code. However, bytecode linked in to an application is much harder to subvert since harmful bytecode will never be the result of running luac.

like image 36
RBerteig Avatar answered Oct 14 '22 18:10

RBerteig