Lua nasceu para ser embutida: o interpretador é uma biblioteca C
(liblua) com uma API pequena, e é essa API que motores de jogos,
editores e servidores usam para rodar scripts. Ela funciona nos dois
sentidos:
| Arquivo | Sentido | O que demonstra |
|---|---|---|
embutir.c |
C chama Lua | criar um estado, executar código, ler uma global e chamar uma função Lua |
modulo_c.c |
Lua chama C | um módulo carregável via require, com validação de argumentos |
testar_modulo.lua |
— | testa o módulo compilado (com skip gracioso quando não há .so) |
C e Lua não compartilham representação de valores — toda conversa passa por uma pilha que pertence ao estado Lua:
(topo) -1 ← último valor empilhado
-2
2
(base) 1 ← primeiro valor
lua_pushinteger, lua_pushstring, …).lua_tointeger(L, -1) lê o topo).Numa função C exposta para Lua, os argumentos chegam nas posições
1, 2, ... da pilha, e a função devolve quantos resultados
empilhou — é o que somar e inverter fazem em modulo_c.c.
Requisitos: um compilador C e os headers do Lua 5.4
(sudo apt install build-essential liblua5.4-dev).
cd capi
make # compila embutir e modulo_c.so
./embutir # o host C executando Lua
lua5.4 testar_modulo.lua # o Lua carregando o módulo C
make clean # remove os artefatos
No Developer Command Prompt (com o Lua compilado pelo MSVC e
lua54.lib/headers acessíveis):
cl /O2 /I<pasta-dos-headers> embutir.c /link <caminho>\lua54.lib
cl /O2 /I<pasta-dos-headers> /LD modulo_c.c /link <caminho>\lua54.lib /OUT:modulo_c.dll
No Windows o módulo vira modulo_c.dll (e o require o encontra pelo
package.cpath com ?.dll). A CI compila e testa apenas no Linux; as
linhas acima ficam como referência.
embutir) linka com a liblua — ele carrega o
interpretador dentro de si.modulo_c.so) não linka com a liblua — quando o
require o carrega, os símbolos do Lua já existem no processo do
interpretador. Linkar duas cópias da liblua é fonte clássica de bugs.../modulos/empacotamento.md.