一、Lua简介
Lua 是一种强大的、高效的、轻量级的、可嵌入的脚本语言。它支持过程(procedural)编程、面向对象编程、函数式编程以及数据描述。Lua 是动态类型的,运行速度快,支持自动内存管理,因此被广泛用于配置、脚本编写等场景。
二、Lua的优势
Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML、ini等文件格式,并且更容易理解和维护。 Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译、运行。 一个完整的Lua解释器不过200k,在所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。
三、Qt + Lua 环境搭建
Lua是用标准C编写的,所以几乎常见的编程环境它都能编译Lua。下载源码包后,直接编译即可。
1、 下载Lua
下载地址:https://www.lua.org/ftp
2、 使用QtCreator编译lua.a库
打开QtCreator,新建项目 > Library > C++库,在后续弹出的窗口中选择 Statically Linked Library,根据向导完成项目的创建,然后删掉由向导添加的头文件和源文件。将除了lua.c和luac.c以外的文件加入到你的开发环境中进行编译即可。(文末有对应的pro文件,可以参考一下。)
ps:lua.c 和 luac.c 中都有main函数,需要分别编译这两个文件。其中,lua.c编译出来是解析器,luac.c编译出来是编译器。
四、在Qt中调用Lua
1、 新建一个math.lua文件,内容如下:
function fn_add(x,y)
return x + y
end
function fn_subtract(x,y)
return x - y
end
function fn_multiply(x,y)
return x * y
end
function fn_divide(x,y)
return x*1.0 / y
end
2、Qt调用Lua的测试代码
新建Qt控制台程序,在该控制台程序的pro文件,配置一下lua库的头文件以及库文件路径:
CONFIG(debug, debug|release){
DESTDIR = $$PWD/../bin/debug
OBJECTS_DIR += $$PWD/../obj/debug
DIR_NAME = debug
}
CONFIG(release, debug|release){
DESTDIR = $$PWD/../bin/release
OBJECTS_DIR += $$PWD/../obj/release
DIR_NAME = release
}
INCLUDEPATH += $$PWD/./3rdparty/libLua/include
LIBS += -L$$PWD/./3rdparty/libLua/lib/$${DIR_NAME}/ -lliblua
控制台main.cpp的代码如下:
#include <QCoreApplication>
#include <stdio.h>
extern "C"{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
lua_State *L;
double luaMath(std::string fname, int x, int y)
{
/* 要调用一个函数请遵循以下协议:
* 首先,要调用的函数应该被压入栈,接着把需要传递给这个函数的参数按正序压栈,
* 这是指第一个参数首先压栈。最后调用一下 lua_call,当函数调用完毕后,
* 所有的参数以及函数本身都会出栈,而函数的返回值这时则被压栈。*/
double result;
/*获取函数名*/
lua_getglobal(L, fname.c_str());
/*压入第一个参数*/
lua_pushnumber(L, x);
/*压入第二个参数*/
lua_pushnumber(L, y);
/*使用2个参数调用函数,返回1个结果。*/
lua_call(L, 2, 1);
/*获取结果*/
result = (double)lua_tonumber(L,-1);
/*清理返回结果*/
lua_pop(L, 1);
return result;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
L = luaL_newstate();//新建lua解释器
luaL_openlibs(L);//载入lua基础库
#if 1
//执行lua脚本:
luaL_dofile(L, "lua/math.lua");//填写实际的math.lua文件的相对路径
/*call the add function*/
int sum = luaMath("fn_add", 10, 15);
printf("sum = %d\r\n", sum);
int subtract = luaMath("fn_subtract", 10, 15);
printf("subtract = %d\r\n", subtract);
int multiply = luaMath("fn_multiply", 10, 15);
printf("multiply = %d\r\n", multiply);
auto divide = luaMath("fn_divide", 10, 15);
printf("divide = %.3f\r\n", divide);
#endif
/*cleanup Lua*/
lua_close(L);
system("pause");
return a.exec();
}
3、输出结果
sum = 25
subtract = -5
multiply = 150
divide = 0.667
五、附上lua库的pro文件内容:
QT -= gui
TEMPLATE = lib
CONFIG += staticlib
CONFIG += c++11
#去掉生成空的debug和release目录
CONFIG -= debug_and_release
# 编译时临时文件路径
RCC_DIR += $$PWD/../temp/rcc_tmp
MOC_DIR += $$PWD/../temp/moc_tmp
UI_DIR += $$PWD/../temp/ui_tmp
CONFIG(debug, debug|release){
DESTDIR = $$PWD/../lib/debug
OBJECTS_DIR += $$PWD/../obj/debug
DIR_NAME = debug
}
CONFIG(release, debug|release){
DESTDIR = $$PWD/../lib/release
OBJECTS_DIR += $$PWD/../obj/release
DIR_NAME = release
}
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
lapi.c \
lauxlib.c \
lbaselib.c \
lcode.c \
lcorolib.c \
lctype.c \
ldblib.c \
ldebug.c \
ldo.c \
ldump.c \
lfunc.c \
lgc.c \
linit.c \
liolib.c \
llex.c \
lmathlib.c \
lmem.c \
loadlib.c \
lobject.c \
lopcodes.c \
loslib.c \
lparser.c \
lstate.c \
lstring.c \
lstrlib.c \
ltable.c \
ltablib.c \
ltm.c \
lundump.c \
lutf8lib.c \
lvm.c \
lzio.c
HEADERS += \
lapi.h \
lauxlib.h \
lcode.h \
lctype.h \
ldebug.h \
ldo.h \
lfunc.h \
lgc.h \
ljumptab.h \
llex.h \
llimits.h \
lmem.h \
lobject.h \
lopcodes.h \
lopnames.h \
lparser.h \
lprefix.h \
lstate.h \
lstring.h \
ltable.h \
ltm.h \
lua.h \
lua.hpp \
luaconf.h \
lualib.h \
lundump.h \
lvm.h \
lzio.h
# Default rules for deployment.
unix {
target.path = $$[QT_INSTALL_PLUGINS]/generic
}
!isEmpty(target.path): INSTALLS += target
#拷贝头文件到include目录下
win32 {
SrcIncludeDir = $${PWD} #定义的宏变量,在非首位置使用时需要带{}
SrcIncludeDir = $$replace(SrcIncludeDir, /, \\)
DstIncludeDir = $$PWD/../include/
DstIncludeDir = $$replace(DstIncludeDir, /, \\)
#多条命令语句之间可以用&&隔开,自动连续执行
QMAKE_POST_LINK += echo "---------prepare to copy *.h---------" && echo.
QMAKE_POST_LINK += cd $$SrcIncludeDir && xcopy /s/y/i $$SrcIncludeDir\lauxlib.h $$DstIncludeDir
QMAKE_POST_LINK += && xcopy /s/y/i $$SrcIncludeDir\lua.h $$DstIncludeDir
QMAKE_POST_LINK += && xcopy /s/y/i $$SrcIncludeDir\luaconf.h $$DstIncludeDir
QMAKE_POST_LINK += && xcopy /s/y/i $$SrcIncludeDir\lualib.h $$DstIncludeDir
#打印测试
#message("--SrcIncludeDir= $$SrcIncludeDir")
#message("--DstIncludeDir= $$DstIncludeDir")
}