lua require函数在iOS系统上找不到我需要的文件。

我是lua的新手,这可能很简单,但我想不出来。我整夜找了一些帖子,但都不太是我要找的。我最终想出了一个烂解决方案,我对此不满意,所以我在这里寻求帮助。

我正在尝试将lua嵌入c ++中,并且该程序将作为iPhone上某个应用程序的一部分运行,我们知道,每个iPhone应用程序都有一个资源束,并且lua脚本与该捆绑软件一起分发。

//我打印输出了捆绑路径:
bundle directory /var/mobile/Applications/C6CEF090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app

假设我在同一个文件夹中有两个脚本文件(main.lua,mylib.lua)。我将它们放在我的Xcode项目中,组织如下:

somefolder
|--main.lua
|--mylib.lua

main.lua如下所示:

--main.lua
print(package.path)
require("mylib")

很明显,我希望使用mylib.lua中的代码,但是,我从lua vm中得到了错误:

/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua
PANIC: unprotected error in call to Lua API (...090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app/test.lua:5: module 'mylib' not found:
    no field package.preload['mylib']
    no file '/usr/local/share/lua/5.2/mylib.lua'
    no file '/usr/local/share/lua/5.2/mylib/init.lua'
    no file '/usr/local/lib/lua/5.2/mylib.lua'
    no file '/usr/local/lib/lua/5.2/mylib/init.lua'
    no file './mylib.lua'
    no file '/usr/local/lib/lua/5.2/mylib.so'
    no file '/usr/local/lib/lua/5.2/loadall.so'
    no file './mylib.so')

当我添加一行修改package.path的代码时,我可以正确运行:

--main.lua modified
print(package.path)
package.path = package.path .. ";/var/mobile/Applications/C6CEF090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app/?.lua"
require("mylib")

但这是绝对路径,肯定应该避免使用。解决此问题的一种方法是为lua提供一个来自c的函数,在运行时向lua脚本返回ipa捆绑包中lua文件的完整路径,并将package.path与该路径连接起来,但我认为这不应是这样做的“正式”方式。

我注意到package.path变量中的“./?.lua”,我只是想知道为什么找不到mylib.lua,它不是针对同一目录中的文件吗?

抱歉,这个问题有点啰嗦,那么问题是:在iOS环境中如何体面地使用“要求”?

点赞
用户1317816
用户1317816

好的,最终我找到了一个不错的答案并且任务已经完成,感谢这个答案

所以,解决方案是在 C++ 代码中修改路径,添加这个函数:

#include <string>

int setLuaPath(lua_State* L, const char* path) {
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "path"); // 从栈顶的 table (-1) 中获取“path”项
    std::string cur_path = lua_tostring(L, -1); // 获取栈顶的路径字符串
    cur_path.append(";"); // 在这里执行路径操作
    cur_path.append(path);
    lua_pop(L, 1); // 弹出第五行刚刚推入的字符串
    lua_pushstring(L, cur_path.c_str()); // 推入新路径
    lua_setfield(L, -2, "path"); // 把堆栈中栈顶的 value 设为 table(-2)中的“path”项
    lua_pop(L, 1); // 弹出栈顶的 package table
    return 0; // 完成!
}

然后,在 Lua_State 初始化的时候调用这个函数:

// yourfile.cpp
void runLua() {
    lua_State *L;
    L = luaL_newstate();
    luaL_openlibs(L);

    OCCaller oc_caller;
    std::string bundlePath = oc_caller.get_ios_bundle_path();
    bundlePath.append("/?.lua");
    setLuaPath(L, bundlePath.c_str());

    ....
}

你的 oc_caller 类可能长成这样:

// OCCaller.h
#ifndef __LuaThirdTry__OCCaller__
#define __LuaThirdTry__OCCaller__

#include <iostream>

class OCCaller {
public:
    OCCaller();
    ~OCCaller();
    std::string get_ios_bundle_path();

};

#endif

实现文件:

// OCCaller.mm
#include "OCCaller.h"
#import <Foundation/Foundation.h>

OCCaller::OCCaller() { }
OCCaller::~OCCaller() { }

std::string OCCaller::get_ios_bundle_path() {
    NSString *bundlePath = [[NSBundle mainBundle]resourcePath];
    return std::string([bundlePath UTF8String]);
}
2014-03-19 00:20:41
用户869951
用户869951

很可能的情况是,"." 不是包含 main.lua 的文件夹,而是工作目录(例如 xcode 运行的位置)。运行脚本的应用程序可能会通过路径来运行它,比如:

lua /full/path/to/your/main.lua

因此,在 LUA_PATH 中输入 ./?.lua 在这里无济于事。相反,你应该让脚本运行一个命令来确定它正在从哪里运行,并将其附加到 package.path 中。这应该是 arg[0] 的路径部分。所以你可以尝试(未经过测试):

local scriptPath = arg[0]
local dir = string.match(scriptPath, '^.*/')
package.path = package.path .. ';' .. dir .. '?.lua'

arg 是解释器自动填充的,参见 Lua 参考手册第 6 节

你绝对不需要用 C 做你想做的事情。

2014-03-19 04:57:10
用户864663
用户864663

这是 Bryophyte 回答的修订版。对我来说,这太过复杂了。我也不确定为什么他会创建所有这些额外的类并使用 C++ 字符串而不是 NSStrings。下面是基于这个解决方案的我的修订版 iOS 代码,希望更容易理解:

-(void)addBundlePathToLuaState:(lua_State*)L
{
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "path"); // 获取堆栈顶部表的 "path" 字段(-1)

    const char* current_path_const = lua_tostring(L, -1); // 获取堆栈顶部的路径字符串
    NSString* current_path = [NSString stringWithFormat:@"%s;%@/?.lua", current_path_const, [[NSBundle mainBundle]resourcePath]];

    lua_pop(L, 1); // 获取我们在第 5 行推入堆栈的字符串
    lua_pushstring(L, [current_path UTF8String]); // 推入新路径
    lua_setfield(L, -2, "path"); // 用堆栈顶部值设置表中 -2"path" 字段
    lua_pop(L, 1); // 获取堆栈顶部的 package 表
}
2014-08-12 20:02:26