Usando LuaLaTeX e SQLite3

Usando LuaLaTeX e SQLite3

Estou tentando acessar bancos de dados SQLite do LuaLaTeX, mas não consigo carregar um lsqlite3pacote instalado. Aqui está o que tentei até agora:

  1. Foi necessária uma nova instalação do Xubuntu 14.04
  2. Instalou um TeX Live 2014 completo
  3. Instalado Luarocks (que instalou Lua5.1 no caminho)
  4. Usei Luarocks para instalarlsqlite3

    uwe@luabuntu:/media/uwe$ luarocks list

    Rochas instaladas:

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

  5. Anexado package.pathno seguinte arquivo 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}
    

O erro que recebo é o seguinte:

! 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*}

O que deve ser configurado para que o LuaLaTeX encontre o lsqlite3pacote?

EDITAR

Tentei ajustar tudo seguindo os comentários abaixo:

  1. Ajustado/usr/local/texlive/2014/texmf.cnf
  2. Coloque tudo no exemplo
  3. Ainda recebo o erro sobre o lsqlite3módulo ausente com o exemplo a seguir

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

Responder1

É possível modificar o mecanismo de carregamento de pacotes no Lua. No caso de LuaTeX, a kpsebiblioteca é usada para carregar módulos em vez do mecanismo padrão que usa package.pathe package.cpath. Portanto, definir essas variáveis ​​não terá nenhum efeito. Mas nada nos impede de usar os dois métodos usando um Luamódulo, lualoader.lua. Salve o trecho abaixo como um arquivo no diretório que contém seu 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 a função make_loaderpara inserir uma função pesquisando package.pathou package.cpathem um índice especificado na package.searcherstabela. 2para arquivos lua, 3para módulos binários. Também precisamos usar funções diferentes para carregar um módulo dependendo do seu tipo. Usamos loadfilepara Luaarquivos e funções um pouco mais complicadas para módulos binários que usam package.loadlib.

Por exemplo, podemos tentar carregar lsqlite3de 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}

É importante executar LuaLaTeX com a --shell-escapeflag, pois as bibliotecas binárias são bloqueadas por padrão. Com --shell-escapevocê pode executar programas externos e chamar bibliotecas binárias.

O exemplo produz:

insira a descrição da imagem aqui

Editar:

ComoUweapontado, luarocksconforme instalado por alguns gerenciadores de pacotes Linux pode não funcionar corretamente. Eu experimentei isso no Fedora, então instalei luarocksa partir do código-fonte. Outra solução pode ser definir package.pathe package.cpathpara os diretórios listados pelo comando

luarocks path

No meu próprio sistema, isso produz:

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

Portanto, um preâmbulo modificado seria:

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

Responder2

Em maio de 2017, existe um pacote no CTAN chamadoluapackageloader, que permite modificar o comportamento padrão de busca de pacotes no LuaTeX.

Depois de carregar luapackageloader, requireprimeiro tentará o pesquisador padrão baseado em kpse. Se o módulo não for encontrado, ele também tentará carregar o pacote a partir dos valores package.pathand de Lua package.cpath.

Exemplo 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: você pode fazer eval $(luarocks path)em seu shell para definir o caminho do pacote usando variáveis ​​de ambiente que o interpretador Lua irá capturar automaticamente. Dessa forma, você não precisa mexer consigo package.pathmesmo.

Responder3

Com base em comentários sobreessa questão, tenho a seguinte linha em /usr/local/texlive/2014/texmf.cnf:

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

Mas minhas luarocks listofertas:

Installed rocks:

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

então você pode precisar ajustar o segundo caminho de acordo com sua instalação.

Responder4

Resumo

Procurando pelo pacote

  • Na Lua normal, um pacote é pesquisado em package.pathe package.cpath.

  • No LuaTeX, um pacote é pesquisado por padrão com kpse.

  • Existem 2 maneiras de modificar onde o LuaTeX procura por pacotes

  1. modificar o comportamento do kpse

    Modifique texmf.cnfarquivo, variáveis LUAINPUTS​​e CLUAINPUTS.

  2. faça Lua carregar de package.(c)pathe modifique-os

    • Com \usepackage{luapackageloader}, os pacotes são pesquisados ​​em kpse e package.(c)path.

    • O valor de package.(c)pathpode ser definido manualmente pelo usuário dentro do próprio código Lua, masé melhor definir variáveis ​​de ambientepor exemplo LUA_PATH, LUA_CPATH.

      Se você executar eval $(luarocks path)no bash, todos os processos gerados nesse shell bash herdarão as variáveis ​​de ambiente.

Pacote binário

  • Se o pacote exigirarquivos binários, --shell-escapedeve ser aprovado.

Versionamento

  • A versão do pacotedeve ser compatível com a versão Lua. Faça print(_VERSION)dentro de Lua para verificar.

    Para especificar uma versão específica para luarocks, faça, por exemplo luarocks --lua-version 5.3 path, .

informação relacionada