Usando LuaLaTeX y SQLite3

Usando LuaLaTeX y SQLite3

Estoy intentando acceder a bases de datos SQLite desde LuaLaTeX pero no puedo cargar un lsqlite3paquete instalado. Esto es lo que probé hasta ahora:

  1. Tomó una nueva instalación de Xubuntu 14.04
  2. Instalé un TeX Live 2014 completo
  3. Luarocks instalado (que instaló Lua5.1 en el camino)
  4. Luarocks usados ​​para instalarlsqlite3

    uwe@luabuntu:/media/uwe$ lista de luarocks

    Rocas instaladas:

    lsqlite3 0.9.1-2 (instalado) - /usr/local/lib/luarocks/rocks

  5. Adjunto el package.pathen el siguiente archivo TeX:

    \documentclass{article}    
    \usepackage{luacode}
    
    \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}
    

El error que recibo es el siguiente:

! LuaTeX error [\directlua]:3: module 'lsqlite3' not found:
  no field package.preload['lsqlite3']
  [luatexbase.loader] Search failed
  [kpse lua searcher] file not found: 'lsqlite3'
  [kpse C searcher] file not found: 'lsqlite3'
  [oberdiek.luatex.kpse_module_loader]-eroux Search failed
stack traceback:
  [C]: in function 'require'
  [\directlua]:3: in main chunk.
\luacode@dbg@exec ...code@maybe@printdbg {#1} #1 }

l.9 \end{luacode*}

¿Qué se debe configurar para que LuaLaTeX encuentre el lsqlite3paquete?

EDITAR

Intenté ajustar todo siguiendo los comentarios a continuación:

  1. Equilibrado/usr/local/texlive/2014/texmf.cnf
  2. Pon todo en el ejemplo.
  3. Aún aparece el error sobre el lsqlite3módulo que falta con el siguiente ejemplo

    \documentclass{article}
    \directlua{
    require "lualoader"
    }
    
    \usepackage{fontspec}
    \usepackage[english]{babel}
    \begin{document}
    
    \directlua{package.path='/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/home/uwe/.luarocks/share/lua/5.1/?.lua;/home/uwe/.luarocks/share/lua/5.1/?/init.lua;/usr/share/lua/5.1//?.lua;/usr/share/lua/5.1//?/init.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua'
    package.cpath='/usr/local/lib/lua/5.1/?.so;/home/uwe/.luarocks/lib/lua/5.1/?.so;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;/usr/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so'
    require "lualoader"
    }
    
    \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}
    

Respuesta1

Es posible modificar el mecanismo de carga de paquetes en Lua. En el caso de LuaTeX, la kpsebiblioteca se usa para cargar módulos en lugar del mecanismo predeterminado que usa package.pathy package.cpath. Por lo tanto, configurar estas variables no tendrá ningún efecto. Pero nada nos impide utilizar ambos métodos utilizando un Luamódulo, lualoader.lua. Guarde el fragmento a continuación como un archivo en el directorio que contiene su documento:

-- 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)

Usamos la función make_loaderpara insertar una función de búsqueda package.patho package.cpathen un índice específico en la package.searcherstabla. 2para archivos lua, 3para módulos binarios. También necesitamos usar diferentes funciones para cargar un módulo según su tipo. Usamos loadfilepara Luaarchivos y una función un poco más complicada para módulos binarios que usa package.loadlib.

Como ejemplo, podemos intentar cargar lsqlite3desde 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}

Es importante ejecutar LuaLaTeX con la --shell-escapebandera, porque las bibliotecas binarias están bloqueadas de forma predeterminada. Con --shell-escapeél puedes ejecutar programas externos y llamar a bibliotecas binarias.

El ejemplo produce:

ingrese la descripción de la imagen aquí

Editar:

ComouweComo se señaló, luarockstal como lo instalan algunos administradores de paquetes de Linux, es posible que no funcione correctamente. Experimenté esto en Fedora, así que lo instalé luarocksdesde la fuente. Otra solución puede ser configurar package.pathy package.cpathacceder a los directorios enumerados por el comando

luarocks path

En mi propio sistema, esto produce:

$ 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'

Entonces un preámbulo modificado sería:

\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"
}

Respuesta2

A partir de mayo de 2017, existe un paquete en CTAN llamadocargador de paquetes lua, que le permite modificar el comportamiento de búsqueda de paquetes predeterminado en LuaTeX.

Una vez que cargue luapackageloader, requireprimero probará el buscador predeterminado basado en kpse. Si no se encuentra el módulo, también intentará cargar el paquete desde los valores package.pathy de Lua package.cpath.

Ejemplo de uso

\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}

Nota adicional: puede hacerlo eval $(luarocks path)en su shell para establecer la ruta del paquete utilizando variables de entorno que el intérprete de Lua recogerá automáticamente. De esa manera, no es necesario que juegues contigo package.pathmismo.

Respuesta3

Basado en comentarios sobreesta pregunta, tengo la siguiente línea en /usr/local/texlive/2014/texmf.cnf:

CLUAINPUTS  = .;$SELFAUTOLOC/lib/{$progname,$engine,}/lua//;/usr/lib/{$progname,$engine,}/lua//

Pero mi luarocks listda:

Installed rocks:

lsqlite3
   0.9.1-2 (installed) - /usr/lib/luarocks/rocks-5.2

por lo que es posible que deba ajustar la segunda ruta según su instalación.

Respuesta4

Resumen

Buscando el paquete

  • En Lua normal, se busca un paquete en package.pathy package.cpath.

  • En LuaTeX, un paquete se busca de forma predeterminada con kpse.

  • Hay 2 formas de modificar dónde busca paquetes LuaTeX

  1. modificar el comportamiento de kpse

    Modificar texmf.cnfarchivo, variables LUAINPUTSy CLUAINPUTS.

  2. hacer que Lua se cargue desde package.(c)path, luego modificarlos

    • Con \usepackage{luapackageloader}, los paquetes se buscan tanto en kpse como en package.(c)path.

    • El valor de package.(c)pathpuede ser establecido manualmente por el usuario dentro del propio código Lua, peroes mejor establecer variables de entornop.ej LUA_PATH, LUA_CPATH.

      Si ejecuta eval $(luarocks path)bash, todos los procesos generados desde ese shell bash heredarán las variables de entorno.

paquete binario

  • Si el paquete lo requierearchivos binarios, --shell-escapedebe aprobarse.

Versionado

  • La versión del paquetedebe ser compatible con la versión Lua. Hazlo print(_VERSION)dentro de Lua para comprobarlo.

    Para especificar una versión particular de luarocks, haga, por ejemplo luarocks --lua-version 5.3 path, .

información relacionada