Lua編譯擴展(DLL)

Lua擴展模塊編譯

真的是把我逼瘋的節奏

在這期間有很多疑惑,如下:

  • Lua是如何自動去“加載”(或者說搜索)c庫中的函數
  • Lua的擴展庫的編譯環境
  • Lua在C中是怎么被調用的

帶著這些問題,的確困擾了我很久,直到我看完了手冊


關于gcc的一些參數

-I 從某個目錄搜索頭文件

-L 從某個目錄鏈接動態庫,好比如 -L.代表在本目錄

-l 要鏈接的動態庫,比如說libab.dll 則是-lab,這個mingw的確給我來了個措手不稽(說好的ab.dll用-lab呢,吐槽還是太年輕)

-c 編譯,但是不鏈接,聲稱.o文件


Lua提供的庫

這些文件都可以在lua的安裝環境中找到

注意%LUA_DEV%指的是lua的安裝目錄,如果是自己編譯源碼的,不包括擴展庫,只有基本庫,

%LUA_DEV%\include lua函數聲明的頭文件,其中包括了

  • lua.h c調用lua的函數聲明基本都在這,還有結構體
  • lualib.h 動態庫編譯(DLL,SO)相關的函數定義都在這,還有結構體
  • luaxlib.h 這個還真不知道,好像是擴展庫的
  • lua.hpp 這個是c++的,實際上和lua.h差不多的
  • luaconf.h 這個是配置的,好比如說配置參數檢查,就在包含這個頭文件前設定一個宏

%LUA_DEV%\lib 這里是lua庫的放的地方,有兩種庫,一種是靜態庫(xx.lib相當于Linux下的xxx.a,通過ar生成)另一種是動態庫dll

  • lua51.dll

  • lua51.lib

  • lua5.1.dll

  • lua5.1.lib

    其實只是名字不太一樣,兩個動態庫和靜態庫一樣的


好的,開始修仙,只討論怎么編譯一個最簡單的,能夠被調用的,不討論C編寫的細節

這段例子網上抄的

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

#include <windows.h>

/*
 文件名:mylib.c
 編譯的庫名:mylib.dll
 這個名字很重要,對不上就沒辦法調用了
 */

//這里定義了一個lua可以調用的函數,lua_State是一個狀態機
static int mylib_pp(lua_State *L){
    MessageBox(NULL,"Hello","Hei",MB_OK);
    //返回值指的是返回值個數的數量
    return 0;
}

//---注冊函數
//本身luaL_reg結構體就是一個名稱和函數名對應的,這里是一個結構體數組,最后我們用{NULL,NULL}結束
static const luaL_reg Mylib[]={
    {"pp",mylib_pp},
    {NULL,NULL},
};
//暴露的函數,都要寫上extern,還有一個很重要的地方就是:
//luaopen_庫名 好比如庫叫mylib,文件名就得叫mylib.dll,而且登記的庫名也得交mylib,保持一致才能調用
extern int luaopen_mylib(lua_State *L)
{
    luaL_register(L,"mylib",Mylib);
    return 1;
}

好的以上就是代碼的相關內容,然后我們來到編譯,需要以下東西

  • mingw
  • lua的靜態庫lib
  • lua的頭文件include

首先先把lua的擴展編譯成.o文件,請注意,有個特殊的環境變量,%LUA_DEV%指的是lua的安裝目錄

gcc -I %LUA_DEV%\include -c mylib.c

然后鏈接

gcc -shared -fPIE -o mylib.dll mylib.o %LUA_DEV%\lib\lua51.lib

最后生成的mylib.dll

打開lua

package.path = package.path .. ".\?.dll"
-- 把當前目錄添加到搜索目錄
require('mylib')
-- 這個對應的是luaL_reg中注冊的名稱
mylib.pp()

偽總結

編譯的時候注意事項:

1.頭文件只是提供了結構體定義和函數聲明,但是具體的實現還是在靜態庫的,編譯期間要包含頭文件

2.編譯dll的時候,把靜態庫一并加進來,就可以了

3.在注冊的函數中,命名有規則,a.dll對應extern int luaopen_a(lua_State *L),同時對應的庫名稱是a,也就是luaL_register(L,"a",表),如果規則不符合他就會提示找不到特定程序

他是調用某個特定的函數,這個函數包含了注冊這個模塊的信息,但是這個函數得符合上面的3的規則,如果不是標準的,就不能直接require導入,至于對一個的名稱和函數的地址關系,是通過一個表來實現的


VS2017版本

使用VS2017編譯lua擴展

代碼跟上面一樣,有設置不一樣的地方

1.lua解釋器不能使用靜態編譯,如果使用靜態編譯,只能使用一個虛擬機,再加載一個虛擬機就會報錯(百度結果,原因未理解)
2.編譯dll時,luaopen_xxx函數要添加_declspec(dllexport)
3.使用extern "C"包裹luaopen_xxx

image.png

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 靜態庫與動態庫的區別 首先來看什么是庫,庫(Library)說白了就是一段編譯好的二進制代碼,加上頭文件就可以供別...
    吃瓜群眾呀閱讀 12,074評論 3 42
  • 動態鏈接,在可執行文件裝載時或運行時,由操作系統的裝載程序加載庫。大多數操作系統將解析外部引用(比如庫)作為加載過...
    小5筒閱讀 5,564評論 0 3
  • 第一篇 語言 第0章 序言 Lua僅讓你用少量的代碼解決關鍵問題。 Lua所提供的機制是C不擅長的:高級語言,動態...
    testfor閱讀 2,724評論 1 7
  • 一、溫故而知新 1. 內存不夠怎么辦 內存簡單分配策略的問題地址空間不隔離內存使用效率低程序運行的地址不確定 關于...
    SeanCST閱讀 7,880評論 0 27
  • 動態調用動態庫方法c/c++linuxwindows 關于動態調用動態庫方法說明 一、 動態庫概述 1、 動態庫的...
    KINGZ1993閱讀 13,974評論 0 10