Luajit загружает общий объект из текущего рабочего каталога вместо пути поиска по умолчанию

Я использую Luajit 2.0.4 на Ubuntu 16.04.

У меня есть простая библиотека C.

int five() {
    return 5;
}

Я компилирую так

gcc -o five.so -shared -fPIC -Wall -Werror five.c

В том же каталоге у меня есть lua-скрипт

local ffi = require("ffi")

ffi.load("./five.so")

ffi.cdef([[
int five();
]])

print(ffi.C.five())

Я также пробовал это с абсолютным путем.

local ffi = require("ffi")

local fh = assert(io.popen("pwd", "r"))
local cwd = assert(fh:read())

print(cwd)

ffi.load(cwd .. "/five.so")

ffi.cdef([[
int five();
]])

print(ffi.C.five())

Когда я бегу

luajit five.lua

я понимаю это

luajit: five.lua:6: luajit: undefined symbol: five
stack traceback:
        [C]: in function '__index'
        five.lua:6: in main chunk
        [C]: at 0x004044a0

Как загрузить общий объект в текущий рабочий каталог в luajit?


person Gregory Nisbet    schedule 03.06.2016    source источник
comment
Используйте local lib = ffi.load( "./five.os" ); print( lib.five() ) или (в POSIX) ffi.load( "./five.so", true ); print( ffi.C.five() ). Ознакомьтесь с документацией ffi.   -  person siffiejoe    schedule 04.06.2016


Ответы (1)


Это правильно. Причина в том, что ffi.C указывает на пространство имен для доступа к стандартной среде выполнения C (плюс некоторые дополнительные библиотеки в зависимости от вашей ОС). Из документов LuaJIT:

Это пространство имен библиотеки C по умолчанию [...] — обратите внимание на заглавную букву «C». Он привязывается к набору символов или библиотек по умолчанию в целевой системе. Это более или менее то же самое, что компилятор C предлагает по умолчанию, без указания дополнительных библиотек ссылок.

Если вы хотите вызвать C-функцию из внешней библиотеки, вам необходимо:

  1. Объявите функцию для использования внутри ffi.cdef, чтобы LuaJIT знал, как вызывать эту функцию.
  2. Импортируйте внешнюю библиотеку и назначьте ее переменной Lua, которая служит пространством имен для внешней функции.
  3. На самом деле вызвать функцию.

Ваш код может быть переработан как:

local ffi = require("ffi")

local lib = ffi.load("five")

ffi.cdef([[
   int five();
]])

print(lib.five())

Кроме того, нет необходимости добавлять суффикс .os. Для разрешения имен библиотек используется переменная package.cpath. Он работает как переменная package.path. Знаки вопроса (?) заменяются именем библиотеки.

$ luajit -e "print(package.cpath)"
./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so

person Diego Pino    schedule 18.06.2016
comment
ffi.load не использует шаблоны пути в package.cpath, а путь поиска общей библиотеки ОС по умолчанию. Вот почему ваш пример кода не работает, и вместо него вам нужно ffi.load("./five.so"). Кроме того, в этом случае вам нужно расширение .so, потому что ffi.load не добавляет расширение, если имя библиотеки уже содержит точку. См. документацию ffi. - person siffiejoe; 19.06.2016
comment
@siffiejoe Верно, ты прав. Я ошибочно предположил, что ffi.load использует package.cpath. Тем не менее, образец кода, который я разместил, работает (по крайней мере, в моей системе). Поскольку имя библиотеки не является путем, добавляется .so, как описано в документации FFI. Запуск программы с помощью strace показывает, что система пытается загрузить библиотеку из текущего каталога open("lib.so", O_RDONLY|O_CLOEXEC) = 3. Хотя я не знаю, в чем причина этого. - person Diego Pino; 19.06.2016
comment
Возможно, у вас установлена ​​переменная окружения LD_LIBRARY_PATH (или путь поиска разделяемой библиотеки по умолчанию уже содержит текущий рабочий каталог). Здесь я получаю luajit: test.lua:5: libfive.so: не удается открыть общий объектный файл: Нет такого файла или каталога, когда я пытаюсь local lib = ffi.load( "five" ) вместо ffi.load( "./five.so" ). - person siffiejoe; 19.06.2016