#Lua:Lua呼叫C++生成的DLL庫

2022-09-24 21:00:28

Lua呼叫C++生成的DLL庫

本文參考了某大佬的部落格,寫得十分詳細,推薦!!!

需求:

在之前的求解器中新增了Lua庫,使得程式可以在Lua指令碼中實現自定義函數功能,考慮到未來可能需要與第三方程式庫進行耦合計算,現在想到可以藉助Lua指令碼,在指令碼中呼叫第三方動態庫,以實現其功能的擴充套件。接下來將要簡要記錄下Lua中呼叫第三方庫的實現過程。

編譯Lua庫

在windows平臺下,藉助mingw編譯器進行編譯。

首先需要去下載Lua原始碼,這裡下載的是最新的Lua5.4

在安裝路徑下進行編譯,原始碼中已經寫好了Makefile,可以直接進行編譯

mingw32-make mingw
mingw32-make install local

在install目錄下得到lua.exe,lua54.dll,liblua.a 等可執行檔案,動態庫與靜態庫

C++編寫DLL介面

以下給出了一個範例,註釋比較詳細

cpp2dll.cpp

#include <Windows.h>
#include "lua.hpp"
#include <iostream>
#include <time.h>
#include <cmath>

// 函數範例:引數輸入順序
int Lua_printf(lua_State *L)
{
    int n = lua_gettop(L); // 判斷輸入引數個數
    switch (n)
    {
    case 0:
        std::cout << "intput Para Number is 0" << std::endl;
        break;
    default:
        std::cout << "intput Para is " << n << std::endl;
        int a = 0;
        for (int i = 1; i <= n; ++i)
        {
            a = lua_tonumber(L, i); // 從棧底,向上依次讀取資料
            std::cout << a << " ";
        }
        std::cout << std::endl;
        break;
    };
    return n; // 返回n個引數
}

int Lua_pow(lua_State *L)
{
    int n = lua_gettop(L); // 判斷輸入引數個數
    if (n != 2)
    {
        std::cout << "intput Para Number is not 2" << std::endl;
        return -1;
    }
    double a, b, temp;

    a = lua_tonumber(L, 1);
    b = lua_tonumber(L, 2);

    int re = std::pow(a, b);
    std::cout << "a=" << a << "|b=" << b << "|re=" << re << std::endl;
    // lua_pushstring(L, "re="); // 將返回結果壓入棧中
    lua_pushnumber(L, re); // 將返回結果壓入棧中
    // return 2;
    return 1;
}

// 註冊名稱與函數的對應關係
static const luaL_Reg name_and_func[]{
    {"printf", Lua_printf},
    {"pow", Lua_pow},
    {NULL, NULL}};

// 註冊函數:函數名稱"luaopen_xxx",其中,xxx必須是dll的名稱,即"xxx.dll"
extern "C"
{
    int __declspec(dllexport) luaopen_cpp2dll(lua_State *L)
    {
        printf("start luaopen_lib\n");
        luaL_newlib(L, name_and_func); // 建立一個新表,並將函數入棧
        printf("end luaopen_lib\n");
        return 1;
    }
}

編譯DLL

編譯時需要連結到Lua生成的靜態庫,所以g++編譯時需要指定lua標頭檔案路徑,以及靜態庫路徑,編譯命令如下

g++ cpp2dll.cpp -O3 -o cpp2dll.dll -shared -fPIC -I ./lua54/include -L absolute/path/to/lua54/lib -llua54

至此生成得Lua可以識別的動態連結庫cpp2dll.dll

Lua中呼叫DLL

編寫如下的Lua指令碼

test.lua

local cpp2dll = require("cpp2dll")

cpp2dll.printf()
cpp2dll.printf(0,1,2,3)

a=2
b=10
print(a,"^",b,"=",cpp2dll.pow(a,b))
print(b,"^",a,"=",cpp2dll.pow(b,a))

lua.exe 執行test.lua指令碼

得到如下輸出

cmd$ lua.exe test.lua
start luaopen_lib
end luaopen_lib
intput Para Number is 0
intput Para is 4
0 1 2 3
a=2|b=10|re=1024
2       ^       10      =       1024.0
a=10|b=2|re=100
10      ^       2       =       100.0

最後,在Lua指令碼中成功呼叫C++編寫的動態連結庫