luaL_dofile 在已知好的字节码上失败,在未编译的版本上成功

我制作了一个非常简单的 Lua 引擎,但它似乎拒绝在 lua 控制台中工作的字节码。未编译的版本在引擎中工作。我是不是使用 luac 有什么问题?

我使用给定的命令进行编译并作为 './a.out' 运行。

res/default.lua:

print("Setting up world structure.")

luac 命令:

luac -o res/default.lux res/default.lua

MWE:

#define SCRIPTDIR "res/"

#define THROW_IF_NONZERO(x,m) if((x)!=0) throw std::runtime_error(m);
#define THROW_IF_ZERO(x,m) if((x)==0) throw std::runtime_error(m);

extern "C" {
        #include "lua.h"
        #include "lauxlib.h"
        #include "lualib.h"
}

#include "sys/stat.h"

#include <string>
#include <system_error>
#include <iostream>

using std::string;

class Entity {
        private:
                lua_State *m_lua;
        public:
                Entity() : Entity(nullptr) { }
                Entity(lua_State *lua) : m_lua{lua} { }
                virtual ~Entity() { }
                void load_and_run(string);
};

class WorldEntity : public Entity {
        public:
                WorldEntity(lua_State *lua) : Entity(lua) {
                        luaL_openlibs(lua);
                }
                ~WorldEntity() { }
};

int main() {
        lua_State *lua{nullptr};
        try {
                lua = luaL_newstate();
                WorldEntity eWorld{lua};
                eWorld.load_and_run("default"); // load default.lua/lux
        } catch(std::exception &e) {
                if (lua != nullptr) {
                        lua_close(lua);
                }
                std::cout << "Error: " << e.what() << std::endl;
        }
        return 0;
}

void Entity::load_and_run(string filename) {
        THROW_IF_ZERO(m_lua, "Lua 尚未启动。");
        filename = SCRIPTDIR + filename + ".lux";
        struct stat sb;
        int rc = stat(filename.c_str(), &sb);
        if (rc == -1) {
                filename.pop_back();
                filename += "a";
                rc = stat(filename.c_str(), &sb);
                THROW_IF_NONZERO(rc, "找不到文件!");
        }
        std::cout << "文件:" << filename << std::endl;
        // 目前无法运行已编译的 Lua 脚本,不知道为什么。
        rc = luaL_dofile(m_lua, filename.c_str());
        THROW_IF_NONZERO(rc, "无法加载 lua 文件。");
}

编译命令:

gcc src/bug001mwe.cpp -std=c++14 -llua -lstdc++

来自脚本的正确输出:

文件:res/default.lua
设置世界结构。

字节码的错误输出:

文件:res/default.lux
错误:无法加载 lua 文件。

两个文件,在 lua 控制台输出:

设置世界结构。
点赞
用户5731639
用户5731639

我感到困惑的是,它在 Lua 控制台中可以工作,但在我的程序中无法工作。我在调用 luaL_dofile 之后添加了一个 lua_tostring 的调用,像这样:

rc = luaL_dofile(m_lua, filename.c_str());
std::ostringstream ostr;
ostr << "Could not load lua file. ";
ostr << lua_tostring(m_lua, -1);
THROW_IF_NONZERO(rc, ostr.str());

错误字符串变成了:

Error: Could not load lua file. res/default.lux: version mismatch in precompiled chunk

到底怎么回事?

长话短说,我之前安装了旧版 Lua,因为某些不相关的软件包依赖过时了,旧版的 luac 拦截了 luac 命令并编译成有效但不兼容的字节码。卸载了我不需要的不相关软件包,现在一切都正常了。

故事的道德:始终检查 Lua 栈上的错误字符串,它(可能)会告诉你出了什么问题。

2020-07-08 10:41:15