Я начинаю вкладывать свои руки в lua и до сих пор испытывал довольно неприятный опыт. Мне нужно загрузить части penlight, чтобы загрузить "mine.lua", для которого требуется pl.import_into. Мне нужно сделать это с C/C++.
Я использую lua 5.1; использование 5.2 не является опцией atm, поэтому у меня нет luaL_requiref
Грубо мой код выглядит так:
void luaLoad(lua_State* L, const char* f) {
if (luaL_dofile(L, f) || lua_pcall(L, 0, 0, 0)) {
const char* err = lua_tostring(L, -1);
lua_pop(L, -1);
throw std::runtime_error("Lua load error");
}
}
int main(void) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaLoad(L, "~/Penlight-1.3.1/lua/pl/compat.lua");
luaLoad(L, "~/Penlight-1.3.1/lua/pl/utils.lua");
luaLoad(L, "~/Penlight-1.3.1/lua/pl/import_into.lua");
luaLoad(L, "mine.lua");
...
}
Я начал пытаться загрузить import_into.lua, который требовал utils.lua и транзитивно compat.lua.
В моем методе luaLoad, если я опускаю lua_pcall, utils.lua "не видит" compat.lua:
utils.lua : module 'pl.compat' not found'
Однако с lua_pcall я получаю
attempt to call a table value' error.
Пытается ли загружать penlight из C в корне неправильно?
Во-первых: lua_pcall
является излишним. luaL_dofile
уже выполняет lua_pcall
. lua_pop
также неверен. Во-вторых: Любая причина, по которой вы не просто изменяете package.path
, так что Lua require
функция могла найти необходимые модули?
Если вы не можете или не хотите этого делать, есть два подхода:
В дополнение к запуску кода модуля вам также нужно сохранить его результат в таблице package.loaded
используя имя модуля в качестве ключа. Таким образом, функция require
вызываемая в коде penlight, может найти эти модули позже.
void luaLoad(lua_State* L, char const* m, const char* f) {
int top = lua_gettop(L);
if (luaL_dofile(L, f)) {
const char* err = lua_tostring(L, -1);
lua_pop(L, 1); /* the 2nd parameter is a number not a stack index! */
throw std::runtime_error("Lua load error");
} else {
lua_settop(L, top+1); /* discard anything but first return value */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); /* get 'package.loaded' */
lua_pushvalue(L, -2); /* 'lua_setfield' needs the return value at stack top */
lua_setfield(L, -2, m); /* store return value as 'package.loaded[m]' */
lus_settop(L, top); /* restore Lua stack */
}
}
Преимущества в том, что вы можете использовать одну и ту же функцию для запуска mine.lua
. Недостатком является то, что вам нужно загрузить модули в правильном порядке, и если один из модулей использует функцию module
, код становится немного сложнее (в основном вы переопределяете части функции Lua require
).
Второй подход - загрузить, но не запускать модули и поместить загруженный код (который является функцией Lua) в таблицу package.preload
с использованием имени модуля в качестве ключа. Функция require
может позже поднять их и запустить оттуда.
void luaPreload(lua_State* L, char const* m, char const* f) {
if (luaL_loadfile(L, f)) {
char const* err = lua_tostring(L, -1);
lua_pop(L, 1);
throw std:runtime_error("Lua load error");
} else {
lua_getglobal(L, "package"); /* there is no shorthand for 'package.preload' */
lua_getfield(L, -1, "preload");
lua_pushvalue(L, -3); /* 'lua_setfield' needs the function at stack top */
lua_setfield(L, -2, m); /* store chunk as 'package.preload[m]' */
lua_pop(L, 3); /* restore Lua stack */
}
}
Преимущества заключаются в том, что в запросе будут автоматически выполняться модули в правильном порядке, а функция module
не требует специальной обработки. Недостатком является то, что вам нужен отдельный код для запуска mine.lua
.
Все эти подходы предполагают, что mine.lua
использует Lua, require
функции для доступа к модулям penlight.