SWIG:Lua - 将 C++ 实例作为 Lua 函数参数传递

我正在使用SWIG将一些c++类导出到Lua。我在SWIG接口文件中声明了boost::filesystem::path,如下所示:

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

现在我想调用在Lua脚本中声明的一个函数,它应该将boost::filesystem::path&作为参数传递给另一个对象。我只需要能够将路径传递给对象。我不需要使用路径对象的任何功能。

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

我将使用其索引从c++中调用Lua函数。

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函数中?

原文链接 https://stackoverflow.com/questions/9455552

点赞
stackoverflow用户734069
stackoverflow用户734069

这实际上相当复杂。 SWIG 的预期使用是创建 Lua 模块。 Lua 脚本应该决定调用什么和什么不调用。它并不是真正意义上的嵌入式使用,你不能直接从应用程序中调用 Lua 代码,然后使用 SWIG 来暴露一些 C++ 对象。

这并不是说不可能,只是复杂。

所有基于 SWIG 的 C++ 对象都作为指针通过 Lua 传递。因此,所有权是个问题;你不能只是把一个指向堆栈对象的指针塞进 Lua 中。

这样做的最安全方式是将对象的新副本传递给 Lua。这样,Lua 拥有该指针的所有权。 SWIG 知道 Lua 拥有指针,会附加一个适当的垃圾回收机制来清理它。所以从记忆方面来看一切都应该没问题。

但要做到这一点需要使用 SWIG 希望完成的适当 "boxing"(此处用一个更好的术语)。这需要使用某些 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, pathType, 1);

SWIG_TypeQuery 获取 SWIG 绑定到 Lua 的任何对象的类型。SWIG_NewPointerObj 需要该类型的指针。这两个都是宏。SWIG_NewPointerObj 让 Lua 拥有指针的所有权;由于 SWIG 的元表,Lua 的垃圾回收器将删除它。此外,SWIG_NewPointerObj 还将对象推送到 lua_State 堆栈上。

一旦它出现在堆栈上,您几乎可以为所欲为。将其从函数返回到 Lua,将其作为参数传递给 Lua 函数,将其放入全局变量等等。它是一个 Lua 值。

现在,如果你将这段代码键入到你的项目中,你很可能会收到一个编译错误,当编译器看到 swig_type_info 时。这个类型在 SWIG 命令行生成的源文件内部定义。

你有两个选择:

  1. 将此源代码放入 .swig 文件本身。是的,真的。你可以在字面上的部分 (即 %{ %} 包围的块) 中在其中定义常规 C++ 函数。这些函数将直接复制到 SWIG 生成的代码中。你可以通过在头文件中放置原型来访问它们。这是最简单和最容易的方法。常常用于创建特殊接口,在该接口中,预先存在的 C++ 函数不适用于 Lua API(或简单地不存在)。

  2. 你可以通过 -external-runtime 参数生成一个包含这些定义的适当头文件。这必须是一个不同的 SWIG 执行步骤,与生成 .cpp 文件的步骤不同。你只需要执行 swig -c++ -lua -external-runtime someheader.h 命令,这就足以获得类型和宏。

    在你想将 SWIG 绑定对象附加到 Lua 中的任何源文件中包含该头文件即可。

2012-02-26 18:42:04