Базовый пример того, как интегрировать вашу библиотеку C с Lua
Привет, ребята, у меня были некоторые проблемы с тем, чтобы библиотека C работала с любовью, поэтому я хочу заархивировать, как это сделать: это руководство создано в основном для Linux, но опытные пользователи из Windows поймут, что делать
Перво-наперво, если вы работаете в среде Linux, вам нужно установить Lua (который вы, вероятно, используете только из любви), но это не должна быть какая-либо версия, это должна быть та же версия Lua, которая использовалась с * * Love 11.3 **, то есть ** Lua 5.1 **, поэтому выполните следующую команду в своем терминале
sudo apt-get install lua5.1-dev
Использование этой версии важно, поскольку я читал, я чувствовал, что Lua меняет способ экспорта функций C в каждой версии.
Эта команда будет установлена в ваши заголовки /usr/include/lua5.1 Lua для работы с C.
Теперь для компиляции C вы должны установить команду gcc, это так же просто, как вызов в терминале shsudo apt-get install gcc После этого вам нужно будет создать свой файл C с функцией для экспорта, поэтому назовем его nativefunc.c
После создания файла вам нужно будет импортировать 2 основные библиотеки в код C, lua lib и вспомогательную lua lib:
#include <lua.h> #include <lauxlib.h>
[Необязательное чтение для этого руководства] (Вам понадобится это для написания более сложных функций) После этого вы захотите изучить некоторые спецификации в главах: с 26 по 28 с сайта lua.org: https: //www.lua. org / pil / contents.html
Главы для чтения
- 26 = ›Вызов C из Lua
- 27 = ›Приемы написания C-функций
- 28 = ›Типы, определяемые пользователем в C
После этого чтения у вас будет все, что вам нужно для написания сложных функций C, а затем давайте создадим вашу первую функцию экспорта C: Каждая экспортируемая функция должна соответствовать следующему прототипу: typedef int (*lua_CFunction) (lua_State *L)
Это означает: определите функцию, возвращаемый тип которой ** int **, а полученные параметры - * lua_State L **, поэтому посмотрите, как она определяется:
static int l_mult50(lua_State* L)
Как видите, здесь есть несколько общих правил: во-первых, обычно функции объявляются как статические функции в C, это означает, что ваша функция не будет видна снаружи, l_ обычно используется для демонстрации того, что это функция что находится в библиотеке.
Чтобы получить параметры в вашей функции, вы должны получить ее индекс, каждая функция параметра начинается с 1, например:
double number = lua_tonumber(L, 1);
Эта функция получит номер, переданный, когда вы вызываете ее из своего сценария Lua в первом параметре, но это небезопасный тип, если вы хотите получить известное сообщение об ошибке, если вы передадите неправильное сообщение, вам нужно переключить его на :
double number = luaL_checknumber(L, 1)
Некоторые из этих проверок запомнить так же легко, как
Функции Checktype
- luaL_checkstring,
- luaL_checknumber,
- luaL_checkint,
- luaL_checkany
Теперь вы готовы делать с параметрами все, что хотите, как показано в простом примере. Давайте умножим их на 50.
number*= 50;
(Сокращение от number = number * 50) После этого мы захотим вернуть его в какую-то переменную в Lua, так как мы это сделаем? Вам нужно вызвать lua_push data, чаще всего используются:
Функции push Value
- lua_pushnumber,
- lua_pushboolean,
- lua_pushstring,
- lua_pushcfunction,
- lua_pushnil,
- lua_pushvalue
В нашем случае мы возвращаем число, поэтому:
lua_pushnumber(L, number);
После этого нам нужно вернуться из нашей функции, но есть одна важная вещь: наша функция должна возвращать, сколько значений мы отправили. Итак, в нашем случае мы должны return 1 В случаях, когда вы возвращаете, например, x и y, вы должны вернуть 2, (так как вам нужно будет нажать номер x и нажать номер y)
Итак, наша законченная функция выглядит так:
static int l_mult50(lua_State* L)
{
double number = luaL_checknumber(L, 1);
lua_pushnumber(L, number*50);
return 1;
}
После этого Lua нужно будет назвать функцию и где ее найти, эта часть чрезвычайно важна для ее выполнения в Lua. Вам нужно будет создать другую функцию с префиксом luaopen_. После этого префикса вам нужно указать имя файла, которое будет импортировано в вашу игру, в нашем случае, так как он будет называться libnativefunc.so (dll в случае Windows), последний имя будет luaopen_libnativefunc Я использую lib в качестве префикса файла, потому что рекомендуется начинать имена ваших библиотек с _lib_ Итак, давайте начнем определять функцию
int luaopen_libnativefunc(lua_State* L)
Теперь нам нужно определить, какие функции наша библиотека будет реализовывать в Lua, для этого нам нужно определить массив структур C, он определяется как:
static const struct luaL_Reg nativeFuncLib []
luaL_Reg - это структура, определенная Lua, которая имеет имя и функцию, поэтому важно продолжать использовать этот тип, для его определения мы будем использовать оператор заполнения массива:
static const struct luaL_Reg nativeFuncLib [] =
{
{"mult50", l_mult50}, //Your function name, and the function reference after
{NULL, NULL}
}
Как видите, зарегистрированные функции из нашей библиотеки ВСЕГДА должны заканчиваться на {NULL, NULL}, это означает, что они завершили итерацию по всему массиву, в противном случае будет выдана следующая ошибка Segmentation Fault (ядро выгружено). сообщение об ошибке C по умолчанию, когда ваш итератор выходит за пределы длины массива. После этого в той же функции вам нужно будет зарегистрировать вашу библиотеку в Lua, именно здесь у меня было больше всего ошибок, пытаясь найти правильный для использования:
luaL_register(L, "nativelib", nativeFuncLib)
nativelib - это глобальная переменная, которая будет содержать ваши библиотечные функции, и она определена как одна из разновидностей таблицы обратного вызова Lua: nativelib » mult50 ', вот как она будет работать, для ее завершения просто верните 1, а теперь я поставлю весь код здесь для упрощения следования:
#include <lua.h>
#include <lauxlib.h>
static int l_mult50(lua_State* L)
{
double number = luaL_checknumber(L, 1);
lua_pushnumber(L, number*50);
return 1;
}
int luaopen_libnativefunc(lua_State* L)
{
static const struct luaL_Reg nativeFuncLib [] =
{
{"mult50", l_mult50}, //Your function name, and the function reference after
{NULL, NULL}
};
luaL_register(L, "nativelib", nativeFuncLib);
return 1;
}
Это наш законченный файл nativefunc.c. После этого, чтобы использовать его в нашем коде Lua, нам нужно будет скомпилировать его как общий объект, наиболее известный как библиотека, файлы .so или .dll. Для этого нам нужно будет скомпилировать его. с нашей новой командой gcc
gcc -I/usr/include/lua5.1 nativefunc.c -c -fPIC
Этот код скомпилирует наш код без компоновки, он выведет один файл с именем «nativefunc.o», и теперь мы будем работать с ним:
gcc nativefunc.o -shared -o libnativefunc.so
(Преобразуйте этот .so в .dll в Windows). После этого вы, наконец, сгенерируете файл, который вы импортируете в Lua, для этого есть 2 обычных способа, один из которых проще и менее гибок, а другой - антоним:
Простой способ
require "libnativefunc"
Труднее
lib = package.loadlib("./libnativefunc.so", "luaopen_libnativefunc")
lib();
--Shorter Version - package.loadlib("./libnativefunc.so", "luaopen_libnativefunc")()
Итак, по сути, разница между более сложным и простым способом заключается в том, что более сложный способ заключается в том, что вы определяете, какая функция регистрирует вашу библиотеку. После этого вы сможете вызывать свой собственный.
print(nativelib.mult50(50))
