Хранение всего в одном блоке байт-кода lua?

Я включил lua вместе с блоком байт-кода в проект, написанный на C. Теперь, когда я расширяю свою базу кода lua, добавляя файлы .lua, есть ли способ сохранить этот код в одном блоке байт-кода?

(Я знаю, как загружать несколько байт-кодов, но заставляя его загружать один кусок, а затем забывать о коде клея, просто будет удобно.)

Я попытался использовать текстовое включение, но, похоже, в Lua нет ключевого слова для этого. "Требовать" и "делать файлы" смотрите файлы во время выполнения, поэтому полученный байт-код после запуска "lua -b..." не будет содержать код этих файлов.

И нет способа комбинировать файлы байт-кода, есть ли? Я имею в виду, что при создании файла байт-кода команда "require" добавит код всех этих файлов в один файл байт-кода.

PS: Михал Коттман отвечает за работу в Lua, и это то, о чем я просил. Я думал, что Lua и LuaJIT будут работать одинаково. Они этого не делают. Чтобы объединить несколько файлов .lua в один файл байт-кода LuaJIT, нужно

  • использовать "LuaJIT -b" (похоже, не работает)
  • скомпилировать Lua luac.c с источниками LuaJIT
  • emulate luac.c с командами lua (без C API)?

Ответы

Ответ 1

Вы можете объединить несколько файлов в один файл, используя luac. При запуске все куски из исходных файлов выполняются в том порядке, в котором они были добавлены в скомпилированный файл:

$ 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

Вы можете загрузить этот файл в Lua из C с помощью luaL_loadfile, который помещает функцию в верхнюю часть стека, если она будет загружена успешно. Затем вы можете просто запустить эту функцию, используя lua_call, чтобы запустить все объединенные скомпилированные файлы.

Обратите внимание, что вы можете вставлять содержимое скомпилированного файла в строку в свой проект, не нужно хранить его во внешнем файле.

Обновление для LuaJIT 2

Как вы уже нашли, вы можете использовать компилятор Lua в Lua, чтобы получить объединенный файл, который можно загрузить, как было отмечено ранее. Это упрощенная версия, которая выводит на 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))

Для предыдущего образца вы можете использовать его следующим образом:

$ luajit combine.lua l1.lua l2.lua l3.lua > out.ljc
$ luajit out.ljc
1   2

Ответ 2

Другой альтернативой является использование инструмента, такого как Mathew Wild squish, чтобы собрать все источники Lua в один файл .lua. Одна приятная особенность хлюпания заключается в том, что она поддерживает множество фильтров, чтобы сделать пакет с закругленным размером меньше, чем общее количество исходных файлов.

После применения squish вы можете запустить результат через luac, чтобы получить байт-код. Однако байт-код часто больше исходного кода и почти наверняка больше, если в squish используется более агрессивный фильтр (например, gzip).

Если ваш файл байт-кода хранился отдельно от исполняемого файла (или, что еще хуже, передавался по сети), я также вызывал проблемы безопасности, связанные с байт-кодом, которые не относятся к исходному коду Lua. Однако байт-код, связанный с приложением, гораздо труднее подорвать, поскольку вредный байт-код никогда не будет результатом запуска luac.

Ответ 3

После попытки luac, luajit и squish, я нашел, что все они требуют, чтобы список файлов был объединен. Это утомительно, когда работа над проектом содержит много файлов lua.

Итак, я написал небольшой инструмент для объединения lua файлов путем анализа require s

Вот он: https://github.com/yi/node-lua-distiller

Надеюсь, что это поможет.

Ответ 4

loadstring - это то, что вы ищете. Он берет строку и загружает, если (после компиляции в байтовый код, если необходимо). Это приводит к функции, которая может быть выполнена для запуска содержащегося кода впоследствии.

Если вам все еще нужно что-то более общее, посмотрите load, который позволяет вам указать функцию для подачи кусков.

Обе функции могут обрабатывать как исходный код Lua, так и скомпилированный байт-код.