[√]lua binding模版文件分析

124 阅读2分钟

layout_head.h和layout_foot.h控制头文件

image.png

layout_head.c 和layout_foot.c控制注册入口

image.png

头文件目录的问题

image.png 文件位置是在Classes/tools/LuaAssistant.h,正确的应该是

#include "tools/LuaAssistant.h"

通过看layout_head.c

#for header in $headers
    #set relative = os.path.relpath(header, $search_path)
    #if not '..' in relative
\#include "${relative.replace(os.path.sep, '/')}"
    #else
\#include "${os.path.basename(header)}" <- 命中了这个逻辑导致的
    #end if
#end for

$search_path有关系

gen_opts = {
    'search_path': os.path.abspath(
        os.path.join(
            userconfig.get('DEFAULT', 'cocosdir'),
            'cocos'
        )
    ),
}

这里的最终变量值为: search_path='e:\proj\tank5\client\frameworks\cocos2d-x\cocos'

我增加一个runtime_classes_path即可,再调整下layout_head.c

#for header in $headers
    #set relative = os.path.relpath(header, $search_path)
    #if not '..' in relative
\#include "${relative.replace(os.path.sep, '/')}"
    #else
      #set relative1 = os.path.relpath(header, $runtime_classes_path)
      #if not '..' in relative1
\#include "${relative1.replace(os.path.sep, '/')}"  
      #else 
\#include "${os.path.basename(header)}"
      #end if
    #end if
#end for

遇到的一个问题

正常情况下,生成的lua-binding代码

// 定义指针变量
cocos2d::Texture2D* arg0;
// 将lua层的值赋给arg0,对to_object来说,他需要的是二级指针
ok &= luaval_to_object<cocos2d::Texture2D>(tolua_S, 2, "cc.Texture2D",&arg0, "cc.GarbageCollection:addGcIgnoreWithTexture");
// 传递给接口
bool ret = cobj->addGcIgnoreWithTexture(arg0);

不能满足需求的binding代码如下

 cocos2d::Vec2* arg2;
 // 对luaval_to_vec2来说,它需要args2是一个可写的内存区域,显然这部分binding代码有问题
 ok &= luaval_to_vec2(tolua_S, 4, &arg2, "MapUtil:Pixel2Grid");
 cocos2d::Vec2 ret = MapUtil::Pixel2Grid(arg0, arg1, arg2);

Pixel2Grid函数的c++实现如下,第三个参数是一个指针,本意是希望外部分配好内存,接口内部修改就行了

Vec2 Pixel2Grid(Vec2 pixel, bool needPosInGrid = false, Vec2* out = nullptr){}

所以我修改了luabing的处理逻辑

def to_string(self, generator):
    # ...
    if self.is_pointer and name.endswith('*'):
        name = name[:-1] #将*去掉了

最终生成的binding代码如下

cocos2d::Vec2 arg2;// 定义为局部变量
ok &= luaval_to_vec2(tolua_S, 4, &arg2, "MapUtil:Pixel2Grid");
//                                                  取地址
cocos2d::Vec2 ret = MapUtil::Pixel2Grid(arg0, arg1, &arg2);

binding代码是符合了预期,但是让流程变得不通用,导致其他binding出现了问题

解决办法只能暂时手动修改了

本质原因,如果参数是Vec2*指针类型,说明数据来自lua层,就需要定义为局部变量

sfunction.c中arg.to_string($generator)决定了参数类型是怎么生成的

总结

使用cheetah模版lua binding也存在局限性,灵活性还有学习成本有点高,其实js的模版引擎有很多,在生态方面也要比python更好,并且配套的vscode体验也非常好,不过碍于当年nodejs并没有起来,所以只能选择使用python。

我使用过的js模版引擎有ejsjade

EJS(Embedded JavaScript)和 Jade(现在改名为 Pug)都是流行的模板引擎,用于在服务器端生成 HTML 或其它文本格式的内容。它们具有不同的语法和特性。

以下是 EJS 和 Pug(Jade)的简介和使用方法:

EJS:

  • 语法更接近于原生的 JavaScript,使用 <% %> 标签来执行 JavaScript 代码,使用 <%= %> 来输出变量值。
  • 可以直接在模板中嵌入 JavaScript 代码,非常灵活。
  • 支持循环和条件语句等常见控制结构。
  • 安装 EJS:npm install ejs

使用示例:

const ejs = require('ejs');
const template = 'Hello, <%= name %>!';
const html = ejs.render(template, { name: 'Alice' });
console.log(html);

Pug(Jade):

  • 使用缩进代替大括号来表示代码块,使用类似于 CSS 选择器的语法来描述 HTML 结构。
  • 语法简洁、优雅,减少了冗余的标记符号。
  • 支持混合(mixins)和布局(layout)的功能,方便地重用代码和组织页面结构。
  • 安装 Pug(Jade):npm install pug

使用示例:

const pug = require('pug');
const template = `html
  head
    title My Page
  body
    h1 Hello, #{name}!`;
const compiledTemplate = pug.compile(template);
const html = compiledTemplate({ name: 'Alice' });
console.log(html);