从 Lua 在活动程序中调用 C++ 函数

2021-12-30 00:00:00 lua c++

我不确定我的问题是否有意义,但我当然知道从 Google 获得结果几乎是不可能的.首先,我不想要什么.我不想调用一些打印hello world"或将两个数字相加的函数,我想从 C++ 程序加载 Lua 脚本,但允许脚本使用函数修改 C++ 程序的变量.例如,假设我有一个这样的 C++ 程序:

I'm not sure if my question makes any sense, but I certainly know it is near impossible to get the results from Google. Firstly, what I do not want. I don't want to call some function that prints "hello world" or adds two numbers together, I want to load a Lua script from a C++ program, but allow the script to modify variables of the C++ program, using functions. For example, imagine I have a C++ program like this:

class Foo
{
    private:
        int number = 0;

    public:
        void setNumber(const int& newNumber) {number = newNumber;}
}

int main()
{
    Foo foo;

    //Load and execute Lua script, with foo object

    return 0;
}

我如何允许 Lua 脚本执行 foo.setNumber()(最好没有 foo.)?这可能是一个很简单的问题,但是如上所述,几乎所有关于谷歌的信息当搜索Call C++ Function from Lua"时假设没有程序,只有一个 .cpp/hpp 文件,其中包含一些您想要调用的函数.

How could I allow the Lua script to do foo.setNumber() (preferably without foo.)? This may be a very simple question, but as mentioned above, almost all information on Google when searching "Call C++ Function from Lua" assume there is no program, but just a .cpp/hpp file with some functions that you want to call.

我使用的是 Linux (Ubuntu),但程序需要在所有平台(Windows 和 Mac)上编译

I'm on Linux (Ubuntu), but the program needs to compile on all platforms (Windows and Mac)

推荐答案

这里经常被问到这个问题.

This is asked here fairly regularly.

要滚动您自己的绑定,您应该:

To roll your own binding you should:

  1. 完全掌握 Lua 元表.
  2. 阅读在 Lua 中编程内容C API,特别是关于类的部分.或者,您可以阅读手册、阅读源代码(尤其是 API 标头)并进行一些谷歌搜索,但这本书可能会为您节省一些时间.
  1. Master Lua metatables completely.
  2. Read the Programming in Lua stuff on the C API, particularly the part on classes. Alternatively you can read the manual, read the source (API headers especially), and do some googling, but the book will probably save you some time.

从广义上讲,您可以通过创建一个包含指向类实例的指针的 Lua用户数据"并将其传递给 Lua 脚本来向 Lua 公开 C++ 类实例.用户数据是一种不透明类型;Lua 脚本实际上不能用它做任何事情(除了传递它),除非你给它一个元表.至少你必须在用户数据上实现 __index 元方法,它允许你的 C++ 代码拦截尝试索引用户数据并返回一些有意义的东西,以及 __gc 元方法,这允许您的 C++ 代码在相应的 Lua 用户数据被垃圾收集时删除暴露的 C++ 对象.

Broadly, you expose a C++ class instance to Lua by creating a Lua "userdata" containing a pointer to the class instance and passing this to the Lua script. A userdata is an opaque type; the Lua script can't actually do anything with it (other than pass it around) unless you give it a metatable. At the very least you must implement the __index metamethod on the userdata, which allows your C++ code to intercept attempts to index the userdata and return something meaningful, and the __gc metamethod, which allows your C++ code to delete the exposed C++ object when the corresponding Lua userdata is garbage collected.

例如,您创建一个名为 createFoo 的函数,它创建一个 Foo 实例,将指针包装为用户数据,应用实现 __index 到它,并将其返回给 Lua 脚本.

For instance, you create a function called createFoo which creates a Foo instance, wraps the pointer as a userdata, applies a metatable implementing __index to it, and returns it to the Lua script.

当用户运行 foo.setNumber 时,您的 C++ __index 元方法将使用用户数据和字符串setNumber"调用.返回什么取决于您,这决定了 foo.setNumber 在 Lua 脚本中的计算结果.您希望 foo.setNumber 计算为 lua_CFunction ,它期望 Foo 用户数据作为其第一个参数,以便可以惯用地调用您的类方法来自 Lua(即 foo:setNumber(12),它是 foo.setNumber(foo, 12) 的语法糖).

When the user runs foo.setNumber, your C++ __index metamethod is called with the userdata and the string "setNumber". It's up to you what you return and this determines what foo.setNumber evaluates to in the Lua script. You want foo.setNumber to evaluate to a lua_CFunction which expects a Foo userdata as its first parameter, so that your class methods can be called idiomatically from Lua (i.e. foo:setNumber(12), which is syntax sugar for foo.setNumber(foo, 12)).

这是一个非常低级的手动过程,一旦你掌握了它的窍门,你最终会创建一个库/模板/宏来为你做样板.那时您可能想要评估存在的无数 C++ 绑定库.然而,多亏了抽象抽象法则,学习如何做是一个很好的主意首先手动.

It's a very low level and manual process, and once you get the hang of it you're going to end up create a library/templates/macros whatever to do the boilerplate for you. At that point you may want to evaluate the myriad C++ binding libraries that exist. However, thanks to the Law of Leaky Abstractions it's a very good idea to learn to do this manually first.

相关文章