lua require function does not find my required file on iOS - ios

I'm new to lua, this might be something quite simple, but I couldn't figure it out. I did all night search, read some posts here, but are not quite what I'm looking for. I finally worked out a lame solution that i'm not happy with, so I'm here to ask for help.
I'm trying to embed lua inside c++, and this program will run as part of an app on the iPhone, as we know, every iPhone app has a resource bundle, and the lua scripts are distributed with the bundle.
// I printed out the bundle path:
bundle directory /var/mobile/Applications/C6CEF090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app
Say I have two script files (main.lua, mylib.lua) in the same folder, I put them in my Xcode project, organized like this:
somefolder
|--main.lua
|--mylib.lua
and main.lua is as below:
--main.lua
print(package.path)
require("mylib")
obviously I want to use code from mylib.lua, however, I got error from 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')
When I add a line modifying package.path, I got it running correctly:
--main.lua modified
print(package.path)
package.path = package.path .. ";/var/mobile/Applications/C6CEF090-B99A-4B9B-ADAC-F0BEF46B6EA4/LuaThirdTry.app/?.lua"
require("mylib")
But this is an absolute path, which should definitely be avoided.
One way to solve this problem is to provide lua a function from c, which returns the full path of lua file in ipa bundle at runtime to lua script, and concatenate the package.path with that path, but I think that shouldn't be the "official" way of doing this.
I noticed "./?.lua" inside package.path variable, I just wonder why mylib.lua can't be found, isn't it for files within the same directory?
Sorry for the blah, so the question is: how do I do the "require" decently in iOS environment?

Okay, I finally find a good answer and the job is done, thank to this answer.
So, the solution is to modify the path within c++ code, add this function
#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!
}
and then, call this function when 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());
....
}
your oc_caller class might look like this:
// OCCaller.h
#ifndef __LuaThirdTry__OCCaller__
#define __LuaThirdTry__OCCaller__
#include <iostream>
class OCCaller {
public:
OCCaller();
~OCCaller();
std::string get_ios_bundle_path();
};
#endif
impl file:
// 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]);
}

Most likely, "." is not the folder containing main.lua, but a working directory (such as where xcode runs from). The app that runs your script probably runs it via a path, like
lua /full/path/to/your/main.lua
So having ./?.lua in LUA_PATH does not help here. Instead, you should have the script run a command to determine where it is running from, and append that to package.path. This should be the path part of arg[0]. So you could try (not tested):
local scriptPath = arg[0]
local dir = string.match(scriptPath, '^.*/')
package.path = package.path .. ';' .. dir .. '?.lua'
The arg is automatically populated by the interpreter, see Section 6 of Lua ref man.
You definitely don't need C to do what you want.

This is a revision on Bryophyte's answer. To me, this was far too complex. I'm also not sure why he did all these extra classes and used C++ strings instead of NSStrings. Here is my revised and hopefully easier to understand iOS code based on this solution:
-(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
}

Related

Why does my code crash when libvlc_media_new_path() is called?

after several days of trying myself to solve my problem I would like to kindly ask for your help:
I am trying to make the libvlc / SDL 2.0 tutorial working.
I am coding in Visual Studio 2022 in x86 C++ Console.
I have linked the libvlc library path and include path and have added the libvlc.lib file in my project linker settings.
The program compiles without error and crashes when libvlc_media_new_path is called.
You see all different formats of path I have used in my minimal reproducible example below:
My sources:
I downloaded the vlc master from Github to get the headers / include directory.
I downloaded the vlc-3.0.17.4-win32 release and from there took the libvlc.dll.
From the libvlc.dll I created the lib file following a visual studio command prompt procedure.
What i noticed is that the function libvlc_media_new_path() only takes the path as an argument now. All examples i find in the internet are with the libvlc instance AND the path as arguments.
Thank you so much for your help!
#include <stdlib.h>
#include "vlc/vlc.h"
int main(int argc, char* argv[]) {
libvlc_instance_t* libvlc;
libvlc_media_t* m;
libvlc_media_player_t* mp;
libvlc = libvlc_new(0, NULL);
if (NULL == libvlc) {
printf("LibVLC initialization failure.\n");
return EXIT_FAILURE;
}
m = libvlc_media_new_path("/1.mp4");
//m = libvlc_media_new_path("C:\\Programmieren\\PACA\\1.mp4");
//m = libvlc_media_new_path("C:/Programmieren/PACA/1.mp4");
//m = libvlc_media_new_path("C://Programmieren//PACA//1.mp4");
//m = libvlc_media_new_path("C:\Programmieren\PACA\1.mp4");
//m = libvlc_media_new_path("file:///C:/Programmieren/PACA/1.mp4");
mp = libvlc_media_player_new_from_media(libvlc, m);
return 0;
}
If you go to Github and click on the Tags link, you can get the headers for version 3.0.17.4. In there you will see that libvlc_media_new_path takes an instance as an argument.
The other option would be to get or build the 3.0.18 DLL.

Reading characters within a file (the fseek command) not working in nxc (not-exactly-c) programming

Basically I'm trying to write code that reads a specified value from a file ex: file contains(12345) the code reads specific place (say the 3rd place) and the output = 3
I already know how to write numbers to a file but I am stuck on how to read a character because the fseek command won't work (it doesn't know what the command is). I downloaded the include folder with all the extra commands but it still couldn't find the file "stdio.h" in the code.
I don't completely know how it all works anyway
I am a complete noob in programing and so I only know the very basic stuff. I am 90% sure it is my fault it isn't working.
#include "cstdio.h." //gets error (doesn't recognize command/file)
task main ()
{
byte handle;
int fsize = 100;
int in;
int sus = 12345;
DeleteFile("int.txt");
CreateFile("int.txt",100,handle);
Write(handle, sus);
CloseFile(handle);
OpenFileRead("int.txt",fsize,handle);
fseek(handle, 10, 3); //gets error (doesn't recognize command)
in = fgetc(handle);
ClearScreen();
NumOut(30,LCD_LINE5,in);
Wait(100000);
CloseFile(handle);
}

Find the path to the executable

I compile a program with Go for various platforms and run it by calling a relative path or just by its name (if it is in the PATH variable).
Is it possible to find out where the executable is?
Say, my program is called "foo(.exe)". I can run ./foo, foo (if it's in the PATH), ../../subdir/subdir/foo.
I have tried to use os.Args[0] and I guess I should check if the program name contains something different besides "foo". If yes, use filepath.Abs, if no, use (I can't find the function name, there is a function that looks through the PATH to check where the program is).
Use package osext.
It's providing function Executable() that returns an absolute path to the current program executable.
It's portable between systems.
Online documentation
package main
import (
"github.com/kardianos/osext"
"fmt"
)
func main() {
filename, _ := osext.Executable()
fmt.Println(filename)
}
You can use os.Executable for getting executable path on Go 1.8 or above version.
import (
"os"
"path"
"log"
)
func main() {
ex, err := os.Executable()
if err != nil { log.Fatal(err) }
dir := path.Dir(ex)
log.Print(dir)
}
This is not go-specific (unless the go "standard library" contains some function to do it), and there is no portable solution. For solutions on some common platforms, see e.g. How do I find the location of the executable in C? or Finding current executable's path without /proc/self/exe .

Illegal text-relocation error, how to embed a text file?

I am currently developing an application in which the first step its to load a text file and read its contents.
For example:
string file = "myfile.txt";
i am calling another function in which i want to look for a certain pattern/occurrence
void read(string pattern, const char *content) {
char subString [blocksize];
int n;
char *search = pattern;
pos = strstr(content,search);
.....
The function works perfectly on my Mac, but once I try to compile the application the compiler throws some error ld : illegal text-relocation.
The text file is in the same folder as the target app.
I'm assuming this has something to do with embedding the text file?
hope someone can help or give a hint !
thanks in advance

Loading a C Module in Lua

I am trying to load the example lproc program (described on Programming Lua, Chapter 30) into Lua and fouling up somehow. I am following this - http://www.lua.org/pil/26.2.html to get my c module into lua. Following are the steps that I've taken:
I have an lproc.h and lproc.c (containing exactly the functions laid out in Chapter 30 of the book). I am compiling lproc.c as --- gcc -c lproc.c -DLUA-USERCONFIG=\"lproc.h\"
I made a library out of lproc.o, named the same.
And then compiled lua.c as instructed. My header files contain the macro LUA_EXTRALIBS and the method declarations.
Went to the Lua interpreter and it gave the following errors:
> require "lproc"
stdin:1: module 'lproc' not found:
no field package.preload['lproc']
no file './lproc.lua'
no file '/opt/local/share/lua/5.1/lproc.lua'
no file '/opt/local/share/lua/5.1/lproc/init.lua'
no file '/opt/local/lib/lua/5.1/lproc.lua'
no file '/opt/local/lib/lua/5.1/lproc/init.lua'
no file './lproc.so'
no file '/opt/local/lib/lua/5.1/lproc.so'
no file '/opt/local/lib/lua/5.1/loadall.so'
stack traceback:
[C]: in function 'require'
stdin:1: in main chunk
[C]: ?
It seems that the module did not get registered, what would I need to do from Lua? Time is short and I am doing something horrendously wrong, any direction would be welcome.
Thanks,
Sayan
Here is a complete and fully portable minimal example of building a C library for Lua (works in Lua 5.1-5.3 and LuaJIT, for any platform):
With this example.c:
#include <lua.h>
int example_hello(lua_State* L) {
lua_pushliteral(L, "Hello, world!");
return 1;
}
int luaopen_example(lua_State* L) {
lua_newtable(L);
lua_pushcfunction(L, example_hello);
lua_setfield(L, -2, "hello");
return 1;
}
Put this rockspec file in the same directory, named example-1.0-1.rockspec:
package = "example"
version = "1.0-1"
source = {
url = "." -- not online yet!
}
build = {
type = "builtin",
modules = {
example = "example.c"
}
}
Then, run luarocks make. It will build the C code with the correct flags for your platform.
Your module is now ready to use!
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
> example = require("example")
> print(example.hello())
Hello, world!
>
The easiest way is to create a shared library and load your C module dynamically. This way avoids having to rebuild the Lua interpreter. There are several examples in http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/ and explanations in http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/install.html and http://lua-users.org/wiki/BuildingModules

Resources