Ну… не совсем из love
файла, но около того.
В общем так, для начала сразу скажу что делать так не надо.
Но если очень хочется то можно.
В чём суть, вы например написали программу/игру на Love2D
и вам вдруг ну очень хочется добавить к ней вашу библиотеку типа libcool.so
в которой что-то делается и вы эту библиотеку вызываете из вашего lua
кода, только вот беда. Если вы создали love
файл mycoolgame.love
и положили в него libcool.so
ваш код не сможет загрузить библиотеку libcool.so
ибо mycoolgame.love
это zip
архив. Ну, не получится и всё тут. Но если очень хочется то есть черезжопный метод, мы внутри нашего love
файла создадим архив с нашей библиотекой и возможно дополнительными файлами, при запуске, мы монтируем этот архив и распаковываем в каталог игры и автоматически добавляем пути до распакованных файлов в cpath
и path
.
Например вот наша библиотека которую мы хотим распространять вместе с нашей игрой прямо в love
файле.
#include <stdio.h>
#ifdef LUAJIT
#include <luajit-2.1/lua.h>
#include <luajit-2.1/lualib.h>
#include <luajit-2.1/lauxlib.h>
#else
#include <lua5.1/lua.h>
#include <lua5.1/lualib.h>
#include <lua5.1/lauxlib.h>
#endif
int example_c_function(lua_State* L)
{
int a = lua_tointeger(L,1);
a+=a;
lua_pushnumber(L,a);
lua_pushstring(L,"hello from c");
return 2;
}
int luaopen_lib(lua_State* L)
{
static const struct luaL_Reg nativeFuncLib [] =
{
{"example_c_function", example_c_function},
{NULL, NULL}
};
luaL_register(L, "lib", nativeFuncLib);
return 1;
}
Соберём её
gcc -DLUAJIT=1 main.c `pkg-config --libs --cflags luajit` --shared -o lib.so
Аахивируем её
mkdir libs
cp lib.so libs/lib.so
zip -r9 libs.zip libs
А вот собственно сама суть и сам механизм распаковки и импорта путей.
function autoreq(zip)
if not zip then
print("[autoreq] failed get zip archive for unpack, argument is 'nil'")
return false;
end
local function unpack(dirname,mount_point,base)
local items = love.filesystem.getDirectoryItems(mount_point)
if items then
for _,val in pairs(items) do
local path = dirname..'/'..val;
local path_mount = mount_point..'/'..val;
if love.filesystem.getInfo(path_mount,'directory') then
package.path = package.path ..';'..base..'/'..path..'/?.lua;';
package.cpath = package.cpath ..';'..base..'/'..path..'/?.so;';
love.filesystem.createDirectory(path)
unpack(path,path_mount,base)
elseif love.filesystem.getInfo(path_mount,'file')then
print("[autoreq] unpack -> "..val)
love.filesystem.write(path,love.filesystem.read(path_mount));
else
print("[autoreq] ok -> "..val)
end
end
end
end
local base = love.filesystem.getSaveDirectory();
print("[autoreq] check depends in '"..base.."'")
local dirname = "libs"
local mount_point = "_autoreq_libs_"
local dir = love.filesystem.createDirectory(dirname)
local dir = love.filesystem.createDirectory(mount_point)
data, err = love.filesystem.newFileData(zip)
if not data then
print("[autoreq] failed get zip archive for unpack -> '"..zip.."'")
return false;
end
local success,msg = love.filesystem.mount(data,mount_point)
unpack(dirname,mount_point,base);
love.filesystem.setRequirePath ( package.path );
love.filesystem.setCRequirePath( package.cpath );
local success,msg = love.filesystem.unmount(data);
love.filesystem.remove(mount_point);
print("[autoreq] all done okey")
return true;
end
autoreq("libs.zip"); -- вызываем распаковку архива с библиотекой и импорта путей
require('lib'); -- вызываем нашу библиотеку
function love.load()
print(lib.example_c_function()) -- вызываем функцию из неё
end
Создаём love
файл с нашей программой и её зависимостями
zip -r9 coolgame.love main.lua libs.zip
Запускаем
love coolgame.love
[autoreq] check depends in '/home/dron/.local/share/love/coolgame'
[autoreq] unpack -> lib.so
[autoreq] all done okey
0 hello from c
Всё работает, наша so
шка может распространяться в обычном love
файле.
Будет создана такая структура каталогов. В автоматическом каталоге игры.
dron@gnu:~/.local/share/love$ tree
.
└── coolgame
└── libs
└── libs
└── lib.so
4 directories, 1 file
dron@gnu:~/.local/share/love$
Ну вот собственно и всё. На деле можно в lib.zip
насовать произвольные файлы, с произвольными каталогами, например выполнить сборку openssl/luasec/luasocket
luarocks --tree `pwd`/luasec install openssl
luarocks --tree `pwd`/luasec install luasec
zip -9 -r libs.zip luasec -x 'luasec/lib/luarocks*'
И получившийся libs.zip
просто добавить в свой love
файл тем самым получив всё что нужно
для работы с https
в вашей программе. Я так и сделал в своей проверялке новостей например.
Работать будет всё абсолютно прозрачно, ничего в коде учитывать и менять не надо. В том и прелесть. Ну разве что один раз вызвать autoreq('libs.zip')
и всё.
Да, теряется смысл в переносимости love
файлов ведь теперь там платформоспецифичные библиотеки таскаются. Но это просто вариант таскания с собой so
шки если уж надо, но без всяких appimage
упаковок и прочего, по иному дёрнуть внешнюю библиотеку из своей поставки из архива, просто никак нельзя. Но порой вот надо бывает.
Я голову ломал довольно долго если честно пока не допёрло. Может кому пригодится.
Вроде всё. Досвиданья.