为了避免当时的库问题,我只是将Lua src树添加到我的Xcode项目中并按原样编译,没有任何问题.
是时候更新到更现代的Lua版本,所以我用5.1.4替换了源代码树.我使用make macosx重建了luac(机器在Intel上运行Leopard).
与往常一样,未编译的脚本在Tiger和Leopard,Intel和PPC中正常工作.
但是,现在编译的脚本无法在PPC计算机上加载.
所以我用’ansi’标志重建了luac,并重新编译了我的脚本.同样的错误.同样,’generic’的构建标志也没有产生任何乐趣.
谁能告诉我接下来能做些什么?
Lua的编译脚本几乎是在短标题之后转储的原始字节码.头文件记录了用于编译字节码的平台的一些属性,但加载器仅验证当前平台具有相同的属性.不幸的是,这会在加载在另一个平台上编译的字节码时产生问题,即使是由相同版本的Lua编译也是如此.当然,不能期望由不同版本的Lua编译的脚本工作,并且由于Lua的版本号包含在字节码头中,因此加载它们的尝试被核心捕获.
简单的答案是不编译脚本.如果Lua编译脚本本身,您只需要担心应用程序的各种版本中的Lua核心之间可能存在版本不匹配,这并不难解决.
实际上,支持已编译字节码的完全交叉兼容性是not easy.在该电子邮件中,Mike Pall确定了以下问题:
Endianess: swap on output as needed.
sizeof(size_t)
, affects huge string constants: check for overflow when
downgrading.
sizeof(int)
, affectsMAXARG_Bx
andMAXARG_sBx
: check for overflow when
downgrading.
typeof(lua_Number)
: easy in C, but only when the host and the target
follow the same FP standard; precision
loss when upgrading (rare case);
warn about non-integer numbers when
downgrading toint32
.
从我在邮件列表中看到的有关此问题的所有讨论中,我看到了两种可行的方法,假设您不愿意考虑只发送未编译的Lua脚本.
第一个是在加载编译脚本时修复字节顺序.事实证明这比你期望的更容易,因为它可以通过替换读取脚本文件的低级函数而不重新编译核心本身来完成.实际上,它甚至可以在纯Lua中完成,方法是将您自己的chunk reader函数提供给lua_load().只要您的平台上唯一的兼容性问题是字节顺序,这应该可以工作.
第二种是修补核心本身,以便在所有平台上使用编译脚本的通用表示.这已被描述为Luiz Henrique de Figueiredo:
….
I’m convinced that the best route to
byte order or cross-compiling is
third-party dump/undump pairs. The
files ldump.c and lundump.c are
completely replaceable; they export a
single, well-defined, entry point. The
format of precompiled chunks is not
sacred at all; you can use any format,
as long as ldump.c and lundump.c agree
about it. (For instance, Rici Lake is
considering writing a text format for
precompiled chunks.)
….
就个人而言,我建议认真考虑不预先编译脚本,从而完全避免平台可移植性问题.
编辑:由于lhf的评论,我已经更新了我对字节码标题的描述.我还没有读过Lua源代码的这一部分,我可能应该先检查它,然后对标题中是否存在哪些信息非常自信.
这是来自lundump.c
的片段,它形成与运行平台匹配的标头的副本,用于与正在加载的字节码进行比较.它只是与memcmp()进行比较,以便与文件中的标题完全匹配,因此任何不匹配都会导致库存加载程序(luaU_undump()
)拒绝该文件.
/* * make header */ void luaU_header (char* h) { int x=1; memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); h+=sizeof(LUA_SIGNATURE)-1; *h++=(char)LUAC_VERSION; *h++=(char)LUAC_FORMAT; *h++=(char)*(char*)&x; /* endianness */ *h++=(char)sizeof(int); *h++=(char)sizeof(size_t); *h++=(char)sizeof(Instruction); *h++=(char)sizeof(lua_Number); *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ }
可以看出,头部长度为12个字节并且包含签名(4个字节,“< esc> Lua”),版本和格式代码,用于字节序的标志字节,类型int的大小,size_t,指令和lua_Number,以及指示lua_Number是否为整数类型的标志.
这允许捕获大多数平台区别,但不会尝试捕获平台可以区别的各种方式.
我仍然支持上面提出的建议:首先,提供可编辑的来源;或者第二,定制ldump.c和lundump.c来存储和加载一个通用格式,另外注意任何自定义格式都应重新定义标题的LUAC_FORMAT字节,以免与stock字节码格式混淆.