Реализация сценариев Lua
Вопрос
В настоящее время я работаю над внедрением Lua в одно из приложений, над которыми я работаю.В настоящее время я просто использую C api и регистрирую функции с помощью lua_register, но я хотел бы иметь возможность передавать статические и нестатические указатели на функции определенным методам класса.
Я нашел определенные библиотеки в сети, но поскольку мне нужно очень мало из общей функциональности, которую они предоставляют, мне было интересно, есть ли простой способ сделать это.
Спасибо.
Решение
Сложный библиотечный API часто может быть быстро и (почти) полностью обернут с помощью ГЛОТОК.Преимущество использования SWIG в этом случае заключается в том, что легко создавать оболочки на основе SWIG, которые позволяют использовать библиотеку в 18 основных языков включая Lua, Perl, Python, Ruby и Java, среди прочих.
Если Lua является вашей предпочтительной (и, возможно, единственной) заботой, то я бы рекомендовал научиться использовать luaL_register()
в основе стратегии создания модулей Lua на C.Преимущество создания модуля таким способом заключается в том, что вы сохраняете все свои функции в одном пространстве имен без каких-либо накладных расходов.Вам нужно будет создать функцию-оболочку, которая соответствует соглашению о вызове функции Lua C (точно так же, как вы делаете с lua_register()
) и это собирает аргументы Lua из стека, вызывает обернутую функцию и отправляет любое возвращаемое значение и выходные параметры обратно в стек Lua.Хороший обзор того, как это сделать, можно найти в книге "Программирование в Lua".Онлайн-копия первого издания обсуждает создание библиотеки в Глава 26, но был написан для Lua 5.0.Я настоятельно призываю всех, кто серьезно использует Lua, приобрести копию текущей версии PiL.
К сожалению, одна из областей, где Lua 5.1 больше всего отличается от 5.0, заключается в динамической загрузке модулей (как C, так и Lua) с require
.
Вот полный (хотя и небольшой) пример библиотеки C, которая работает в Lua 5.1.Мы начинаем с реализации оболочки в файле C:
#include <lua.h>
#include <luaxlib.h>
#include <math.h>
#undef PI
#define PI (3.14159265358979323846)
static int l_sin (lua_State *L) {
double r = luaL_checknumber(L,1);
lua_pushnumber(L, sin(r));
return 1;
}
static int l_cos (lua_State *L) {
double r = luaL_checknumber(L,1);
lua_pushnumber(L, cos(r));
return 1;
}
static const struct luaL_reg smlib [] = {
{"sin", l_sin},
{"cos", l_cos},
{NULL, NULL} /* sentinel */
};
int luaopen_sm (lua_State *L) {
luaL_openlib(L, "sm", smlib, 0);
lua_pushnumber(L,PI);
lua_rawset(L,-2,"pi");
return 1;
}
Обратите внимание, в частности, что единственной функцией, которую необходимо экспортировать, является luaopen_sm()
, имя которого должно соответствовать имени модуля , который будет использоваться с require
, и с именем DLL-файла.С этим файлом, скомпилированным как DLL с именем sm.dll
(вероятно, названный libsm.so
в Unix-подобных системах), затем его можно загрузить и использовать в скрипте Lua, подобном этому:
require "sm" print(sm.sin(sm.pi/3), sm.cos(sm.pi/3));
Этот пример, хотя и непроверенный, должен быть скомпилирован и запущен.Для полного примера, обертывающего большинство функций из math.h
, смотрите на источник для math
модуль это распространяется с помощью Lua.Поскольку эти тонкие оболочки содержат много повторяющегося кода, такие инструменты, как SWIG, часто способны создавать их, учитывая только объявление каждой функции.
Обертывание методов класса C ++ аналогично по принципу.Каждой вызываемой на Lua функции-оболочке потребуется аргумент, который может быть сопоставлен с this
на стороне C ++, и она должна быть реализована либо как модульно-статическая функция, либо как статическая функция-член, которая также определяет местонахождение экземпляра целевого объекта, а также преобразует другие аргументы.SWIG особенно хорош в создании такого рода оболочки и скрывает множество кровавых деталей на этом пути.