Using LuaLaTeX and SQLite3
It is possible to modify the package loading mechanism in Lua
. In the case of LuaTeX
, the kpse
library is used to load modules instead of the default mechanism that uses package.path
and package.cpath
. So setting these variables will not have any effect. But nothing prevents us from using both methods using a Lua
module, lualoader.lua
. Save the snippet below as a file in the directory containing your document:
-- lualoader.lua
-- this is copied from luatexbase.loader
local make_loader = function(path, pos, loadfunc)
local default_loader = package.searchers[pos]
local loader = function(name)
local file, _ = package.searchpath(name,path)
if not file then
local msg = "\n\t[lualoader] Search failed"
local ret = default_loader(name)
if type(ret) == "string" then
return msg ..ret
elseif type(ret) == "nil" then
return msg
else
return ret
end
end
local loader,err = loadfunc(file, name)
if not loader then
return "\n\t[lualoader] Loading error:\n\t"..err
end
return loader
end
package.searchers[pos] = loader
end
local binary_loader = function(file, name)
local symbol = name:gsub("%.","_")
return package.loadlib(file, "luaopen_"..symbol)
end
make_loader(package.path,2,loadfile)
make_loader(package.cpath,3, binary_loader)
We use the function make_loader
to insert a function searching package.path
or package.cpath
at a specified index in the package.searchers
table. 2
for lua files, 3
for binary modules. We also need to use different functions to load a module depending on its type. We use loadfile
for Lua
files and slightly more complicated function for binary modules that uses package.loadlib
.
As an example, we can try loading lsqlite3
from LuaTeX
:
\documentclass{article}
\directlua{
require "lualoader"
}
\usepackage{fontspec}
\usepackage[english]{babel}
\begin{document}
\directlua{%
local sqlite3 = require("lsqlite3")
local db = sqlite3.open_memory()
db:exec[[
CREATE TABLE test (id INTEGER PRIMARY KEY, content);
INSERT INTO test VALUES (NULL, 'Hello World');
INSERT INTO test VALUES (NULL, 'Hello Lua');
INSERT INTO test VALUES (NULL, 'Hello Sqlite3')
]]
for row in db:nrows("SELECT * FROM test") do
tex.print(row.id .. " : ".. row.content )
end
}
\end{document}
which yields:
Edit:
As Uwe pointed out, luarocks
as installed by some Linux package managers may not work correctly. I experienced this on Fedora, so I installed luarocks
from source. Another solution may be to set package.path
and package.cpath
to the directories listed by the command
luarocks path
On my own system, this yields:
$ luarocks path
export LUA_PATH='/home/michal/.luarocks/share/lua/5.2/?.lua;/home/michal/.luarocks/share/lua/5.2/?/init.lua;/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/share/lua/5.2/?.lua;/usr/share/lua/5.2/?/init.lua;/usr/lib/lua/5.2/?.lua;/usr/lib/lua/5.2/?/init.lua;./?.lua'
export LUA_CPATH='/home/michal/.luarocks/lib/lua/5.2/?.so;/usr/local/lib/lua/5.2/?.so;/usr/lib/lua/5.2/?.so;/usr/lib/lua/5.2/loadall.so;./?.so'
So a modified preamble would be:
\directlua{
package.cpath = '/home/michal/.luarocks/lib/lua/5.2/?.so;/usr/local/lib/lua/5.2/?.so;/usr/lib/lua/5.2/?.so;/usr/lib/lua/5.2/loadall.so;./?.so'
package.path = '/home/michal/.luarocks/share/lua/5.2/?.lua;/home/michal/.luarocks/share/lua/5.2/?/init.lua;/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/share/lua/5.2/?.lua;/usr/share/lua/5.2/?/init.lua;/usr/lib/lua/5.2/?.lua;/usr/lib/lua/5.2/?/init.lua;./?.lua'
require "lualoader"
}
As of May 2017, there is a package on CTAN called luapackageloader, that allows you to modify the default package searching behavior in LuaTeX.
Once you load luapackageloader
, doing a require
will first try the default kpse based searcher. If the module isn’t found, it will also try to load the package from Lua’s package.path
and package.cpath
values.
Usage example
\documentclass{article}
\usepackage{luacode}
\usepackage{luapackageloader}
\begin{document}
\begin{luacode*}
package.path="/usr/local/lib/luarocks/rocks;/usr/local/lib/luarocks/rocks/lsqlite3;
/usr/local/lib/lua/5.1/lsqlite3.so" .. package.path
require("lsqlite3")
\end{luacode*}
Hello Lua!
\end{document}
Additional note: you can do eval $(luarocks path)
on your shell to set the package path using environment variables which the Lua interpreter will pick up automatically. That way, you do not need to fiddle with the package.path
yourself.