SWIG: Lua - передача экземпляра c ++ в качестве параметра функции lua - PullRequest
2 голосов
/ 26 февраля 2012

Я экспортирую некоторые классы с ++ в Lua с помощью SWIG.Я объявил boost :: filesystem :: path в файле интерфейса SWIG следующим образом:

namespace boost
{
    namespace filesystem
    {
        class path {};
    }
}

Теперь я хочу вызвать функцию, объявленную в скрипте lua, которая должна принять boost :: filesystem :: path &в качестве параметра, чтобы передать его другому объекту.Мне нужно только пройти путь к объекту.Мне не нужно использовать какую-либо функциональность из объекта path.

function on_path_selected(the_path)
    another_object:set_path(the_path)
end

Я собираюсь вызвать функцию Lua из c ++, используя ее индекс.

lua_rawgeti(L, LUA_REGISTRYINDEX, m_function_index);
lua_push[SOMETHING](L, path_object); // <-- HOW TO ?
lua_pcall(L,1,0,0)

ВОПРОС: Каквставить boost :: filesystem :: path в качестве параметра функции Lua?

1 Ответ

6 голосов
/ 26 февраля 2012

Это на самом деле довольно сложно.Ожидаемое использование SWIG - создание модулей для Lua.Скрипт Lua должен решать, что вызывать, а что нет.На самом деле он не предназначен для встроенного использования, когда вы используете SWIG для предоставления некоторых объектов C ++, а затем вызываете код Lua непосредственно из вашего приложения.

Это не означает, что это невозможно, просто сложно.

Все основанные на SWIG объекты C ++ передаются через Lua как указатели.Таким образом, собственность является вопросом;Вы не можете просто вставить указатель на объект стека в Lua.

Самый безопасный способ сделать это - передать новую копию объекта Lua.Таким образом, Луа владеет указателем.SWIG будет знать, что Lua владеет указателем, и присоединит к нему надлежащий механизм сбора мусора, чтобы очистить его.Таким образом, все должно быть хорошо, с точки зрения памяти.

Но для этого требуется должным образом "боксировать" (если не сказать лучшего термина), чтобы объект возражал так, как этого хочет SWIG.Это требует использования определенных макросов SWIG.

Учитывая, как вы связали тип path с SWIG, вы бы сделали что-то вроде этого, чтобы вставить его в стек Lua:

swig_type_info *pathType = SWIG_TypeQuery("boost::filesystem::path *");
boost::filesystem::path *pArg = new boost::filesystem::path(the_path);
SWIG_NewPointerObj(L, pArg, outputType, 1);

SWIG_TypeQuery выбирает тип любого объекта, который был привязан SWIG к Lua.Информационный объект этого типа необходим для SWIG_NewPointerObj, который принимает указатель на этот тип.Оба из них являются макросами.SWIG_NewPointerObj дает Lua право владения указателем;Сборщик мусора Lua удалит его благодаря метатаблицам SWIG.Также SWIG_NewPointerObj помещает объект в стек lua_State.

Как только он окажется в стеке, вы можете делать с ним все, что захотите.Верните его из функции в Lua, передайте его функции Lua в качестве аргумента, вставьте в глобальную переменную и т. Д. Это значение Lua.

Теперь, если вы введете этот код в свой проект, шансыхорошо, что вы получите ошибку компиляции, когда компилятор увидит swig_type_info.Этот тип определяется внутренне в исходном файле, сгенерированном командной строкой SWIG.

У вас есть две опции:

  1. Поместите этот исходный код всам файл .swig.Да, действительно.Вы можете определить обычные функции C ++ там, в пределах дословных разделов (блоки с разделителями %{ %}).Эти функции будут скопированы непосредственно в сгенерированный код SWIG.Вы можете получить к ним доступ, поместив прототипы в заголовки.Это самый простой и легкий способ работы.Это часто используется для создания специальных интерфейсов, где ранее существующая функция C ++ не подходит для Lua API (или просто не существует).

  2. Вы можете сгенерировать соответствующийзаголовок, содержащий эти определения с аргументом -external-runtime.Это должен быть шаг выполнения SWIG, отличный от шага, который генерирует файл .cpp.Видите, на самом деле он не обрабатывает файл SWIG или что-то еще.Все, что ему нужно, это целевой язык (-lua) и то, используете ли вы C ++ (-c++). Поэтому просто введите команду, которая выполняет swig -c++ -lua -external-runtime someheader.h, и это все, что вам нужно для получения типов и макросов.

    Включите этот заголовок в любой источник, к которому вы хотите присоединить объекты, привязанные к SWIG, в Lua.

...