How to structure internal dependencies in a Lua library? - lua

I'm struggling to figure out how to structure and then use internal dependencies in a Lua library I'm writing.
I've defined my library like this:
./alib.lua
./alib/adependency.lua
And the code:
-- File: ./alib.lua
local ad = require "alib.adependency"
module( "alib")
return {}
-- File: ./alib/adependency.lua
module( "adependency" )
return {}
This works a treat:
$ lua alib.lua
<no output>
Now let's "add" this library into another app:
./anapp.lua
./lib/alib.lua
./lib/alib/adependency.lua
And the new code:
-- File: ./anapp.lua
local alib = require "lib.alib"
local print = print
module( "anapp")
print "Hello"
Try to run it:
$ lua anapp.lua
lua: ./lib/alib.lua:2: module 'alib.adependency' not found:
no field package.preload['alib.adependency']
no file './alib/adependency.lua'
no file '/usr/local/share/lua/5.1/alib/adependency.lua'
no file '/usr/local/share/lua/5.1/alib/adependency/init.lua'
no file '/usr/local/lib/lua/5.1/alib/adependency.lua'
no file '/usr/local/lib/lua/5.1/alib/adependency/init.lua'
no file '/usr/share/lua/5.1/alib/adependency.lua'
no file '/usr/share/lua/5.1/alib/adependency/init.lua'
no file './alib/adependency.so'
no file '/usr/local/lib/lua/5.1/alib/adependency.so'
no file '/usr/lib/x86_64-linux-gnu/lua/5.1/alib/adependency.so'
no file '/usr/lib/lua/5.1/alib/adependency.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './alib.so'
no file '/usr/local/lib/lua/5.1/alib.so'
no file '/usr/lib/x86_64-linux-gnu/lua/5.1/alib.so'
no file '/usr/lib/lua/5.1/alib.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
[C]: in function 'require'
./lib/alib.lua:2: in main chunk
[C]: in function 'require'
anapp.lua:2: in main chunk
[C]: ?
Oh dear. Now I make a manual edit inside the library:
-- File: ./lib/alib.lua
-- local ad = require "alib.adependency" -- Doesn't work
local ad = require "lib.alib.adependency" -- Works
module( "alib")
return {}
And it works:
$ lua anapp.lua
Hello
It seems that Lua's require() relates paths relative to the ultimate script being run by Lua, not the script in which the require() is called.
Surely you don't have to manually fix the internal paths require()d inside of a Lua library every time you add one to your project... And I don't see how this can work from a unit test perspective either. What am I doing wrong?

I think the cleanest solution is to leave your library as it was, and then make whomever is using your library responsible for configuring the package.path correctly. In your setup that means the application should add the lib folder to the path:
package.path = './lib/?.lua;' .. package.path
See also related questions like Is there a better way to require file from relative path in lua as well as the manual for more about the path.

Related

How to properly import a lua script from a lower directory into another one, +Hammerspoon

I am trying to create an organized library for lu functions to be configured in the hammerspoon init script, however the import syntax that I have found online doesnt seem to work the same way, or perhaps i am ignorant to something..
I have seen answers that you can require them directly if they are in the same directory, but for the sake of organization I am curious if this is possible
init.lua:
local web_elem_poc = require "web_elements/web_elem_poc.lua"
doc = {}
function doc.init()
web_elem_poc.helloWorld("1234")
end
web_elem_poc.lua:
function web_elem_poc.helloWorld(content)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"}, "W",
function()
hs.alert.show(content)
end
)
end
return 0
Hammerspoon error:
{...}
web_elements/web_elem_poc.dylib'
no file '~/.local/share/hammerspoon/site/lib/web_elements/web_elem_poc.dylib'
no file '~/.local/share/hammerspoon/site/lib/web_elements/web_elem_poc.so'
stack traceback:
[C]: in function 'rawrequire'
...poon.app/Contents/Resources/extensions/hs/_coresetup.lua:662: in function 'require'
/Users/AVONSTU1/.hammerspoon/init.lua:1: in main chunk
[C]: in function 'xpcall'
...poon.app/Contents/Resources/extensions/hs/_coresetup.lua:723: in function 'hs._coresetup.setup'
(...tail calls...)
Can someone please spot the issue?
I am using Hammerspoon and hitting refresh config.
I have tried several forms of require including as you see using the import as an object and refering to it that way and just importing the script and using the function directly.
In the init.lua file, you will want to import the file web_elements.web_elem_poc without the extension by using the following code:
local web_elem_poc = require "web_elements.web_elem_poc"
web_elem_poc.helloWorld("This is cool!")
In the web_elem_poc.lua file, you will need to define the web_elem_poc module and the helloWorld function as follows:
local web_elem_poc = {}
function web_elem_poc.helloWorld(content)
print("This is web_elem_poc.helloWorld with content: ".. content)
end
return web_elem_poc
Assuming that the directory structure looks like this:
<>/init.lua
<>/web_elements.web_elem_poc.lua
You should see the message This is web_elem_poc.helloWorld with content: This is cool! printed on the console.

How to require a shared object file (nuklear.so) from a subdirectory in Love2D?

For a small game, I'm trying out the love-nuklear library to create UIs. I've successfully built the .so by following the exact instructions provided by the author, see this section.
When nuklear.so is placed in the same directory as my main.lua file, nuklear = require('nuklear.so') imports the library correctly, and is accessible when I run $ love ..
However for better organization, I've decided to move nuklear.so into a subdirectoy lib/, where other lua modules are also imported. But now in main.lua, when using nuklear = require('lib.nuklear'), then running $ love . in the project root directory, the following error is produced:
Error: error loading module 'lib.nuklear' from file './lib/nuklear.so':
./lib/nuklear.so: undefined symbol: luaopen_lib_nuklear
stack traceback:
[string "boot.lua"]:637: in function <[string "boot.lua"]:633>
[C]: at 0x7ff27837fc00
[C]: in function 'require'
main.lua:4: in main chunk
[C]: in function 'require'
[string "boot.lua"]:475: in function <[string "boot.lua"]:311>
[C]: in function 'xpcall'
[string "boot.lua"]:645: in function <[string "boot.lua"]:639>
[C]: in function 'xpcall'
How should I correctly relocate my shared object from the project root directory to its lib/ subdirectory?
By default when loading a C library, Lua looks for a function in the library named luaopen_x, where x is the module name with . replaced with _ (and with some other transformations), and runs it. (See the documentation for package.searchers.) In this case the module name lib.nuklear results in the function name luaopen_lib_nuklear. But the function is actually named luaopen_nuklear, so Lua doesn't find it and can't load the library.
To fix this, you can add ./lib/?.so to package.cpath before loading the library with require "nuklear": package.cpath = package.cpath .. ";./lib/?.so". Then Lua will look for luaopen_nuklear in ./lib/nuklear.so. This will allow you to load other .so libraries in that directory.
Getting the source code of nuklear.so and renaming luaopen_nuklear to luaopen_lib_nuklear and recompiling would also work, but would be kind of silly and wouldn't solve the problem for other C libraries in the same directory.

require module fails in love2d fused executable, but succeeds when running love.exe on my project folder

I followed the steps on the love2d wiki to make a fused executable for my game. When I launch the resulting fused exe, I get the below error:
Error: main.lua:12: module 'util/strict' not found:
no field package.preload['util/strict']
no 'util/strict' in LOVE game directories.
no file 'util/strict.dll' in LOVE paths.
no file 'flowerpowers/scripts/util/strict.lua'
no file 'flowerpowers/data/util/strict.lua'
stack traceback:
[C]: in function 'require'
main.lua:12: in main chunk
[C]: in function 'require'
[string "boot.lua"]:429: in function <[string "boot.lua"]:275>
[C]: in function 'xpcall'
However, when I run my game by dragging the folder (i.e. the one that mirrors the contents of the zip I made in the fusing process: both directly contain main.lua, conf.lua and all the subfolders of my project) onto love.exe, it works like a dream.
Here's the top of my main.lua, up until the line it crashes on (note: the commented out BASEDIR was an attempt to get it to work, but it broke both the fused exe and the drag-folder method):
io.stdout:setvbuf("no")
love.keyboard.setKeyRepeat(true)
BASEDIR = "flowerpowers"
-- BASEDIR = ""
package.path = BASEDIR..'/scripts/?.lua;'..BASEDIR..'/data/?.lua'
package.cpath = ""
package.preload = {}
require "util/strict"
I've tried various combinations of individual solutions I saw suggested on similar questions, but nothing seems to work: appending package.path to the string I'm setting for package.path above, using "\\" instead of "/", using "." instead of "/", explicitly including all subfolders in the project in my package.path string, and removing subfolders from the require targets. Nothing works, unfortunately.
This is what my folder structure looks like:
+ FlowerPowers (the folder that I zip the contents of, not including the folder itself)
- main.lua
- conf.lua
+ data (contains other files and folders)
+ scripts (contains other files and folders, but only listing relevant ones)
+ util
- strict.lua
+ bin
- love.exe
- [love DLLs]
+ distro
- FlowerPowers.exe (fused executable)
- [love DLLs]
Hopefully that's enough information to get started, but if I can provide any other info that would be helpful, just let me know. Totally stumped as to why it works when running my folder on love.exe, but not when they've been fused.
EDIT: My fused exe seems to work when it is run from a folder that also contains my entire project folder (i.e. FlowerPowers in the above structure). But if that folder is missing, I get this crash.
EDIT #2: Got the solution! Details here: https://love2d.org/forums/viewtopic.php?f=4&t=83142&p=206049#p206049
Working code here:
BASEDIR = love.filesystem.getRealDirectory("/scripts"):match("(.-)[^%.]+$")
BASEDIR = string.sub(BASEDIR, 1, string.len(BASEDIR)-1)
local myPath = BASEDIR..'/scripts/?.lua;'..BASEDIR..'/data/?.lua'
local myPath2 = 'scripts/?.lua;/data/?.lua'
package.path = myPath
love.filesystem.setRequirePath( myPath2 )

Lua require doesn't work on directories

I have been given some skeleton code for an assignment from my professor in lua. The code has several require statements that add packages to the current directory. The problem I am having is that many of these require statements are not requiring a .lua file, they require a directory containing many lua files. For instance, I have a directory qtwidget with a single file in it: init.lua
In the skeleton code, this package is referenced like this:
local w = qtwidget.newwindow(width,height,"Energy surface")
So that's all fine and dandy, but when I run the skeleton code I get the following error:
dofile('/data/mar608/BigData/src/optim/demo2.lua')
error loading module 'qttorch' from file '/usr/local/pkg/torch/share/torch/lua/qttorch':
cannot read /usr/local/pkg/torch/share/torch/lua/qttorch: Is a directory
stack traceback:
[C]: ?
[C]: in function 'require'
/data/me/BigData/src/optim/demo2.lua:36: in main chunk
[C]: in function 'dofile'
[string "dofile('/data/mar608/BigData/src/optim/demo..."]:1: in main chunk
[C]: ?
What's going on? Why doesn't lua understand this require statement? Is there any way I need to chance my package.path variable that will solve this problem? I need to be able to do this for many directories (i.e. specify the directories name and have lua load all it's files into a single name to be referenced later)
1) Do you have /usr/local/pkg/torch/share/torch/lua/qttorch/init.lua ?
2) Do you have .../?/init.lua entry in package.path ?
Example: /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.

Loading in Lua Modules via Require (TLC)

I'm trying to use https://github.com/aptiva/TLC
I try:
$ echo $LUA_PATH; echo "====="; find .; echo "====="; luajit-2.0.0-beta10 examples/window.lua
I get:
?;?.lua;./?/init.lua
=====
.
./examples
./examples/talkingcomputer.lua
./examples/window.lua
./lst
./objc
./objc/BridgeSupport.lua
./objc/dispatch.lua
./objc/init.lua
./README.md
=====
luajit-2.0.0-beta10: error loading module 'objc' from file 'objc':
cannot read objc: Is a directory
stack traceback:
[C]: ?
[C]: in function 'require'
examples/window.lua:5: in main chunk
[C]: ?
My question: what am I doing wrong? How do I load in the objc module?
Thanks!
Add ./?/init.lua to LUA_PATH.
Some further explanation on why the accepted solution works.
When a module is required, Lua uses environment variable LUA_PATH to find the location of the required module. The special symbol '?' is a wildcard that matches any string, thus when require("module") and LUA_PATH="?;./?.lua", Lua will search for 'module' and 'module.lua' in the current directory.
In the question above LUA_PATH was originally defined as:
LUA_PATH="?;?.lua;"
Once the solution was posted, the user added ./?/init.lua at the end of LUA_PATH, however it didn't work. The reason why it didn't work was that when Lua tries to solve require('objc') objc matches the first entry in LUA_PATH (?), and objc is a directory, thus the error.
The solution is to add ./?/init.lua at the beginning of LUA_PATH:
LUA_PATH="./?/init.lua;?.lua;?;"
With regard to LUA_PATH, it's important to notice that unlike environment variable PATH, directories are separated by semicolon (";"). Another way of specifying what directories to search from, it's using Lua variable package.path (inside a Lua file):
package.path = "./?/init.lua;"..package.path
local objc = require("objc")

Resources