i plan on comercially releasing games soon, so i would like to find out a way to compile to bytecode and then fuse it into an executable. I have been searching for a way for literal months, but i haven't found a way, let me tell you what happens when i do try to do a method.
So doing jit.version, i can see Love2D uses 2.1.0beta3, which is the version i use to do luajit -b test.lua test.bc
. After i do do that i proceed to remove the contents of the .lua file, and add different code to it.
Let's show you what i originally had inside of test.lua (the code i compiled):
local test = {}
function test:load()
print("Worked.")
end
return test
So this is the code i compile, i then remove the contents of it and add this instead:
local f = assert(love.filesystem.load("test.bc"))
return f()
and then in my main.lua file i do this:
function love.load()
local testclass = require("test")
testclass:load()
end
When i do that, i produce this error (Before you ask, there's no syntax error in the Lua code before compilation.):
Error
test.lua:1: Syntax error: test.bc: cannot load incompatible bytecode
Traceback
[love "callbacks.lua"]:228: in function 'handler'
[C]: in function 'load'
test.lua:1: in main chunk
[C]: in function 'require'
main.lua:3: in function 'load'
[love "callbacks.lua"]:136: in function <[love "callbacks.lua"]:135>
[C]: in function 'xpcall'
[C]: in function 'xpcall'
I genuinly have been looking for a way for literal months, if someone could help out, it'd be greatly appreciated!
So doing
jit.version
, i can see Love2D uses 2.1.0beta3, which is the version i use to doluajit [...]
Unfortunately, the assumption that LuaJIT version numbers would be sane is wrong. LuaJIT has been on 2.1.0-beta3 for years, despite numerous changes; Mike Pall's motivation for stopping to explicitly release new versions is unclear, but it seems that you are supposed to just use latest master.
Thus, to make sure that you're compiling your bytecode with the same LuaJIT version LÖVE uses, compile it from within LÖVE using string.dump
.
Note that - contrary to PUC Lua - string.dump
generates portable bytecode on LuaJIT:
The generated bytecode is portable and can be loaded on any architecture that LuaJIT supports, independent of word size or endianess. However, the bytecode compatibility versions must match. Bytecode stays compatible for dot releases (x.y.0 → x.y.1), but may change with major or minor releases (2.0 → 2.1) or between any beta release. Foreign bytecode (e.g. from Lua 5.1) is incompatible and cannot be loaded.
You can also set a strip
flag, which will be helpful to remove debug information to make reversing harder:
An extra argument has been added to string.dump(). If set to true, 'stripped' bytecode without debug information is generated. This speeds up later bytecode loading and reduces memory usage. See also the -b command line option.
So, let's first use the following main.lua
, which assumes your project folder as the current working directory:
-- Compile `test.lua` to bytecode, strip debug info
local bytecode = string.dump(assert(love.filesystem.load("test.lua")), true)
local f = assert(io.open("test.bc", "wb"))
f:write(bytecode)
f:close()
print("Compiled `test.lua` to `test.bc`")
love.event.quit()
Now execute love .
inside your project directory to compile test.lua
to test.bc
. After doing this, you can replace test.lua
with:
return assert(love.filesystem.load("test.bc"))()
and replace main.lua
with
function love.load()
local testclass = require("test")
testclass:load()
end
Running this using love .
prints Worked.
as expected.
Automatizing this build process using Lua scripts, shell scripts or Makefiles is left as an exercise to the reader.
You could also try figuring out the exact LuaJIT commit LÖVE uses to compile that LuaJIT version yourself, which would allow you to use luajit -b test.lua test.bc
.