Lua本身是一個輕量級的腳本語言,包含在Lua源碼中的庫功能通常相對單一,用戶通常需要自己內嵌Lua解釋器到自己的應用中,並且一個一個地將需要導出的函數導出給Lua使用。
假如我們需要使用第三方的庫,比如LuaFileSystem庫——lfs、用於網絡的Socket庫或者計算Base64編碼的庫,除了找到其源碼,並拷貝到自己的應用代碼中之外,還有沒有別的什么方式呢?
大家都知道Windows DLL,這是一種動態鏈接的方式。Lua同樣也支持這樣一種模塊加載的方式。你只需將所需的第三方庫的DLL放到Lua的環境路徑中——這個我暫時並不能窮舉出具體有哪些,期待高人解答——或者簡單地將其放入你的Lua解釋器目錄下。接着,在需要使用的腳本中,直接調用Lua的require函數,將DLL的名字去除擴展名作為參數,Lua就可以自動加載指定的DLL模塊,並將其模塊導出的內容打包到一個table中並返回。你可以使用一個全局的table來接收其引用。
對於自己編寫的模塊,也可以采用相同的方式去編寫。只需導出一個可以通過require加載的函數符號就可以了——require內部通過Windows API GetProcAddress來尋找其地址。這個函數的格式需要遵循Lua的模塊標准,格式如下:

static int foo(lua_State *L) { lua_pushnumber(L, 1); return 1; } static const struct lua_Reg modulename[] = { {"foo", foo}, {NULL,NULL}, }; int luaopen_modulename(lua_State *L) { luaL_newlib(L, modulename); // 5.2之前使用luaL_register(L, "modulename", modulename); return 1; }
Lua5.2修改了其導出模塊的格式,大家要注意一下。
當你在腳本中使用require加載一個模塊xxx的時候,首先它會在Lua的環境路徑中尋找以xxx命名的DLL,如果找到了,則會在這個DLL中尋找luaopen_xxx的函數用於加載模塊。我們只需要將自己需要導出給Lua調用的C內容通過這個函數導出就可以了,具體方式可以查看Lua的源碼,參考其math數學庫luaopen_math的實現。使用起來確實相當方便。只不過要注意一下Lua5.2與之前版本的不兼容性——導出函數從LuaL_register變成了LuaL_newlib,雖然可以選擇開啟Lua5.2的兼容模式來繼續使用LuaL_register,但我嘗試的時候總是在Lua_checkversion的時候出錯,提示說Multiple VMs detected。暫時來說,我是參考lfs庫的實現方式,自己重定義宏LuaL_register。
完整的示例我已經上傳到GitHub中了,請用Visual Studio 2010查看其中的mylib工程,歡迎指正。