zoukankan      html  css  js  c++  java
  • c++自动导出lua绑定

    cocos 使用bindings-generator脚本代替了toLua++. 编写效率大大提高。

    具体的在本机中分享:

    bindings-generator脚本的工作机制是:

    1、不用挨个类地写桥接.pkg和.h文件了,直接定义一个ini文件,告诉脚本哪些类的哪些方法要暴露出来,注册到Lua环境里的模块名是什么
    2、摸清了toLua++工具的生成方法,改由Python脚本动态分析C++类,自动生成桥接的.h和.cpp代码,不调用tolua++命令了
    3、虽然不再调用tolua++命令了,但是底层仍然使用toLua++的库函数,比如tolua_function,bindings-generator脚本生成的代码就跟使用toLua++工具生成的几乎一样


    bindings-generator脚本掌握了生成toLua++桥接代码的主动权,不仅可以省下大量的.pkg和.h文件,而且可以更好地插入自定义代码,达到cocos2d-x环境下的一些特殊目的,比如内存回收之类的。

    接下来说怎么用bindings-generator脚本:

    1、写自己的C++类,按照cocos2d-x的规矩,继承cocos2d::Ref类,以便使用cocos2d-x的内存回收机制。
    2、编写一个.ini文件,让bindings-generator可以根据这个配置文件知道C++类该怎么暴露出来
    3、修改bindings-generator脚本,让它去读取这个.ini文件
    4、执行bindings-generator脚本,生成桥接C++类方法
    5、将自定义的C++类和生成的桥接文件加入工程,不然编译不到
    6、修改AppDelegate.cpp,执行桥接方法,自定义的C++类就注册进Lua环境里了


    看着步骤挺多,其实都狠简单。下面一步一步来。

    1.首先是自定义的C++类。我习惯将文件保存在frameworks/runtime-src/Classes/目录下:

    frameworks/runtime-src/Classes/MyClass.h

    #include "cocos2d.h"usingnamespace cocos2d;
    
    class MyClass : public Ref
    {
    public:
      MyClass()   {};
      ~MyClass()  {};
      boolinit(){ returntrue; };
      CREATE_FUNC(MyClass);
    
      intfoo(int i);
    };
    

    frameworks/runtime-src/Classes/MyClass.cpp

    #include "MyClass.h"int MyClass::foo(int i)
    {
      return i + 100;
    }
    

    2.然后编写.ini文件。在frameworks/cocos2d-x/tools/tolua/目录下能看到genbindings.py脚本和一大堆.ini文件,这些就是bindings-generator的实际执行环境了。随便找一个内容比较少的.ini文件,复制一份,重新命名为MyClass.ini。大部分内容都可以凑合不需要改,这里仅列出必须要改的重要部分:

    frameworks/cocos2d-x/tools/tolua/MyClass.ini

    [MyClass]prefix = MyClasstarget_namespace = myheaders = %(cocosdir)s/../runtime-src/Classes/MyClass.hclasses = MyClass
    

    也即在MyClass.ini中指定MyClass.h文件的位置,指定要暴露出来的类,指定注册进Lua环境的模块名。

    然后修改genbindings.pyMyClass.ini文件加进去:

    3.frameworks/cocos2d-x/tools/tolua/genbindings.py

    cmd_args = {'cocos2dx.ini' : ('cocos2d-x', 'lua_cocos2dx_auto'), 
                'MyClass.ini' : ('MyClass', 'lua_MyClass_auto'), 
                ...
    

    4.至此,生成桥接文件的准备工作就做好了,执行genbindings.py脚本:

    python ./genbindings.py
    

    成功执行genbindings.py脚本后,会在frameworks/cocos2d-x/cocos/scripting/lua-bindings/auto/目录下看到新生成的文件:

    每次执行genbindings.py脚本时间都挺长的,因为它要重新处理一遍所有的.ini文件,建议大胆修改脚本文件,灵活处理,让它每次只处理需要的.ini文件就可以了,比如像这个样子:

    在frameworks/cocos2d-x/cocos/scripting/lua-bindings/auto/目录下观察一下生成的C++桥接文件lua_MyClass_auto.cpp,里面的注册函数名字为register_all_MyClass(),这就是将MyClass类注册进Lua环境的关键函数:

    5.编辑frameworks/runtime-src/Classes/AppDelegate.cpp文件,首先在文件头加入对lua_MyClass_auto.hpp文件的引用:

    然后在正确的代码位置加入对register_all_MyClass函数的调用:

    如何是lua工程则在:lua_module_register.h 中添加上述调用。

    最后在执行编译前,将新加入的这几个C++文件都加入到Xcode工程中,使得编译环境知道它们的存在:

    这其中还有一个小坑,由于lua_MyClass_auto.cpp文件要引用MyClass.h文件,而这俩文件分属于不同的子项目,互相不认识头文件的搜寻路径,因此需要手工修改一下cocos2d_lua_bindings.xcodeproj子项目的User Header Search Paths配置。特别注意一共有几个../:

    最后,就可以用cocos compile -p mac命令重新编译整个项目了,不出意外的话编译一定是成功的。

    修改main.lua文件中,尝试调用一下MyClass类:

    localtest = my.MyClass:create()
    print("lua bind: " .. test:foo(99))
    
    6.android上运行的话需要做的事情是要将生成的桥接文件lua_MyClass_auto.cpp放到android.mk中。
    

    配置ini时需要注意的选项:

      • [title]:要配置将被使用的工具/ tolua的/ gengindings.py脚本的称号。一般来说,标题可以是文件名。

      • prefix:要配置一个函数名的前缀,通常,我们还可以使用文件名作为前缀 生成函数一次为前缀。

      • target_namespace:要配置在脚本层模块的名字。在这里,我们使用cc作为模块名,当你想在脚本层REF的名称,您必须将一个名为前缀,CC在名称的前面。例如,CustomClass可以参考作为cc.CustomClass。

      • headers:要配置所有需要解析的头文件和%(cocosdir)s是的Cocos2d-x的引擎的根路径。

      • classes:要配置所有绑定所需的类。在这里,它支持正则表达式。因此,我们可以设置MyCustomClass。*在这里,用于查找多个特定的用法,你可以对照到tools/tolua/cocos2dx.ini。

      • skip:要配置需要被忽略的功能。现在绑定发电机无法解析的void *类型,并委托类型,所以这些类型的需要进行手动绑定。而在这种情况下,你应该忽略所有这些类型,然后再手动将它们绑定。你可以对照到配置文件路径下的cocos/scripting/lua-bindings/auto 。

      • rename_functions:要配置的功能需要在脚本层进行重命名。由于某些原因,开发者希望更多的脚本友好的API,所以配置选项就是为了这个目的。

      • rename_classes:不在使用。

      • remove_prefix:不在使用。

      • base_classes_to_skip = #当被它们的子类发现的时候会跳过的基类

    • classes_have_no_parents:要配置是过滤器所需要的父类。这个选项是很少修改。

    • abstract_classes:要配置的公共构造并不需要导出的类。

    • script_control_cpp:是的。要配置脚本层是否管理对象的生命周期。如果没有,那么C++层关心他们的生命周期。
      现在,它是不完善的,以控制原生对象的续航时间在脚本层。所以,你可以简单地把它设置为no。

    有几篇值得参考的笔记。都是本人使用过且自动生成成功的经验总结。
    文章编辑格式copy自己的有道云笔记,格式太乱。但是笔记可以以看得。如下笔记讲述的是原理和过程。

    作者:Four
    链接:https://www.zhihu.com/question/35082562/answer/129615490
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    浅析Vue CompositionAPI和React Hooks对比:hook的意义、两者差别(原理链表/Proxy、代码执行每次渲染都执行/组件创建时运行、声明响应式状态、如何跟踪依赖、生命周期、自定义hook、Ref获取元素、计算属性附加函数、Context和provide/inject、在渲染上下文中暴露值)
    算法设计和数据结构学习_1(一道堆排序作业题)
    总结系列_14(OpenCV2.4.3的新特征以及安装方法)
    Kinect+OpenNI学习笔记之8(Robert Walter手部提取代码的分析)
    基础学习笔记之opencv(21):一个简单有趣的皮肤检测代码
    基础学习笔记之opencv(16):grabcut使用例程
    Eigen初步1:初步体验Eigen库
    基础学习笔记之opencv(19):有关图像序列的直方图计算
    基础学习笔记之opencv(17):皮肤检测类CvAdaptiveSkinDetector的使用
    ChaLearn Gesture Challenge_4:one shot learning比赛结果简单分析
  • 原文地址:https://www.cnblogs.com/mokey/p/8041787.html
Copyright © 2011-2022 走看看