How to let lua load another lua script? - lua

I'm trying to embed Lua 5.2 into my C program.
I want to let the Lua script to be able to require and load another script. How to do it?
Suppose the Lua part has such file structure:
lua_script
- main.lua
+ utils
- custom_loader.lua
+ globals
- scene_globals.lua
- scene_levels.lua
The main.lua will try to require and import functions from custom_loader.lua, and so on...
Is it possible to do this without writing a kind-of wrapper in C?
Can the Lua script automagically just load everything it needs?
(Ps. I don't really need sandboxing for now, so it's okay for the script to do what it want.)

As decribed by the Lua require man page, it searches for the file in a path.
This path can be defined in C.
Have a look to this post : "Setting the global LUA_PATH variable from C++/C"
The require function is very pratical to load modules and libraries defined in .lua files.

Related

Lua: relative import fails from different working directory

I'm trying to repackage into a Docker container some Lua library that is made of the main module and some helper modules. The helper modules are kept inside a subfolder of the library so that imports from the main file are done as
require 'helpers/SomeHelper'
The problem is: because of the way I want the Docker container to work, it would be extremely helpful if I can invoke this library from a different working folder. That is, my call to the main program would be something like
th /app/main.lua
regardless of the actual working directory I'm standing. Unfortunately, relative imports seem to fail when the working directory is different from the directory where the main file is located.
Is there any way I can configure LUA_PATH or any other mechanism to make these imports work correctly? Note that changing the code of the library itself would be a poor solution, as it wasn't developed by me and I would like to be able to update it to newer versions easily.
If you don't care about the working directory, you can just load lfs / LuaFileSytem and use lfs.chdir( src_dir ) to change to the source directory (potentially saving the current working directory with lfs.currentdir( ) first.)
You can also extend the search path of Lua so that it will search those extra directories. The search is driven by package.searchpath. To add a directory /foo/bar/ to the search in a way that supports all normally supported library layouts, add
/foo/bar/?.lua;/foo/bar/?/init.lua to package.path
/foo/bar/?.so (or .dylib or .dll on other OSen) to package.cpath
You can use several ways to extend the path.
One option that works well is to set the LUA_PATH / LUA_CPATH environment variables. (A ;; sequence in one of them will expand to the full default path.) This can be done from .profile or other setup scripts via an earlier export LUA_PATH="..." or (if started from a wrapper script) inline by setting variables just for that call LUA_PATH="..." lua /foo/bar.lua. (Note that if you export this variable in too broad a scope, other Lua scripts will also get their path extended and may find potentially incompatible Lua libraries.)
(You can also manually modify package.(c)path from LUA_INIT. That way, you won't be able to independently disable LUA_INIT or LUA_PATH, but you can use all of Lua to generate the path dynamically.)
A third option (this may be best in your specific case) is to put the extension of package.path at the top of your main script, as in
do
local dir = (arg[0]:match "^(.*)/$")
if dir then -- else cwd is . which works by default
package.path = dir.."/?.lua;"..dir.."/?/init.lua;"..package.path
package.cpath = dir.."/?.so;"..package.cpath
end
end
-- rest of your program goes here
When running a script with the Lua interpreter, arg[0] is the script. So this extends the path to include the program's directory no matter where it is located, and it will only affect the search path of this particular script / program.
You should not forget about that not all modules are loaded from FS directly.
E.g. to improve perfomance it is possible read/compile file to memory and then
use preload table to provide way to load module from memory.
Basic example
--- preload code. It can be done by host application.
local FooUtils = function()
return {
print = function(...)
print("foo", ...)
end
}
end
local Foo = function()
local Utils = require "foo.utils"
return {
foo = function()
Utils.print"hello"
end
}
end
package.preload['foo.utils'] = FooUtils
package.preload['foo'] = Foo
--- main application
require "foo".foo()
In this example assume that FooUtils and Foo just example of compiled modules.
E.g. it can be like FooUtils = loadstring('path/to/utils.lua) and it can be done
even in separate Lua state and then used in any other.
It is important to remember that Foo module have no idea about how host application does lookup of foo.utils.
So there no standart way to provide original file path or relevant paths.
So if you write some module wich relays on relative paths then this module
may be not working in some environments.
So I just suggest use full namespace like require 'foo.utils' instead of require 'utils'

in lua (love2D), i want to import a library in a subfolder, the file in there will not find the next module it requires

So in lua, i want to import a module.
I want to have my "polygon" lib in a subfolder, so i reference it like this
local polygon = require('polygon.polygon')
however, it needs another module called 'delaunay', it cannot find it as it checks the main folder
Is there anyway short of editing my library, to get this to work? (some kind of ability to add search paths?)
Thanks
To know where to look for modules, Lua's require uses the variables package.path (.lua) and package.cpath (.so/.dll). You can change them in your program to look in the directory you have it in. For consistency's sake, you can look at their contents to know which OS-specific separator to use. For example:
local sep = package.path:find("\\") and "\\" or "/"
package.path = package.path .. ";." .. sep .. "polygon" .. sep .. "?.lua"
This would include ./polygon/?.lua into the search path, and a call to require "delaunay" would therefore have the require function look for ./polygon/delaunay.lua in addition to existing paths. Bear in mind that in require strings, . denotes a separator as far as file searching is concerned, so calling require "polygon.delaunay" in this scenario will mean searching for ./polygon/polygon/delaunay.lua.
From what I understand of your question, changing the package.path variable to include the path to where your delaunay library is stored would solve your issue, although to give a specific solution more information about your project and directory structure is required.
All what loaded into package.loaded can be load with require() because require() looks first in package.loaded...
-- Lua 5.3 ( lua -i )
> package.loaded.code=load(code.dump)()
> test=require('code')
> test
function: 0x565cb820
So you can use load() or loadfile('/path/to/your_code.lua') to do this. Another nice feature of this method is to load dumped code...
> package.loaded.shell=loadfile('shell.bin')
> shell=require('shell')
> shell('cat shell.bin')
uaS�
�
xV(w#F#�d�#��F�#G���d#��F�#G���d#&�typestringoexecute
/bin/bash>
In any way, it appears that you will have to deal with the subfolders explicitly.
As in, either the module polygon will have to import delaunay as polygon.delaunay.
Or module names will have to be appended to package.path so that lua could search through subfolders for filenames:
package.path=package.path..";./polygon/?.lua"
More info is here.
It is pointed out in comments, you'd probably want to ensure that path concatenation happens only once.
Also, one should be wary of name shadowing.
Finally, while we are at stirring up the past, a pretty nifty trick to solve the issue was proposed here five years before the question.

Can I separate `init.lua` to different components in Hammerspoon?

I would like to separate init.lua script used in Hammerspoon to enhance the readability and maintainance.
So it looks like the following:
init.lua
AppWatcher.lua
WiFiWatcher.lua
KeyRemap.lua
And then from within init.lua I would read these files and make the watcher activate.
However, it seems that there is no such function defined (maybe I may be missing it, though). Is it possible to separate the logic like that in Hammerspoon?
Yes, you can do this using require.
If you put your Lua files in ~/.hammerspoon/, you can then load them using require('modulename'). For example, if you have the following modules:
~/.hammerspoon/AppWatcher.lua
~/.hammerspoon/WiFiWatcher.lua
~/.hammerspoon/KeyRemap.lua
Then you can load them from ~/.hammerspoon/init.lua like this:
local AppWatcher = require('AppWatcher')
local WiFiWatcher = require('WiFiWatcher')
local KeyRemap = require('KeyRemap')
You can load any Lua modules, as long as they appear in package.path. To see the directories you can use, take a look at HammerSpoon's package.path setup file. This references the default Lua package.path, which is defined in luaconf.h.
If you want to put your Lua modules in a directory not included in package.path, you can do it by adding them to the LUA_PATH_5_3 or LUA_PATH environment variables.

Embedding LuaJIT module into C application

In my application, I have all the Lua libraries exposed from the C backend. Now, I have a need to load a Lua module. The method for this seems to be :
lua_getglobal(L, "require");
lua_pushstring(L, libname);
lua_pcall(L, 1, 0, 0);
which will search the package.path to find <libname>.lua and load it.
Is it possible to build-in the Lua module into the C application (so that the module becomes part of the C application) ? so that I don't have to separately package the Lua module. Somehow I am not able to find any references or examples of this! :(
p.s. I am using LuaJIT-2.0.2, and the library in question is SciLua/Time (uses ffi)
Yes.
luajit -b Module.lua Module_bc.c
will compile a module to bytecode and output a C array initializer containing that bytecode.
If you build with shared libraries enabled and export this array from the main executable, require will find it (and will not need to look for Module.lua.)
To test that it is working, set package.path = "" before requireing the module. If it still works, you know the preload is working and it is not just using the Module.lua file from the current directory.
http://luajit.org/running.html
Other things to keep in mind:
If the module depends on an external file (using io.open), that file still needs to be present. For example some ffi modules try to open a C header file, to pass to ffi.cdef
You need to keep Module_bc.c in sync with Module.lua, e.g. with a Makefile recipe, or you will see some confusing bugs!

Modular code structure in Lua

I've been working with Love2d recently to build a Conway's Game of Life implementation.
I really like the framework, but I haven't been able to figure out how to modularize my code, which I feel is crucial to solid code structure.
What I'm wanting to do is be able to import a file that has different functions in it and be able to access that through my main lua file. I have been able to write scripts and run entire files, but not specific functions.
Is there a way to do this in Lua? If so, how?
Thanks!
You can use the require function in LÖVE. It works similarly to how it works in Lua.
-- lib.lua
local lib = {} -- table to store the functions
function lib.inc(x)
return x + 1
end
return lib
And here is how you require it in another file (for example, main.lua) and use it:
local lib = require('lib')
function love.load()
print(lib.inc(1)) -- prints '2' in the terminal
end
Lua supports modules. Here is a tutorial on using them http://lua-users.org/wiki/ModulesTutorial

Resources