zoukankan      html  css  js  c++  java
  • Lua & C++

    # Lua 与 C++ 交互
    ## 提供系统级别Lua API
    提供系统级别API需要对Lua源码进行修改
    ### Lua源码编译
    [LuaResourceCode]:https://github.com/lua/lua "lua源码下载地址"
    [LuaResourceCode2]: https://github.com/LuaDist/lua "lua源码下载地址CMake版"
    [lua源码下载地址Makefile版][LuaResourceCode]
    [lua源码下载Cmake版][LuaResourceCode2]
    下载好源码,Linux下编译非常简单,如果要使用VS编译,可以使用CMake版,生成了VS的sln之后打开解决方案,其中:
    - liblua: lua动态库项目
    - liblua_static: lua静态库项目
    - lua: lua解释器
    - luac: lua编译器
    修改源码我们对动态库进行修改
    - loslib.c是Lua os API文件, 接下来对这个文件进行修改,添加一个os API
    ### 添加lua os API
    ```c++
    static int os_test(lua_State* L) {
    print("Test the add lua api. ");
    lua_pushboolen(L, 0);
    return 1;
    }
    ```
    上面代码写了一个简单的os_test函数,其中就是打印一行数据,lua_pushboolen(L, 0)的意思是压栈一个参数为0的bool值,这个压栈的参数就是Lua调用os_test Api的返回值,这里会返回false,最后一行return 1的意思是返回值的个数.
    ```c++
    static const luaL_Reg syslib[] = {
    //...
    {"test", os_test},
    {NULL, NULL}
    };
    ```
    在写完os_test之后,lua还并不能直接调用,需要进行注册,在源码中找到syslib这个数组,添加一行{"test", os_test}, 第一个参数表示提供给外部的函数名,第二个参数是一个函数指针, 进行完这一步,编译生成最新的dll,之后再编译lua项目,然后运行lua.exe, 调用我们刚刚写的API
    ```lua
    print(os.test())
    ```
    调用完之后会看到输出"Test the add lua api.", 并且还会打印返回值(false).
    ## 提供dll来扩展Lua核心功能
    ```c++
    extern "C" {
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
    #pragma comment(lib, "lua.lib")
    };
    int Add(int a, int b) {
    return a + b;
    }
    static const char* const ERROR_ARGUMENT_COUNT = "参数数目错误!";
    void ErrorMsg(lua_State* luaEnv, const char* const pszErrorInfo) {
    lua_pushstring(luaEnv, pszErrorInfo);
    lua_error(luaEnv);
    }
    // 检测函数调用参数个数是否正常
    void CheckParamCount(lua_State* luaEnv, int paramCount) {
    // lua_gettop获取栈中元素个数.
    if (lua_gettop(luaEnv) != paramCount) {
    ErrorMsg(luaEnv, ERROR_ARGUMENT_COUNT);
    }
    }
    extern "C" __declspec(dllexport)
    int Test_Add(lua_State* luaEnv) {
    CheckParamCount(luaEnv, 2);
    int a = luaL_optinteger(luaEnv, 1);
    int b = luaL_optineger(luaEnv, 2);
    lua_pushinteger(luaEnv, Add(a, b));
    // 一个返回值
    return 1;
    }
    static luaL_Reg lua_libs[] = {
    {"Add", Test_Add},
    {NULL, NULL}
    };
    extern "C" __declspec(dllexport)
    int luaopen_WinFeature(luaState* luaEnv) {
    const char* const library_name = "test";
    lua_register(luaEnv, library_name, lua_libs);
    return 1;
    }
    ```
    导出函数的格式必须为:
    ```c++
    extern "C" int ExportFuncName(luaState* luaEnv);
    ```
    lua_State里面保存了一个属于自己的堆栈信息,取参数和返回参数都是通过压栈或者出栈来操作,luaL_optxxx(出栈), luaL_pushxxx(入栈)
    ```c++
    extern "C" __declspec(dllexport)
    int luaopen_WinFeature(luaState* luaEnv) {
    const char* const library_name = "test";
    lua_register(luaEnv, library_name, lua_libs);
    return 1;
    }
    ```
    使用dll方式相比添加源码只是多了luaopen_WinFeature这个函数, 这个函数是Lua DLL入口函数,我们通过luaL_register将LIBRARY_NAME对应的库名,以及luaL_Reg数组对应的导出列表来注册到lua_State*对应的Lua环境中。
    ### Lua使用Dll
    lua 搜索目录顺序
    - 当前目录
    - lua安装目录下的clibs目录
    将刚刚编译的DLL放到与lua.exe统级目录下
    ```lua
    require "test"
    print(test.Add(10, 20))
    ```
    ## C++ 加载Lua文件,调用Lua函数
    ```lua
    // test_add.lua
    function add(int a, int b) do
    return a + b
    end
    ```
    ```c++
    lua_State* InitLuaEnv() {
    lua_State* luaEnv = lua_open();
    luaopen_base(luaEnv);
    luaL_openlibs(luaEnv);
    return luaEnv;
    }
    bool LoadLuaFile(lua_State* luaEnv, const std::string& fileName) {
    int result = luaL_loadfile(luaEnv, fileName.c_str());
    return result ? false : true;
    }
    lua_CFunction GetClobalProc(lua_State* luaEnv, const std::string& procName) {
    lua_getglobal(luaEnv, procName.c_str());
    if (!lua_iscfunction(luaEnv, 1))
    return 0;
    return lua_tocfunction(luaEnv, 1);
    }
    int main(void) {
    lua_State* luaEnv = InitLuaEnv();
    if (!luaEnv) {
    return -1;
    }
    if (!LoadLuaFile(luaEnv, "./test_add.lua")) {
    std::cout << "Load lua file failed!" << std::endl;
    return -1;
    }
    int a = 10, b = 20;
    // 将要调用的函数和函数调用参数入栈
    lua_getglobal(luaEnv, "add");
    lua_pushinteger(luaEnv, a);
    lua_pushinteger(luaEnv, b);
    // 2代表有二个参数,1表示返回值有一个,0表示发生错误时的处理函数
    lua_pcall(luaEnv, 2, 1, 0);
    if (lua_isnumber(L, -1))
    }
    ```
  • 相关阅读:
    我的第一颗二叉链树的笔记
    我的kmp笔记
    链表操作笔记
    POJ 2559 Largest Rectangle in a Histogram (单调栈)
    牛客网 wyh的数列(循环节+快速幂)
    数论知识点
    牛客网 n的约数 (唯一分解定理)
    POJ 3783 Balls (DP)
    关于unordered_map和map
    2018年四校联合周赛-第二场 B.异或和问题(二维树状数组)
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/15028171.html
Copyright © 2011-2022 走看看