Accessing Lua Functions On Other Files - lua

Hi I want to separate my Lua file into two files. One that holds my functions and one that can call them. I have done a lot of research on this and all the resources I find do not explain this process very indepth. They typically say to use:
require "subsystem.lua"
I put this at the top of a new Lua file that is saved to the same directory and am not able to access anything.
Is there a config file I need to modify? Where is it?

Require the module
The require function looks in a series of places to find a module. The exact list of places can be extensively customized by adjusting fields in the global table package.
The easiest way to get a sense of how many places and names it uses when looking for a module is to look at the error message produced when require fails. For example, on my PC, Lua 5.1 says this:
C:\Users\Ross>lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> require "xyzzy"
stdin:1: module 'xyzzy' not found:
no field package.preload['xyzzy']
no file '.\xyzzy.lua'
no file 'C:\Program Files (x86)\Lua\5.1\lua\xyzzy.lua'
no file 'C:\Program Files (x86)\Lua\5.1\lua\xyzzy\init.lua'
no file 'C:\Program Files (x86)\Lua\5.1\xyzzy.lua'
no file 'C:\Program Files (x86)\Lua\5.1\xyzzy\init.lua'
no file 'C:\Program Files (x86)\Lua\5.1\lua\xyzzy.luac'
no file '.\xyzzy.dll'
no file '.\xyzzy51.dll'
no file 'C:\Program Files (x86)\Lua\5.1\xyzzy.dll'
no file 'C:\Program Files (x86)\Lua\5.1\xyzzy51.dll'
no file 'C:\Program Files (x86)\Lua\5.1\clibs\xyzzy.dll'
no file 'C:\Program Files (x86)\Lua\5.1\clibs\xyzzy51.dll'
no file 'C:\Program Files (x86)\Lua\5.1\loadall.dll'
no file 'C:\Program Files (x86)\Lua\5.1\clibs\loadall.dll'
stack traceback:
[C]: in function 'require'
stdin:1: in main chunk
[C]: ?
>
After looking internally, the first "real" place it looks for xyzzy is in the file named .\xyzzy.lua. Then it tries a number of folders and names in the folder where lua.exe was found. Finally, it looks for a DLL that might offer it. The list of folders it searches for a .lua file is controlled by the string value in package.path. (The comparable list for DLLs in is package.cpath.) In that value, require will replace each ? with the module name, and then attempt to read the file. The first one to succeed is used.
(The story here is slightly more complicated; you can create "searchers" that require will use to look in different places, and even change the order of the built-in searchers, but that is an advanced topic.)
So just putting modules in Lua files in the current directory should work just fine, and adjusting package.path before calling require for your own modules can cover most quirks you will encounter.
Create a module to require
At its simplest, a module is just something that can be stored in package.loaded. Which is what require will do with it once it has been found, so that multiple calls to require will only search once and always return the same value.
The traditional answer is for that "something" to be a table, usually mostly populated by functions that can be called, and occasionally having values. The math module is a good example: it provides lots of functions like sin and cos, along with the useful value math.pi and math.huge.
Aside from being stored in a table, there is nothing special about a function in a module. Like any other function, it takes parameters and return zero or more values. The only real rule is that a module should not change or add global variables.
So a very minimal module file can be as simple as:
return {
addtwo = function(a, b) return a+b end,
subtwo = function(x) return x-2 end,
}
which if stored as example.lua could be used like this:
local example = require "example"
print(example.addtwo(2,2)) -- 4
print(example.subtwo(42)) -- 40
A better module skeleton
Sticking all your code in a single table declaration will not fly for most real cases. It does not scale well, and it makes it difficult to clearly express the relationship among functions that share state.
-- simple modules
-- capture the name searched for by require
local NAME=...
-- table for our functions
local M = { }
-- A typical local function that is also published in the
-- module table.
local function addtwo(a,b) return a+b end
M.addtwo = addtwo
-- Shorthand form is less typing and doesn't use a local variable
function M.subtwo(x) return x-2 end
return M
Why no call to the module() function?
Lua 5.1 included a standard function named module() intended to be used at the top of module implementations. Its use was never required, and a consensus formed fairly quickly that it was not as helpful an idea as hoped. It has since been deprecated.
As a result, the simple skeleton I show above does not use it, and is portable to all versions of Lua since 5.1.

What you need to do is to return a table with the fields you want to access in subsystem.lua and then assign and use fields from that table in your main file. Something along these lines:
-- subsystem.lua
local function doSomething()
-- do something useful here
end
local function doMore()
-- do something else useful
end
return { doSomething = doSomething, doMore = doMore }
-- main.lua
local subsystem = require "subsystem" -- don't add `.lua` to your `require` call
subsystem.doSomething()
subsystem.doMore()
You may want to check Modules tutorial for details.

You probably want to use dofile instead of require.
dofile accepts file names, with paths.
require accepts module names and uses Lua search paths.

Related

Require looks for .dll files instead of my modules?

So i've been trying to figure this out, im doing the following
main.lua:
package.path = io.popen("cd"):read'*all' -- to set the path the same as main.lua (for exporting)
local u = require("utilities") -- this is the line that dosent work
utilities.lua:
local u = {}
function u.GetService(s)
return require(tostring(s))
end
function u.Wait(s)
local ntime = os.clock() + s/10
repeat until os.clock() > ntime
end
function u.NPWait(s)
local ntime = os.time() + s
repeat until os.time() > ntime
end
return u
The error:
module 'utilities' not found:
Then here goes a search that DOES look in the correct folder, however it looks for .dll files
Require has never been something I've been good at, Sometimes I get it to work, sometimes it breaks like this, if someone can help me understand how to fix this then thank you, as this has been annoying me every so often
You're misunderstanding package.path.
Unlike the PATH variable used by windows and linux, in Lua you don't just tell it what directory to look in but also what the files should look like.
What you're doing is erasing the default search paths completely and replacing it with a broken path that won't find any files.
Generally speaking, to add a new directory to your path, you should add both C:\path\to\your\files\?.lua, and C:\path\to\your\files\?\init.lua, which are the two ways Lua loads modules by default.
You also shouldn't replace package.path, because you're keeping modules from being loaded elsewhere.
Your code should look somewhat like this:
local cd = io.popen("cd")
package.path = cd:read('*line') .. "\\?.lua;" .. package.path
cd:close()
The reason why it's still looking for DLL files is that package.cpath is separate, so you're not changing that.
require("utilities.lua") should work.
You have to specify how to get from the required name to the file. For example by adding a path and a file extension to it.
If you want to require c:\folder\script.lua with require("script") your package.path must contain something like c:\folder\?.lua where ? is replaced by the required name.
If you have your module in a folder with its name and let's say a init.lua for that module the path is c:\folder\?\init.lua
Just print the original package.path and see what's inside befor you overwrite it.
Refer to Lua Reference Manual 6.3 Modules: package.searchpath
A path is a string containing a sequence of templates separated by
semicolons. For each template, the function replaces each
interrogation mark (if any) in the template with a copy of name
wherein all occurrences of sep (a dot, by default) were replaced by
rep (the system's directory separator, by default), and then tries to
open the resulting file name.
For instance, if the path is the string
"./?.lua;./?.lc;/usr/local/?/init.lua" the search for the name foo.a will try to open the files ./foo/a.lua, ./foo/a.lc, and
/usr/local/foo/a/init.lua, in that order.

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.

Require custom C module in Lua by path

This is a problem that plagued me for quite a while.
After I wrote and compiled my custom functions into a shared library, require('mylib') would only work when the shared library was directly in the same directory as the script I called it from.
Any efforts to try require('/path/to/mylib') or similar absolute paths failed. Furthermore, "backtracking" through a relative path (i.e. using .. failed as well.
So how can one specify the bin directory, or wherever the shared library is output to?
Well according to the Lua documentation on the require call (using Lua 5.2 here), there are a few places the loader looks for these loadable modules.
It seems that require() uses what are called "searchers" (docs linked to in above) to determine where to find these modules. There are four searchers in total. From the docs:
The first searcher simply looks for a loader in the package.preload
table.
The second searcher looks for a loader as a Lua library, using the
path stored at package.path. The search is done as described in
function package.searchpath.
The third searcher looks for a loader as a C library, using the path
given by the variable package.cpath. Again, the search is done as
described in function package.searchpath. For instance, if the C path
is the string "./?.so;./?.dll;/usr/local/?/init.so" the searcher for module foo will try to open the files ./foo.so, ./foo.dll, and
/usr/local/foo/init.so, in that order. Once it finds a C library, this
searcher first uses a dynamic link facility to link the application
with the library. Then it tries to find a C function inside the
library to be used as the loader. The name of this C function is the
string "luaopen_" concatenated with a copy of the module name where
each dot is replaced by an underscore. Moreover, if the module name
has a hyphen, its prefix up to (and including) the first hyphen is
removed. For instance, if the module name is a.v1-b.c, the function
name will be luaopen_b_c.
The fourth searcher tries an all-in-one loader. It searches the C path
for a library for the root name of the given module. For instance,
when requiring a.b.c, it will search for a C library for a. If found,
it looks into it for an open function for the submodule; in our
example, that would be luaopen_a_b_c. With this facility, a package
can pack several C submodules into one single library, with each
submodule keeping its original open function.
The searcher of use to us is the third one: it is used for any shared libraries (.dll or .so) which is generally how our custom C modules are built.
Using the template string (the one with the question marks), the searcher will look in each of the specified paths, substituting the argument of require() in place of the question mark. In order to specify the path for this third searcher, one must set (or append to) package.cpath and then call require().
So perhaps you have a directory structure as
- ROOT
|-lua
|-bin
where lua contains script.lua and bin contains mylib.so
To load mylib.so, you just need these two lines of code in script.lua:
package.cpath = '/ROOT/bin/?.so;' .. package.cpath
libfuncs = require('mylib')
NOTE: Notice the semicolon. If you append (as opposed to the prepending above), make sure to lead with the semicolon on your added path. It is not there buy default. Otherwise your new path will be merged to the current default cpath, which is just ./?.so.
If you whant just configure your system to use some path to store
libraries there then best way just use LUA_PATH and LUA_CPATH env variables.
e.g.LUA_CPATH=/path/to/?.so. Or for specific Lua version like LUA_CPATH_5_3=/path/to/?.so.
But if you have full path to some library and whant just load this particular library from this directory you can use package.loadlib function.
local function loadlib(path, name)
local sep = string.sub(package.config, 1, 1)
local file = path .. sep .. name .. ((sep == '/') and '.so' or '.dll')
local func = 'luaopen_' .. name
local loader, msg = package.loadlib(file, func)
assert(loader, msg)
return assert(loader())
end
local mylib = loadlib([[/path/to]], 'mylib')

Resources