Запуск объектного файла luajit из C

Из документации: http://luajit.org/running.html

luajit -b test.lua test.obj                 # Generate object file
# Link test.obj with your application and load it with require("test")

Но не объясняет, как это делать. Я предполагаю, что они предполагают, что любой, кто использует Lua, также является программистом C, но не в случае со мной! Могу ли я получить некоторую помощь? ГЦК как пример.

Я также хотел бы сделать то же самое, кроме заголовка массива байтов C. Я также не могу найти документацию по этому поводу.

luajit -bt h -n test test.lua test.h

Это создает файл заголовка, но я не знаю, как запустить его из C. Спасибо.


person Matthew    schedule 17.10.2013    source источник
comment
Вы должны иметь возможность использовать luaL_loadstring для загрузки этого массива C. После того, как вы вернете функцию в стек, вы можете выполнить ее с помощью чего-то вроде call или pcall или сохранить ее в таблице package.preload, если она понадобится вам позже — в зависимости от того, что вы хотите сделать.   -  person greatwolf    schedule 17.10.2013


Ответы (2)


main.lua

print("Hello from main.lua")

app.c

#include <stdio.h>

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

int main(int argc, char **argv)
{
  int status;
  lua_State *L = luaL_newstate();
  luaL_openlibs(L);
  lua_getglobal(L, "require");
  lua_pushliteral(L, "main");
  status = lua_pcall(L, 1, 0, 0);
  if (status) {
    fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
    return 1;
  }
  return 0;
}

Команды оболочки:

luajit -b main.lua main.o
gcc -O2 -Wall -Wl,-E -o app app.c main.o -Ixx -Lxx -lluajit-5.1 -lm -ldl

Замените -Ixx и -Lxx на LuaJIT include и библиотечные каталоги. Если вы установили его в /usr/local (по умолчанию), то большинство установок GCC обнаружат его без этих двух опций.

Первая команда компилирует исходный код Lua в байт-код и встраивает его в объектный файл main.o.

Вторая команда компилирует и связывает минимальный код приложения C. Обратите внимание, что он также ссылается на встроенный байт-код. -Wl,-E является обязательным (в Linux) для экспорта всех символов из исполняемого файла.

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

mv main.lua main.lua.orig
./app
# Output: Hello from main.lua
person Mike Pall    schedule 17.10.2013
comment
Потрясающий! Спасибо! Может ли luac создать файл .o? - person Matthew; 17.10.2013
comment
Нет, только luajit -b может сделать это за один шаг. Существуют сторонние инструменты, такие как bin2c, которые помогают с этим для простого Lua. Посмотрите на другой ответ для общего подхода. - person Mike Pall; 17.10.2013
comment
Есть ли способ сделать что-то вроде assert(loadfile("main")) вместо require("main")? loadfile, похоже, не находит связанный модуль, как это делает require, а вместо этого просто бежит искать файл. Я пытаюсь передать аргументы (из app.c, используя argv) в связанный модуль и не могу использовать require, потому что он не возвращает модуль как функцию, которую я могу вызвать, как это делает loadfile. - person ; 29.11.2015

Основное использование заключается в следующем:

  • Сгенерируйте заголовочный файл с помощью luajit
  • #include этот заголовок в исходном файле (файлах), который будет ссылаться на его символы
  • Скомпилируйте исходный код в работающий исполняемый или общий двоичный модуль для lua в зависимости от вашего варианта использования.

Вот минимальный пример для иллюстрации:

test.lua

return
{
  fooprint = function (s) return print("from foo: "..s) end,
  barprint = function (s) return print("from bar: "..s) end
}

test.h

// luajit -b test.lua test.h
#define luaJIT_BC_test_SIZE 155
static const char luaJIT_BC_test[] = {
27,76,74,1,2,44,0,1,4,0,2,0,5,52,1,0,0,37,2,1,0,16,3,0,0,36,2,3,2,64,1,2,0,15,
102,114,111,109,32,102,111,111,58,32,10,112,114,105,110,116,44,0,1,4,0,2,0,5,
52,1,0,0,37,2,1,0,16,3,0,0,36,2,3,2,64,1,2,0,15,102,114,111,109,32,98,97,114,
58,32,10,112,114,105,110,116,58,3,0,2,0,5,0,7,51,0,1,0,49,1,0,0,58,1,2,0,49,1,
3,0,58,1,4,0,48,0,0,128,72,0,2,0,13,98,97,114,112,114,105,110,116,0,13,102,
111,111,112,114,105,110,116,1,0,0,0,0
};

runtest.cpp

// g++ -Wall -pedantic -g runtest.cpp -o runtest.exe -llua51
#include <stdio.h>
#include <assert.h>

#include "lua.hpp"
#include "test.h"

static const char *runtest = 
"test = require 'test'\n"
"test.fooprint('it works!')\n"
"test.barprint('it works!')\n";


int main()
{
  lua_State *L = luaL_newstate();
  luaL_openlibs(L);

  lua_getglobal(L, "package");
  lua_getfield(L, -1, "preload");
  // package, preload, luaJIT_BC_test
  bool err = luaL_loadbuffer(L, luaJIT_BC_test, luaJIT_BC_test_SIZE, NULL);
  assert(!err);

  // package.preload.test = luaJIT_BC_test
  lua_setfield(L, -2, "test");

  // check that 'test' lib is now available; run the embedded test script 
  lua_settop(L, 0);
  err = luaL_dostring(L, runtest);
  assert(!err);

  lua_close(L);
}

Это довольно прямолинейно. Этот пример берет байт-код и помещает его в таблицу package.preload для среды lua этой программы. Затем другие сценарии lua могут использовать это, выполнив require 'test'. Встроенный источник lua ​​в runtest делает именно это и выводит:

from foo: it works!
from bar: it works!
person greatwolf    schedule 17.10.2013
comment
Потрясающе, спасибо! Это то, что мне нужно было знать, luaL_loadbuffer. Не подскажете, возможно ли то же самое с помощью обычного luac? - person Matthew; 17.10.2013