Este es un problema que me atormentó durante bastante tiempo.

Después de escribir y compilar mis funciones personalizadas en una biblioteca compartida, require('mylib') solo funcionaría cuando la biblioteca compartida estuviera directamente en el mismo directorio que el script desde el que lo llamé.

Cualquier intento de probar require('/path/to/mylib') o rutas absolutas similares fracasó. Además, el "retroceso" a través de una ruta relativa (es decir, el uso de .. también falló.

Entonces, ¿cómo se puede especificar el directorio bin o hacia dónde se envía la biblioteca compartida?

1
marcman 31 ago. 2016 a las 00:44

2 respuestas

La mejor respuesta

Bueno, de acuerdo con la documentación de Lua sobre la llamada obligatoria ( usando Lua 5.2 aquí), hay algunos lugares donde el cargador busca estos módulos cargables.

Parece que require() usa lo que se llama "buscadores" (documentos vinculados arriba) para determinar dónde encontrar estos módulos. Hay cuatro buscadores en total. De los documentos:

El primer buscador simplemente busca un cargador en la tabla package.preload.

El segundo buscador busca un cargador como una biblioteca Lua, usando la ruta almacenada en package.path. La búsqueda se realiza como se describe en la función package.searchpath.

El tercer buscador busca un cargador como una biblioteca C, usando la ruta dada por la variable package.cpath. Nuevamente, la búsqueda se realiza como descrito en la función package.searchpath. Por ejemplo, si la ruta C es la cadena "./?.so;./?.dll;/usr/local/?/init.so" el buscador del módulo foo intentará abrir los archivos ./foo.so, ./foo.dll, y /usr/local/foo/init.so, en ese orden. Una vez que encuentra una biblioteca C, esto El buscador primero utiliza una función de enlace dinámico para vincular la aplicación. con la biblioteca. Luego intenta encontrar una función C dentro del biblioteca que se utilizará como cargador. El nombre de esta función C es el cadena "luaopen_" concatenada con una copia del nombre del módulo donde cada punto se reemplaza por un guión bajo. Además, si el nombre del módulo tiene un guión, su prefijo hasta (incluido) el primer guión es remoto. Por ejemplo, si el nombre del módulo es a.v1-b.c, la función el nombre será luaopen_b_c.

El cuarto buscador prueba un cargador todo en uno. Busca en la ruta C una biblioteca para el nombre raíz del módulo dado. Por ejemplo, cuando requiera a.b.c, buscará una biblioteca C para un. Si lo encuentra, busca una función abierta para el submódulo; en nuestro ejemplo, sería luaopen_a_b_c. Con esta función, un paquete puede empaquetar varios submódulos C en una sola biblioteca, y cada submódulo mantiene su función abierta original.

El buscador más útil para nosotros es el tercero: se usa para cualquier biblioteca compartida (.dll o .so) que es generalmente la forma en que se construyen nuestros módulos C personalizados.

Usando la cadena de plantilla (la que tiene los signos de interrogación), el buscador buscará en cada una de las rutas especificadas, sustituyendo el argumento de require() en lugar del signo de interrogación. Para especificar la ruta para este tercer buscador, uno debe establecer (o agregar a) package.cpath y luego llama a require().

Entonces, tal vez tenga una estructura de directorio como

- ROOT
    |-lua
    |-bin

Donde lua contiene script.lua y bin contiene mylib.so

Para cargar mylib.so, solo necesita estas dos líneas de código en script.lua:

package.cpath = '/ROOT/bin/?.so;' .. package.cpath
libfuncs = require('mylib')

NOTA: Observe el punto y coma. Si agrega (a diferencia de lo anterior), asegúrese de comenzar con el punto y coma en la ruta agregada. No hay compra por defecto. De lo contrario, su nueva ruta se fusionará con la cpath predeterminada actual, que es solo ./?.so.

2
marcman 30 ago. 2016 a las 21:44

Si solo desea configurar su sistema para usar alguna ruta para almacenar bibliotecas allí, entonces, la mejor manera es usar las variables env LUA_PATH y LUA_CPATH. por ejemplo, LUA_CPATH=/path/to/?.so. O para una versión específica de Lua como LUA_CPATH_5_3=/path/to/?.so.

Pero si tiene la ruta completa a alguna biblioteca y simplemente carga esta biblioteca en particular desde este directorio, puede usar la función package.loadlib.

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')
0
moteus 31 ago. 2016 a las 13:04