Lua是一种功能强大且快速的编程语言,易于学习和使用,并且可以嵌入到应用程序中。
Lua被设计成一种轻量级的可嵌入脚本语言。它被用于各种各样的应用程序,从游戏到web应用程序和图像处理。
lua配置
下载
Lua的官网
https://www.lua.org/start.html

脚本语言的运行需要解释器,Lua5.1.5的解释器下载地址,我选择了win32版本的。只有不到1Mb
https://sourceforge.net/projects/luabinaries/files/5.1.5/Tools%20Executables/
下载后解压,将他的主目录添加到windows系统的PATH环境变量里。

运行lua命令
之后运行cmd,输入lua5.1就能够启动解释器,以交互式的方式运行lua
lua脚本的执行
新建一个example.lua文件,编辑文本
之后使用lua解释器执行
可以使用luac程序将lua脚本编译成字节码后执行
执行
C++调用lua
环境配置
下载Lua的库
windows32版本5.1.5的静态库下载地址
https://sourceforge.net/projects/luabinaries/files/5.1.5/Windows%20Libraries/Static/
我下载了VC11版本,适用于VS2012编译器。下载后解压
使用VS2012新建一个项目,配置项目附加头文件目录为lua库的头文件目录

配置链接库目录为lua静态库文件的目录

添加链接的lua库文件名

我下载的是静态库,所以配置完了,如果你下载的是动态库,需要把动态库文件dll目录添加到系统的PATH环境变量,所以运行时会调用。
错误和警告
编译时出现警告
LINK : warning LNK4098: 默认库“LIBCMT”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
是项目生成配置与库的不一致导致的,在C++代码生成的配置里,运行库有/MT,/MTd,/Md,/MDd四个选项,我使用的是静态库,非debug版本,所以项目配置改成多线程(/MT),之后编译就不会有警告

使用c语言编译器直接包含lua头文件,使用c++编译器包含Lua头文件要使用extern "C" 修饰
否则会在链接时报错
1>main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_close(struct lua_State *)" (?lua_close@@YAXPAUlua_State@@@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_settop(struct lua_State *,int)" (?lua_settop@@YAXPAUlua_State@@H@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "int __cdecl lua_tointeger(struct lua_State *,int)" (?lua_tointeger@@YAHPAUlua_State@@H@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_pushinteger(struct lua_State *,int)" (?lua_pushinteger@@YAXPAUlua_State@@H@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_getfield(struct lua_State *,int,char const *)" (?lua_getfield@@YAXPAUlua_State@@HPBD@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl lua_call(struct lua_State *,int,int)" (?lua_call@@YAXPAUlua_State@@HH@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "int __cdecl lua_pcall(struct lua_State *,int,int,int)" (?lua_pcall@@YAHPAUlua_State@@HHH@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl luaL_openlibs(struct lua_State *)" (?luaL_openlibs@@YAXPAUlua_State@@@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "int __cdecl luaL_loadfile(struct lua_State *,char const *)" (?luaL_loadfile@@YAHPAUlua_State@@PBD@Z),该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 "struct lua_State * __cdecl luaL_newstate(void)" (?luaL_newstate@@YAPAUlua_State@@XZ),该符号在函数 _main 中被引用
1>c:\users\jack\documents\visual studio 2012\Projects\LuaTest\Debug\LuaTest.exe : fatal error LNK1120: 10 个无法解析的外部命令
这是因为Lua库是使用c语言编写的库,c语言编译器与c++编译器的名称修饰不同导致的错误。
通过使用extern "C"来包含C语言头文件就可以解决问题:
C++编译器会对函数名进行名称修饰(name mangling)以支持函数重载和命名空间等特性。而C语言没有名称修饰的概念。使用extern "C"可以告诉C++编译器,对包含的C语言头文件中的函数名不进行名称修饰,保持它们的原始名称。
实现C和C++的混合编程:C++代码可以通过包含C语言头文件来调用C语言函数。通过extern "C"包装C语言头文件,可以确保C++编译器正确处理C语言函数的声明和调用,避免编译错误。
其中,c_header.h是C语言的头文件,extern "C"告诉C++编译器不对该头文件中的函数名进行名称修饰。这样在C++代码中就可以直接使用C语言头文件中的函数了。
测试c++程序
编辑c++源文件,调用lua脚本中的函数比较两个数字的最大值
#include <iostream>
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
int main(){
lua_State *L = luaL_newstate(); //创建Lua状态
luaL_openlibs(L); //打开Lua库
luaL_dostring(L,"print('hello lua')");//直接执行lua语句
luaL_dofile(L, "script.lua"); //加载和执行Lua脚本
lua_getglobal(L, "maxnumber"); // 获取函数引用
lua_pushinteger(L, 5); // 添加参数
lua_pushinteger(L, 6); // 添加参数
lua_call(L, 2, 1); // 调用函数,2个参数,1个返回值
int result = lua_tointeger(L, -1); // 获取返回值
lua_pop(L, 1); // 弹出返回值
lua_close(L); //清理Lua状态
std::cout<<result; //打印结果
std::cin.get();
return 0;
}
lua脚本
程序加载的lua脚本有调用的函数
script.lua
结果
编译运行程序可以得到输出
hello lua
lua script is executed.
6