C++与lua的结合,LuaBridge的使用

2022-05-11 08:39:16 浏览数 (1)

LuaBridge介绍

LuaBridge 是一个简单好用的轻量级且无依赖的库,用于在C 和 LUA(一种强大,快速,轻量级,可嵌入的脚本语言)之间来回映射数据,函数和类。

github地址:

代码语言:javascript复制
https://github.com/vinniefalco/LuaBridge
https://github.com/kunitoki/LuaBridge3

为什么使用Lua

实现业务的热更新,或者再不改动源码和从新编译的情况下用脚本对业务进行模块化测试,提高不少效率。C 和脚本结合使用是非常好的实践,这种用法提供了非常大的灵活度和自由空间。

脚本文件能够作配置文件和编写复杂的函数。更重要的一点是修改脚本文件后无需重新编译,它帮你提高效率。甚至可以设计这样的一个系统,在不修改源码从新打包部署的情况下,通过修改脚本或者远程下发脚本的方式实现业务的热更新。

LuaBridge环境准备

luaBridge的使用简单,只需要把luaBridge的一堆头文件目录拷贝进项目包含进去使用。

但是需要提前准备好lua.lib,项目打包生成可执行exe时需要链接它。

编译lua.lib的方法:

进入luaBridge的项目源码中的LuaBridgeTestsLua文件夹,里面已经包含了lua的源代码,只需要编译为链接库即可。

这里使用cmake和ps脚本编译lua的源码。

 附CMakeLists.txt文件内容:

代码语言:javascript复制
cmake_minimum_required(VERSION 3.12)
 
project(lua VERSION 0.0.1)
 
set(CMAKE_CXX_STANDARD 11)
 
####################  set output directory ####################
set(BUILD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../lua-build)
set(LIB_DIR ${BUILD_DIR}/Release)
set(LIB_FIX)
if (CMAKE_BUILD_TYPE MATCHES "Debug")
    set(LIB_DIR ${BUILD_DIR}/Debug)
    set(LIB_FIX _d)
endif ()
 
get_filename_component(ABSOLUTE_PATH ${LIB_DIR} ABSOLUTE)
set(LIB_DIR ${ABSOLUTE_PATH})
 
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
set(CMAKE_PDB_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
 
set(LIB_DIR_FIX ${LIB_DIR}/bin)
option(USE_VS_BUILD "use visual studio build." OFF)
if (USE_VS_BUILD)
    set(LIB_DIR_FIX ${LIB_DIR}/bin/Debug)
endif ()
 
####################  set include path ####################
set(SRC_PATH
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        )
 
include_directories(
        ${SRC_PATH}
)
 
add_definitions(
     
)
 
####################  scan source files ####################
foreach (path ${SRC_PATH})
    aux_source_directory(${path} SRC_FILES)
endforeach ()
#message(STATUS ${SRC_FILES})
#过滤不相关的源文件
set(FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src)
list(REMOVE_ITEM SRC_FILES ${FILE_PATH}/lua.c)

####################  version config ####################
#生成动态库 dll
add_library(${PROJECT_NAME} SHARED ${SRC_FILES})
#生成静态库 lib
add_library(${PROJECT_NAME}_static STATIC ${SRC_FILES})
#add_executable(${PROJECT_NAME} WIN32 ${SRC_FILES})
#add_executable(${PROJECT_NAME} ${SRC_FILES})
####################  set target properties ####################
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX _d)
set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
####################  set target dependencies ####################
#set(LOGGING_LIB ${LIB_DIR}/lib/Logging${LIB_FIX}.lib)
set(THIRD_LIBS
        #${LOGGING_LIB}
        )
target_link_libraries(${PROJECT_NAME} PRIVATE ${THIRD_LIBS})

接下来配置vs的编译环境,调用cmake指令完成最终的编译和库的生成。

附ps脚本:

代码语言:javascript复制
$VcpkgPath = "F:/vcpkg/scripts/buildsystems/vcpkg.cmake"
#if (($result = Read-Host "Enter the full path of vcpkg.cmake[default: F:/vcpkg/scripts/buildsystems/vcpkg.cmake]") -eq '') {} else {$VcpkgPath=$result}
Write-Host "`n VcpkgPath: $VcpkgPath" -ForegroundColor Yellow

Push-Location 'C:Program Files (x86)Microsoft Visual Studio 14.0Common7Tools'    
cmd /c "vsvars32.bat&set" |
ForEach-Object {
  if ($_ -match "=") {
    $v = $_.split("="); set-item -force -path "ENV:$($v[0])"  -value "$($v[1])"
  }
}
Pop-Location
write-host "`nVisual Studio 2015 Command Prompt variables set." -ForegroundColor Yellow

Write-Host "`n build for this module project." -ForegroundColor Green
cmake . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_TOOLCHAIN_FILE="$VcpkgPath" -Wno-dev -G "NMake Makefiles" 
Set-Location build
nmake 
#nmake install
Set-Location ..

最终生成的想要的lua.lib文件。

 LuaBridge简单示例

新建项目文件夹testlua,把luaBridge的文件夹拷贝进去。

src文件夹中为应用的入口main.cpp

lua文件夹中放上去lua的几个头文件:lualib.h,lua.h,lauxlib.h,luaconfig.h

 测试的main.cpp内容如下:

代码语言:javascript复制
//引用c文件的头文件所以需要加上extern "C"
extern "C"
{
     #include "lua.h"
     #include "lauxlib.h"
     #include "lualib.h"
}
#include "LuaBridgeLuaBridge.h"
#include <iostream>

class test_lua
{
public:
    test_lua()
    {
        m_test_string = "c   test string";
    }
    ~test_lua()
    {
    }
//test方法
    void test(int a,int b)
    {
        printf("c   test function %d %d=%dn", a, b, a b);
    }

//属性set方法
    void SetName(std::string name)
    {
        m_name = name;
    }
//属性get方法,注意需要后面加const
    std::string GetName() const
    {
        return m_name;
    }
//供lua调用方法,返回多个参数方法
    int cFunc(lua_State* L)
    {
//返回参数1
        lua_pushstring(L,"str1");
//返回参数1
        lua_pushstring(L,"str2");
//返回参数个数
        return 2;
    }
    std::string m_test_string;
    std::string m_name;
    static int m_static_data;
};
//test_lua静态变量定义(静态变量在类内只是声明)
int test_lua::m_static_data;
//test_lua子类
class test_lua_child :public test_lua
{
    public:
        test_lua_child(std::string test)
            :m_test_child_string(test)
        {
            printf("call test_lua_child constructorn");
        }
        ~test_lua_child()
        {
        }
        std::string m_test_child_string;
};

int main(){
	
	std::cout << "hello test lua begin" << std::endl;
	//初始化Lua (最后记得调用lua_close(lua_state)释放)
    lua_State* lua_state = luaL_newstate(); 
    //加载Lua基本库
    luaL_openlibs(lua_state);
	
	luabridge::getGlobalNamespace(lua_state)
	.beginNamespace("test")
	.beginClass<test_lua>("test_lua")
	.addConstructor<void (*) (void)> ()//无参构造函数的注册
	.addData("test_str",&test_lua::m_test_string)//注册变量到lua
	.addStaticData("static_data", &test_lua::m_static_data)//注册静态变量到lua
	.addFunction("test", &test_lua::test)//注册test、方法到lua(addStaticFunction静态函数注册也类似)
	.addProperty("name",&test_lua::GetName,&test_lua::SetName)//属性方法的注册(addStaticProperty静态属性方法也类似)
	.addCFunction("cFunc",&test_lua::cFunc)//注册返回多个参数给lua的方法
	.endClass()
	.deriveClass<test_lua_child, test_lua> ("test_lua_child")//子类的注册
	.addConstructor<void (*) (std::string)> ()//有参构造函数的注册
	.addData("test_child_string", &test_lua_child::m_test_child_string)//注册变量到lua
	.endClass()
	.endNamespace();

	//创建test_lua对象
	test_lua test;
    luabridge::setGlobal(lua_state, &test, "test_lua");//注册test_lua对象到lua
	
	//运行lua脚本
    luaL_dofile(lua_state, "test.lua");
	//关闭Lua
    lua_close(lua_state);
	
	std::cout << "hello test lua end" << std::endl;
	
	return 0;
	
}

我们的test.lua文件如下:

代码语言:javascript复制
--lua 打印lua script
print("lua script") 
--调用成员变量m_test_string(test_str为注册的名字)
print(test_lua.test_str)
--调用c  静态变量(需要加上test命名空间)
test.test_lua.static_data=12
print("static_data: "..test.test_lua.static_data)
--调用c  类test_lua属性name
test_lua.name="name_property";
print("name: "..test_lua.name);
--lua调用c  方法test_lua为c  类在lua的注册名,调用test方法
test_lua:test(3,4)

--调用c  调用方法返回多个值
local ret1,ret2 = test_lua:cFunc()
print("ret1="..ret1.." ret2="..ret2)

--创建test_lua_child对象
local test_lua_child = test.test_lua_child("test_string")
--调用其变量
print("child string:"..test_lua_child.test_child_string);
--调用父类的name属性
test_lua_child.name="child_name_property";
print("name:"..test_lua_child.name);

--lua 方法加法
function lua_add_function(a,b)
    print("lua_add_function") 
    return a b;
end

--lua 方法字符串加法(..是相加语法)
function lua_add_str_function(a,b)
    print("lua_add_str_function") 
    return a..b;
end

 最后,编译运行一下:

 同样使用的cmake编译生成可执行exe。

附上CMakeLists.txt

代码语言:javascript复制
cmake_minimum_required(VERSION 3.12)
 
project(main VERSION 0.0.1)
 
set(CMAKE_CXX_STANDARD 11)
 
####################  set output directory ####################
set(BUILD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../main-build)
set(LIB_DIR ${BUILD_DIR}/Release)
set(LIB_FIX)
if (CMAKE_BUILD_TYPE MATCHES "Debug")
    set(LIB_DIR ${BUILD_DIR}/Debug)
    set(LIB_FIX _d)
endif ()
 
get_filename_component(ABSOLUTE_PATH ${LIB_DIR} ABSOLUTE)
set(LIB_DIR ${ABSOLUTE_PATH})
 
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
set(CMAKE_PDB_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIB_DIR}/lib)
 
set(LIB_DIR_FIX ${LIB_DIR}/bin)
option(USE_VS_BUILD "use visual studio build." OFF)
if (USE_VS_BUILD)
    set(LIB_DIR_FIX ${LIB_DIR}/bin/Debug)
endif ()
 
####################  set include path ####################
set(SRC_PATH
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        )
 
include_directories(
		${SRC_PATH}
		${CMAKE_CURRENT_SOURCE_DIR}/
		${CMAKE_CURRENT_SOURCE_DIR}/lua
)
 
add_definitions(
      
)
 
####################  scan source files ####################

foreach (path ${SRC_PATH})
    aux_source_directory(${path} SRC_FILES)
endforeach ()
#message(STATUS ${SRC_FILES})
#过滤不相关的源文件
####################  version config ####################
 
add_executable(${PROJECT_NAME} ${SRC_FILES})
####################  set target properties ####################
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX _d)
 
####################  set target dependencies ####################
set(LUA_LIB ${LIB_DIR}/lib/lua${LIB_FIX}.lib)
set(THIRD_LIBS
        ${LUA_LIB}
        )
target_link_libraries(${PROJECT_NAME} PRIVATE ${THIRD_LIBS})

引用

C 和Lua交互教程(基于LuaBridge)_CSDN云计算的博客-CSDN博客_luabridge

C 反射:全方位解读Lura库的前世今生! - 云 社区 - 腾讯云

https://github.com/zfengzhen/lua_tinker_5.2

tolua 编译 及使用 简单介绍_乌班图ysm的博客-CSDN博客_tolua

https://github.com/zfengzhen/lua_tinker_5.2

0 人点赞