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环境中如何体面地使用“要求”?
很可能的情况是,"." 不是包含 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 做你想做的事情。
这是 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 表
}
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
好的,最终我找到了一个不错的答案并且任务已经完成,感谢这个答案。
所以,解决方案是在 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]); }