API сложной библиотеки часто можно быстро и почти полностью обернуть, используя SWIG. Преимущество использования SWIG в этом случае заключается в том, что легко создавать оболочки SWIG, которые позволяют использовать библиотеку в 18 major languages, включая, среди прочих, Lua, Perl, Python, Ruby и Java.
Если Lua является вашей предпочтительной (и, возможно, единственной) проблемой, то я бы посоветовал научиться использовать luaL_register()
в основе стратегии создания модулей Lua в C. Преимущество построения модуля таким образом заключается в том, что вы сохраняете все ваши функции в одном пространстве имен без каких-либо накладных расходов. Вам понадобится создать функцию-обертку, которая соответствует соглашению о вызове функции Lua C (как и в случае с lua_register()
), и которая собирает аргументы Lua из стека, вызывает завернутую функцию и выталкивает любое возвращаемое значение и выводит параметры обратно в Стек Lua. Хороший обзор того, как это сделать, можно найти в книге «Программирование в Луа». Онлайн-копия первого издания обсуждает создание библиотеки в Chapter 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
, см. В source to the math
module, который распространяется вместе с Lua. Поскольку эти тонкие обертки содержат много повторяющегося кода, такие инструменты, как SWIG, часто могут создавать их, учитывая только объявление каждой функции.
Способы упаковки класса C++ в принципе аналогичны. Каждой Lua-вызываемой функции-обертки понадобится аргумент, который может быть отображен на this
на стороне C++, и он должен быть реализован либо как модуль-статическая функция, либо статическая функция-член, которая также находит экземпляр целевого объекта, а также преобразует другие аргументы. SWIG особенно хорош в создании такого рода обертки и скрыть много деталей gory на этом пути.
Какая проблема с lua_register у вас на самом деле? Является ли это видимостью функций, объявленных как звездные? –