hot-code loading
To get hot-code loading you need to separate your program into an immutable loader (compiled to an executable and run directly) and a mutable hot-loaded library (compiled to a shared object and linked at runtime). When and how to do this are matters completely under your control.
To demonstrate this, a library:
local function greet() <cexport 'greet'>
print('hello, world')
endand a loader:
local ffi = require 'ffi' -- from nelua-batteries
local fs = require 'fs' -- from nelua-batteries
local function usleep(usec: integer): cint <cimport, nodecl, cinclude '<unistd.h>'> end
local LIB <comptime> = './greet.so'
local function load(): (ffi, function())
local lib = ffi.load(LIB)
assert(lib.handle ~= nilptr, "can't load lib")
local f = lib:get('greet')
assert(f, "can't find sym")
return lib, (@function())(f)
end
local function unload(lib: ffi)
assert(lib:unload(), 'failed to unload lib')
end
local function fresh(last: int64): (int64, boolean)
local buf, err, code = fs.stat(LIB)
assert(code == 0, err)
return buf.mtime, last ~= buf.mtime
end
local function main()
local last: int64
last = fresh()
local lib, f = load()
defer unload(lib) end
local reload: boolean
while true do
last, reload = fresh(last)
if reload then
unload(lib)
lib, f = load()
end
f()
usleep(200 * 1000)
end
end
main()And to run it:
$ nelua -P noentrypoint -o greet.so greet.nelua $ nelua live.nelua hello, world hello, world hello, world hello, world ...
While this is running you can edit greet.nelua, rebuild the .so, and see the changes reflected in the running program.
It's not necessary to set pragmas.noentrypoint since the linking is at runtime, but for static or dynamic linking this avoids a name collision on main. NB. Windows has some extra security around DLLs that will probably require you to swap back and forth between two libraries rather than update a single library while it's being used.