Базовый пример того, как интегрировать вашу библиотеку 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))