KRTSt内嵌Lua脚本
Lua 简介
Lua是一门强大、高效、轻量、可嵌入的脚本语言。它支持多种编程架构:过程编程、面向对象编程(OOP)、函数式编程、数据驱动编程及数据描述。
Lua结合了简洁的过程语法和强大的数据描述结构(基于关联数组和可扩展语义)。Lua使用动态类型,运行时内部通过寄存器式虚拟机(register-based VM)来执行解释字节码,有自动内存管理和分代GC机制,是配置、编写脚本和原型设计的理想选择。
Lua是作为一个C语言编写的库实现的,其被标准C/C++所兼容。Lua的发行版本中包括一个独立程序(就叫 lua),它就是由Lua库所实现,作为一个完整独立的编译/解释器,也可以用于交互式使用或批量执行。Lua志在成为一门强大轻量可嵌入在任何需要的地方的脚本语言,并且是强力但轻便高效的独立语言。
作为扩展语言,Lua没有 主程序 的概念,它通常是 嵌入 到宿主程序中使用,宿主程序也被称为 被嵌入程序 或简称 宿主 (通常宿主程序指上边说到的独立程序lua)。宿主程序可以调用函数来执行一段Lua代码,可以写入或读取Lua变量,也可以注册C函数供Lua代码调用。通过使用C函数,可以在相同的语法框架下来自定义编程语言,从而使得Lua能够应用于广泛的领域。
Lua官网
Lua中文参考手册
功能简介
KRTS内核中内嵌Lua解释器和编译器执行Lua脚本您需要了解KRTS任务处理的相关知识,我们假设您已经学习了相关知识。本实例主要实现的功能是内核成调用Lua脚本执行和Lua脚本调用内核函数并运行;
工程构建
-
构建KRTS任务程序(请查阅KRTS任务)
-
下载Lua源码解压并加入项目中 (Lua 5.4.7源码)
-
移植Lua程序,将lua源码文件除了lua.c和luac.c之外,加入到内核工程即可,我是用CMake构建的项目,下面是简单的示例
set(LUA_LIST
../3rdparty/lua-5.4.7/lapi.c
../3rdparty/lua-5.4.7/lapi.h
../3rdparty/lua-5.4.7/lauxlib.c
../3rdparty/lua-5.4.7/lauxlib.h
../3rdparty/lua-5.4.7/lbaselib.c
../3rdparty/lua-5.4.7/lcode.c
../3rdparty/lua-5.4.7/lcode.h
../3rdparty/lua-5.4.7/lcorolib.c
../3rdparty/lua-5.4.7/lctype.c
../3rdparty/lua-5.4.7/lctype.h
../3rdparty/lua-5.4.7/ldblib.c
../3rdparty/lua-5.4.7/ldebug.c
../3rdparty/lua-5.4.7/ldebug.h
../3rdparty/lua-5.4.7/ldo.c
../3rdparty/lua-5.4.7/ldo.h
../3rdparty/lua-5.4.7/ldump.c
../3rdparty/lua-5.4.7/lfunc.c
../3rdparty/lua-5.4.7/lfunc.h
../3rdparty/lua-5.4.7/lgc.c
../3rdparty/lua-5.4.7/lgc.h
../3rdparty/lua-5.4.7/linit.c
../3rdparty/lua-5.4.7/liolib.c
../3rdparty/lua-5.4.7/ljumptab.h
../3rdparty/lua-5.4.7/llex.c
../3rdparty/lua-5.4.7/llex.h
../3rdparty/lua-5.4.7/llimits.h
../3rdparty/lua-5.4.7/lmathlib.c
../3rdparty/lua-5.4.7/lmem.c
../3rdparty/lua-5.4.7/lmem.h
../3rdparty/lua-5.4.7/loadlib.c
../3rdparty/lua-5.4.7/lobject.c
../3rdparty/lua-5.4.7/lobject.h
../3rdparty/lua-5.4.7/lopcodes.c
../3rdparty/lua-5.4.7/lopcodes.h
../3rdparty/lua-5.4.7/lopnames.h
../3rdparty/lua-5.4.7/loslib.c
../3rdparty/lua-5.4.7/lparser.c
../3rdparty/lua-5.4.7/lparser.h
../3rdparty/lua-5.4.7/lprefix.h
../3rdparty/lua-5.4.7/lstate.c
../3rdparty/lua-5.4.7/lstate.h
../3rdparty/lua-5.4.7/lstring.c
../3rdparty/lua-5.4.7/lstring.h
../3rdparty/lua-5.4.7/lstrlib.c
../3rdparty/lua-5.4.7/ltable.c
../3rdparty/lua-5.4.7/ltable.h
../3rdparty/lua-5.4.7/ltablib.c
../3rdparty/lua-5.4.7/ltm.c
../3rdparty/lua-5.4.7/ltm.h
#../3rdparty/lua-5.4.7/lua.c
../3rdparty/lua-5.4.7/lua.h
../3rdparty/lua-5.4.7/lua.hpp
#../3rdparty/lua-5.4.7/luac.c
../3rdparty/lua-5.4.7/luaconf.h
../3rdparty/lua-5.4.7/lualib.h
../3rdparty/lua-5.4.7/lundump.c
../3rdparty/lua-5.4.7/lundump.h
../3rdparty/lua-5.4.7/lutf8lib.c
../3rdparty/lua-5.4.7/lvm.c
../3rdparty/lua-5.4.7/lvm.h
../3rdparty/lua-5.4.7/lzio.c
../3rdparty/lua-5.4.7/lzio.h
)
add_library(${PROJECT_NAME} SHARED
kernel.cpp
${LUA_LIST}
)
核心代码
内核代码
- kernel.cpp
/**************************************
*
* 内核层入口
*
*************************************/
#include "Base/SharedData.h"
#include "Business/TaskHandle.h"
SharedData *kernel_data_ptr_ {nullptr}; // 全局数据指针
KSHandle kernel_shared_data_handle_ {NULL}; // 共享数据句柄
// Task处理回调
KSError __stdcall TaskCallback(void * /*pArgs*/, void * /*pContext*/);
// KRTS资源初始化
extern "C" KSError __declspec(dllexport) __stdcall InitFunction(void *pArgs, void * /*pContext*/)
{
KS_printK("InitFunction called!\n");
// 获取全局数据指针
kernel_data_ptr_ = static_cast<SharedData *>(pArgs);
// 设置任务专用的CPU
error = KS_setTargetProcessor(kernel_data_ptr_->task_cpu,KSF_NO_FLAGS);
if (error != KS_OK) { KS_printK("KS_setTargetProcessor failed!\n"); }
error = KS_createCallBack(&kernel_data_ptr_->task_callback_handle, TaskCallback, nullptr, KSF_DIRECT_EXEC | KSF_SAVE_FPU, 0);
if (error != KS_OK) { return error; }
error = KS_setTaskStackSize(0x100000, KSF_NO_FLAGS);
if (error != KS_OK) { return error; }
error = KS_createTask(&kernel_data_ptr_->task_handle, kernel_data_ptr_->task_callback_handle, 172, KSF_CUSTOM_STACK_SIZE);
if (error != KS_OK) { return error; }
return KS_OK;
}
// KRTS资源析构
extern "C" KSError __declspec(dllexport) __stdcall ExitFunction(void * /*pArgs*/, void * /*pContext*/)
{
KS_printK("ExitFunction called!\n");
if (kernel_data_ptr_ == nullptr)
{
return KSERROR_FUNCTION_NOT_AVAILABLE;
}
// 向任务发出终止信号。
kernel_data_ptr_->abort = 1;
if (kernel_data_ptr_->task_handle != NULL)
{
KS_removeTask(kernel_data_ptr_->task_handle);
}
if (kernel_data_ptr_->task_callback_handle != NULL)
{
KS_removeCallBack(kernel_data_ptr_->task_callback_handle);
}
return KS_OK;
}
// 这是实时任务将运行的函数,并对执行 Task 操作。只有实时任务才应调用 Task 函数。
KSError __stdcall TaskCallback(void * /*pArgs*/, void * /*pContext*/)
{
// 处理循环,此循环仅在发出中止信号时停止。
while (true)
{
// 等待停止的通知。
if (kernel_data_ptr_->abort != 0) { break; }
// Todo 处理 lua
if (kernel_data_ptr_->script_run_status)
{
TaskHandle::OnLuaScript();
kernel_data_ptr_->script_run_status = false;
}
KS_sleepTask(REFRESH_TIME*10*1000);
}
return KS_OK;
}
#pragma pack(push, 8)
#include <windows.h>
#pragma pack(pop)
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID pReserved)
{
return TRUE;
}
Lua 交互
- TaskHandle.h
/*****************************************
*
* lua内核处理
*
*****************************************/
#ifndef TASKHANDLE_H
#define TASKHANDLE_H
class TaskHandle
{
public:
TaskHandle();
~TaskHandle();
//lua 脚本执行
static void OnLuaScript();
};
#endif //TASKHANDLE_H
- TaskHandle.cpp
#include "TaskHandle.h"
#include "Base/SharedData.h"
#pragma pack(push, 8)
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include <iostream>
#pragma pack(pop)
// 方法一 :函数注册
static int FunctionTest(lua_State *lua_state)
{
// 获取参数个数
const int count = lua_gettop(lua_state);
int value {};
for (int i = 0; i <= count; i++)
{
// 获取参数类型
const int type = lua_type(lua_state, i);
// 获取参数值
value = lua_tonumber(lua_state, i);
// 输出
printf("index:%d, type:%d, value:%d\n", i, type, value);
}
lua_pushnumber(lua_state, value);
return 1;
}
// 方法二:模块注册
static int FunctionModule(lua_State *lua_state)
{
// 获取参数个数
const int count = lua_gettop(lua_state);
double avg {},sum{};
for (int i = 0; i <= count; i++)
{
// 获取参数类型
const int type = lua_type(lua_state, i);
// 获取参数值
const double value = lua_tonumber(lua_state, i);
printf("index:%d, type:%d, value:%f\n", i, type, value);
sum += value;
}
avg = sum / count;
// 返回参数压入栈中
lua_pushnumber(lua_state, avg);
lua_pushnumber(lua_state, sum);
// 返回的参数个数
return 2;
}
// 列出需要注册的函数数组
static const luaL_Reg KRTS_FunctionModule[] =
{
{"FunctionModule", FunctionModule},
{nullptr, nullptr}
};
// 将所有函数放到表并压入栈中
int CreateLibs(lua_State *lua_state)
{
// 创建一个表
luaL_newlib(lua_state, KRTS_FunctionModule);
return 1;
}
// 注册模块
static const luaL_Reg RegisterModule[] = {
{ "base", luaopen_base }, // 基础库
{ "KRTS", CreateLibs }, //自定义的模块名字:KRTS
{ nullptr, nullptr}
};
TaskHandle::TaskHandle()
{
}
TaskHandle::~TaskHandle() = default;
void TaskHandle::OnLuaScript()
{
try
{
// 初始化
lua_State *lua_state = luaL_newstate();
// 加载lua库
luaL_openlibs(lua_state);
/****************************************************
* 方法一: 以函数的形式注册C++普通函数提供给Lua使用
* C++方法: FunctionTest
* lua脚本:
* val = FunctionTest(10)
* print("The value is ", val)
****************************************************/
/* 注册C++函数 */
lua_register(lua_state, "FunctionTest", FunctionTest);
/*****************************************************
* 方法二: 以模块的方式注册C++普通函数提供给Lua使用
* C++模块: KRTS
* 函数: FunctionModule
* lua脚本:
* avg,sum = KRTS.FunctionModule(1,2)
* print("The sum is ", sum)
* print("The avg is ", avg)
*****************************************************/
for (const luaL_Reg* lua_reg = RegisterModule; lua_reg->func; ++lua_reg)
{
luaL_requiref(lua_state, lua_reg->name, lua_reg->func, 1);
lua_pop(lua_state, 1);
}
//luaL_dostring(lua_state, "print('hello lua')");
// 执行lua文件
luaL_dofile(lua_state, LUA_FILE_NAME);
lua_close(lua_state);
}
catch (...)
{
printf("lua error\n");
}
}
运行结果
index:0, type:4, value:0.000000
index:1, type:3, value:1.000000
index:2, type:3, value:2.000000
The sum is 3.0
The avg is 1.5
--------------------------------
index:0, type:4, value:0
index:1, type:3, value:10
The value is 10.0
--------------------------------