lua require函数在iOS上找不到我所需的文件

时间:2014-03-18 22:52:04

标签: ios lua require

我是lua的新手,这可能很简单,但我无法弄清楚。我整夜搜索,在这里阅读一些帖子,但不是我想要的。我终于找到了一个我不满意的蹩脚解决方案,所以我来这里寻求帮助。

我试图在l ++中嵌入lua,这个程序将作为iPhone上应用程序的一部分运行,我们知道,每个iPhone应用程序都有一个资源包,而lua脚本随捆绑包一起分发

// I printed out the bundle path:
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")

但这是一条绝对的道路,绝对应该避免。 解决这个问题的一种方法是从c提供lua函数,它在运行时将ipa包中的lua文件的完整路径返回到lua脚本,并将package.path与该路径连接起来,但我认为不应该这样做。是"官员"这样做的方式。

我注意到" ./?。lua"在package.path变量中,我只是想知道为什么找不到mylib.lua,对于同一目录中的文件是不是?

对不起,所以问题是:我怎么做"要求"在iOS环境中体面?

3 个答案:

答案 0 :(得分:1)

好的,我终于找到了一个好的答案,工作已经完成,感谢this answer

因此,解决方案是修改c ++代码中的路径,添加此函数

#include <string>

int setLuaPath(lua_State* L, const char* path) {
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "path"); // get field "path" from table at top of stack (-1)
    std::string cur_path = lua_tostring(L, -1); // grab path string from top of stack
    cur_path.append(";"); // do your path magic here
    cur_path.append(path);
    lua_pop(L, 1); // get rid of the string on the stack we just pushed on line 5
    lua_pushstring(L, cur_path.c_str()); // push the new one
    lua_setfield(L, -2, "path"); // set the field "path" in table at -2 with value at top of stack
    lua_pop(L, 1); // get rid of package table from top of stack
    return 0; // all done!
}

然后,在init 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

impl文件:

// 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]);
}

答案 1 :(得分:0)

最有可能,“。”不是包含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,请参阅Section 6 of Lua ref man

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

答案 2 :(得分:0)

这是对苔藓植物答案的修订。对我来说,这太复杂了。我也不确定他为什么要做所有这些额外的类并使用C ++字符串而不是NSStrings。以下是基于此解决方案修改并希望更容易理解的iOS代码:

-(void)addBundlePathToLuaState:(lua_State*)L
{ 
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "path"); // get field "path" from table at top of stack (-1)

    const char* current_path_const = lua_tostring(L, -1); // grab path string from top of stack
    NSString* current_path = [NSString stringWithFormat:@"%s;%@/?.lua", current_path_const, [[NSBundle mainBundle]resourcePath]];

    lua_pop(L, 1); // get rid of the string on the stack we just pushed on line 5
    lua_pushstring(L, [current_path UTF8String]); // push the new one
    lua_setfield(L, -2, "path"); // set the field "path" in table at -2 with value at top of stack
    lua_pop(L, 1); // get rid of package table from top of stack
}