Como faço para chamar funções C ++ a partir de um script Lua?
-
06-07-2019 - |
Pergunta
Estou usando o Visual Studio 2005.
------------------------ [luapassing.cpp] ------------------ -
#include "lua.h"
static int myCfunc (Lua_State *L){
double trouble = lua_tonumber(L,1);
lua_pushnumber(L,16.0 -trouble);
return 1;
}
int luaopen_luapassing (Lua_State *L){
static const lua_reg Map [] = {{"dothis",myCfunc},{NULL,NULL}};
luaL_register(L,"cstuff",Map);
return;
}
------------------------- [csample.lua] ----------------- --------
package.cpath = "./CLua2.dll"
require "luapassing"
print("hola")
print(seth.doThis(120))
Solução
Eu vejo vários problemas. Vou descrevê-los, e fornecer um fragmento de código que deve funcionar como eu acredito que você destina esse exemplo para trabalho.
O primeiro problema é que o compilador C ++ mutilado o nome da única função exportada de seu DLL cujas matérias nome à Lua: luaopen_luapassing()
. A distribuição de ações binário para Windows foi compilado como um programa C, e assume um nome de estilo C para o ponto de entrada do módulo DLL.
Além disso, você tem o protocolo para a função luaopen_x
ligeiramente errado. A função retorna um inteiro que conta Lua como muitos itens no topo da pilha de Lua são valores de retorno para uso por Lua. O protocolo assumido por require
preferiria que você deixe tabela de objeto do novo módulo no topo da pilha e devolvê-lo à Lua. Para fazer isso, a função luaopen_x
normalmente seria usar luaL_register()
como você fez, em seguida, retornar 1.
Há também a questão da nomeação. Módulos escritos em puro Lua têm a oportunidade de estar menos conscientes de seus nomes. Mas módulos escritos em C tem que exportar uma função a partir da DLL que inclui o nome do módulo em seu nome. Eles também têm que fornecer esse nome módulo para luaL_register()
para que a tabela direita é criado e atualizado no ambiente global. Finalmente, o script Lua cliente verá o módulo carregado em uma tabela global chamada como o nome passado para require
, que também é retornado de require
para que ele possa ser armazenado em cache em um local em que script.
Um par de outras lêndeas com o código C são de que o tipo numérico realmente deve ser escrito lua_Number
para a portabilidade, e que seria convencional para usar luaL_checknumber()
em vez de lua_tonumber()
para reforçar o argumento necessário para a função. Pessoalmente, gostaria de citar a implementação C de uma função pública com um nome relacionado ao seu nome que será conhecido publicamente pela Lua, mas que é apenas uma questão de gosto.
Esta versão do lado do C deve corrigir esses problemas:
#include "lua.h"
static int my_dothis (Lua_State *L){
lua_Number trouble = luaL_checknumber(L,1);
lua_pushnumber(L,16.0 -trouble);
return 1;
}
extern "C" int luaopen_luapassing (Lua_State *L){
static const lua_reg Map [] = {
{"dothis", my_dothis},
{NULL,NULL}
};
luaL_register(L,"luapassing",Map);
return 1;
}
O script de amostra, então, precisa para se referir ao módulo carregado pelo seu nome próprio, e para as funções definidas por esse módulo por seus nomes próprios. Lua é case sensitive, por isso, se o módulo cria uma função chamada dothis()
, em seguida, o script deve usar o mesmo nome, e não pode encontrá-lo chamado doThis()
, por exemplo.
require "luapassing" print("hola") print(luapassing.dothis(120))
Devo acrescentar que eu realmente não tenho compilado e executar o acima, então pode haver um erro de digitação ou dois deixada como um exercício; -)
Outras dicas
Se você vai estar fazendo um monte de C ++ para ligação lua, você pode querer dar uma olhada em luabind .
Se você está compilando como C ++ e quer combinar uma interface 'C', você deve declarar as funções visíveis externamente como extern "C"
para citar evitar deturpação.