尝试在C++中调用Lua

(记录一次尝试在C++中调用Lua的经历,最后效果貌似正确,但不确定方式是否是最佳的)

目标

LuaPython同为脚本语言,在嵌入一个宿主应用(如C++程序)时,Lua的一个优点是更轻量级。我没有Lua的实际开发经验,但我对其感兴趣,想试一试它。

本篇的目标类似《实践在C++中调用Python函数》,希望能在在C++中调用Lua。

方式是什么?

《实践在C++中调用Python函数》里,Python提供了“头文件”和“库文件”,我在C++中调用了头文件中的方法,以此来对Python内容的调用,而这些方法的具体实现在“库文件”中。那么Lua的方式和它一样吗?

《Lua: getting started》里,官方指出:

To embed Lua into your C or C++ program, you’ll need the Lua headers to compile your program and a Lua library to link with it. If you’re getting a ready-made Lua package for your platform, you’ll probably need the development package as well. Otherwise, just download Lua and add its source directory to your project.

为了让Lua嵌入你的C或C++程序,你需要在编译你的程序时将Lua的头文件添加进工程,然后将Lua的库文件链接进工程。如果你得到了你的平台现成的“Lua包”,你可能还需要“开发包”。或者,就下载Lua源码然后添加进项目就可以了。

我不确定我是否精确理解了官方的意思,我的理解:

  1. 似乎可以像Python那样以“添加头文件、链接库文件” 这种方式来嵌入。
  2. 但是这种方式需要一个“开发包”,而这个和“Lua包”是不一样的。我暂时不清楚“开发包”和“Lua包”都特别指什么。。
  3. 从官方的语气上来看,它们更推荐直接在工程中编译源代码。

官网下载源码
在这里插入图片描述
随后发现主要包括两部分:文档(doc)和源码(src)
在这里插入图片描述
而 src 中的头文件/源文件总共只有62个,整个src文件夹不到1MB,看来Lua确实比较“轻量级”。因此我决定使用“直接在工程中编译Lua源代码”的方式。

实践

首先,我将下载的源码src文件夹拷贝过来加入工程
在这里插入图片描述
下面,便是测试调用的Lua脚本文件,以及调用它的C++代码:
(代码上基本参考了《C语言中调用LUA(3)–往Lua脚本中传递变量_Eric_-CSDN博客》


Lua脚本test.lua


--打开文件时的测试打印信息
print("Hello Lua File")

--测试函数
function TestFunction(x,y)
	
	--调用函数时的测试打印信息
    print("Call TestFunction")
	
	--返回的运算结果
    return x*y 
	
end

其中 TestFunction是测试的函数,也是我希望在C++中可以调用的函数。

下面是C++代码:

#include<iostream>

#include "LuaSrc/lua.h"
#include "LuaSrc/lualib.h"
#include "LuaSrc/lauxlib.h"

//全局的 Lua state
lua_State* L;

//将Lua函数封装为一个函数
int TestFunction_LuaWrapper(int x, int y)
{
    //将“TestFunction”压入栈
    lua_getglobal(L, "TestFunction");

    //往栈中压入参数
    lua_pushnumber(L, x);  
    lua_pushnumber(L, y);

    //调用函数,结果会压入栈
    lua_pcall(L
        , 2     //nargs:几个参数
        , 1     //nresults:几个返回值
        , 0);   //msgh:If msgh is 0, then the error object returned on the stack is exactly the original error object. Otherwise, msgh is the stack index of a message handler. 
    
    //获得结果,就是栈内的第一个元素
    int result = (int)lua_tonumber(L, -1); 
    
    //出栈
    lua_pop(L, 1);   
    
    return result;
}

int main(void)
{
    //创建一个 Lua state
    L = luaL_newstate();

    //Opens all standard Lua libraries into the given state.
    //对于一个给定的 Lua state 打开所有的Lua标准库
    luaL_openlibs(L);

    //打开Lua脚本文件
    luaL_dofile(L, "test.lua"); 

    //调用函数并打印结果
    std::cout << "调用TestFunction(3,7)的结果:" << TestFunction_LuaWrapper(3, 7) << std::endl;

    //关闭 Lua state
    lua_close(L);

    return 0;
}

问题1. 多个Main函数

在最开始,无法通过编译:

1>luac.obj : error LNK2005: _main 已经在 lua.obj 中定义
1>Main.obj : error LNK2005: _main 已经在 lua.obj 中定义

经查看,luac.clua.c中都已经定义了main函数。

目前我并不知道如何“最正确”处理,于是我暂时将他们的main函数都去掉了。

问题2. 无法找到函数的实现

看来所有的函数都没有找到实现:

1>Main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_close(struct lua_State *)" (?lua_close@@YAXPAUlua_State@@@Z),函数 _main 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _lua_close
1>Main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_settop(struct lua_State *,int)" (?lua_settop@@YAXPAUlua_State@@H@Z),函数 "int __cdecl TestFunction_LuaWrapper(int,int)" (?TestFunction_LuaWrapper@@YAHHH@Z) 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _lua_settop
1>Main.obj : error LNK2019: 无法解析的外部符号 "double __cdecl lua_tonumberx(struct lua_State *,int,int *)" (?lua_tonumberx@@YANPAUlua_State@@HPAH@Z),函数 "int __cdecl TestFunction_LuaWrapper(int,int)" (?TestFunction_LuaWrapper@@YAHHH@Z) 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _lua_tonumberx
1>Main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_pushnumber(struct lua_State *,double)" (?lua_pushnumber@@YAXPAUlua_State@@N@Z),函数 "int __cdecl TestFunction_LuaWrapper(int,int)" (?TestFunction_LuaWrapper@@YAHHH@Z) 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _lua_pushnumber
1>Main.obj : error LNK2019: 无法解析的外部符号 "int __cdecl lua_getglobal(struct lua_State *,char const *)" (?lua_getglobal@@YAHPAUlua_State@@PBD@Z),函数 "int __cdecl TestFunction_LuaWrapper(int,int)" (?TestFunction_LuaWrapper@@YAHHH@Z) 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _lua_getglobal
1>Main.obj : error LNK2019: 无法解析的外部符号 "int __cdecl lua_pcallk(struct lua_State *,int,int,int,int,int (__cdecl*)(struct lua_State *,int,int))" (?lua_pcallk@@YAHPAUlua_State@@HHHHP6AH0HH@Z@Z),函数 "int __cdecl TestFunction_LuaWrapper(int,int)" (?TestFunction_LuaWrapper@@YAHHH@Z) 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _lua_pcallk
1>Main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl luaL_openlibs(struct lua_State *)" (?luaL_openlibs@@YAXPAUlua_State@@@Z),函数 _main 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _luaL_openlibs
1>Main.obj : error LNK2019: 无法解析的外部符号 "int __cdecl luaL_loadfilex(struct lua_State *,char const *,char const *)" (?luaL_loadfilex@@YAHPAUlua_State@@PBD1@Z),函数 _main 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _luaL_loadfilex
1>Main.obj : error LNK2019: 无法解析的外部符号 "struct lua_State * __cdecl luaL_newstate(void)" (?luaL_newstate@@YAPAUlua_State@@XZ),函数 _main 中引用了该符号
1>  已定义且可能匹配的符号上的提示:
1>    _luaL_newstate
1>D:\0_WorkSpace\Cpp\TestLua\Debug\TestLua.exe : fatal error LNK1120: 9 个无法解析的外部命令

目前我也不太能说出为何没能找到。但是经《C编程语言嵌入Lua的用法_Study杨的博客-CSDN博客》的提示,加入extern "C"后可以解决:
在这里插入图片描述
最后成功调用:
在这里插入图片描述

总结与问题

目前总结出的方式就是:

  1. 拷贝Lua源代码入工程
  2. luac.clua.c中的main函数移除
  3. 在include Lua的头文件时需要使用extern "C"

但目前还有疑问:

  • 删除luac.clua.c中的main函数一定不是最佳的解决方式,更好的解决方式是什么?
  • 为何必须使用extern "C"才可以让那些函数的实现被找到?
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页