堅持 成長 每日一篇
平時用mac的同學可以看下,在mac下如何封裝乙個c庫給lua用,這兩天看了好多帖子都沒有成功打包,今天這裡做乙個詳細的教程,總結一下。
首先我們寫乙個c檔案,**如下
test.c
#include "lauxlib.h"
#include "lualib.h"
#include "lua.h"
//待註冊的c函式,該函式的宣告形式在上面的例子中已經給出。
static
int add(lua_state* l)
static
int sub(lua_state* l)
//lual_reg結構體的第乙個欄位為字串,在註冊時用於通知lua該函式的名字。
//第乙個欄位為c函式指標。
//結構體陣列中的最後乙個元素的兩個欄位均為null,用於提示lua註冊函式已經到達陣列的末尾。
static
const
struct lual_reg mylibs = ,
,};//該c庫的唯一入口函式。其函式簽名等同於上面的註冊函式。見如下幾點說明:
//1. 我們可以將該函式簡單的理解為模組的工廠函式。
//2. 其函式名必須為luaopen_***,其中***表示library名稱。lua**require "***"需要與之對應。
//3. 在lual_register的呼叫中,其第乙個字串引數為模組名"***",第二個引數為待註冊函式的陣列。
//4. 需要強調的是,所有需要用到"***"的**,不論c還是lua,都必須保持一致,這是lua的約定,
// 否則將無法呼叫。
int luaopen_mytestlib(lua_state* l)
終端編譯
bogon:liblua chris$ gcc -c
-i/usr/local/include test.c //編譯不連線
bogon:liblua chris$ gcc -bundle
-undefined dynamic_lookup -o mytestlib.so test.o //連線生成動態庫
終端lua互動模式
> require "mytestlib"
table:
0x7fb9696010c0
> mytestlib.add(100.0,200.0)
300.0
> mytestlib.sub(200.0,10)
190.0
lua成功呼叫了add和sub的方法。
我在網上很多教程裡會看到一些東西這裡特別注意幾點:
1.包含lua的標頭檔案使用 #include 「」而不使用#include<> 原因。使用尖括號(< >),對於a類,預處理程式cpp在系統預設包含檔案目錄(如/usr/include)中搜尋相應的檔案。使用雙引號(「 」),預處理程式在目標檔案的資料夾內搜尋相應檔案。由於我的標頭檔案沒有放在/usr/include中所以我用的是雙引號(「 」)。
2.由於標頭檔案使用的是雙引號,我們要通過-i dirname,告訴編譯標頭檔案的位置如:-i /usr/local/include.i必須大寫
3.如果你用 c 方式來編譯它,但用在 c++中,那麼你需要象下面這樣來包含 lua.h 標頭檔案。如果只是c語言就不需要extern 「c」(「完全不懂c++….不然說不定也不會因為這事整了兩天」)
extern
"c"
4.對於require的使用,路徑注意自己的載入的動態庫是否是自己的庫。具體require的原理看附錄
將包含c函式的**生成庫檔案,如linux的so,或windows的dll,同時拷貝到lua**所在的當前目錄,或者是lua_cpath環境變數所指向的目錄,以便於lua解析器可以正確定位到他們。我的mac上的環境變數在」/usr/local/lib/lua/5.3/」,這裡包含了所有lua可呼叫的c庫。
5.打包的動態包mytestlib.so必須是和 lua_setglobal(l,libname);的第二個引數名一致。
6.編譯時 -bundle -undefined dynamic_lookup 如果不使用這些選項,liblua將會被編譯到so檔案中並引起「multiple lua vms detected」錯誤, bundle是mac使用的檔案格式。
7.附加乙個移動端動態庫的編譯方法,這樣lua就可以調動移動端的.m 格式的oc**
xcrun -sdk iphoneos gcc -arch armv7 -arch armv7s -arch arm64 -miphoneos
-version
-min
=4.3
-o3-std
=c99 -i/opt/theos/include/
-c-o mt.o mt.m
xcrun -sdk iphoneos gcc -arch armv7 -arch armv7s -arch arm64 -miphoneos
-version
-min
=4.3
-o3-framework foundation -framework uikit -bundle
-undefined dynamic_lookup -o mt.so mt.o
?;?.lua;c:\windows\?;/usr/local
/lua/?/?.lua
呼叫 require 「lili」時會試著開啟這些檔案:
lili
lili.lua
c:\windows\lili
/usr/local/lua/lili/lili.lua
require 關注的問題只有分號(模式之間的分隔符)和問號,其他的資訊(目錄分隔 符,副檔名)在路徑中定義。
為了確定路徑,lua 首先檢查全域性變數 lua_path 是否為乙個字串,如果是則認 為這個串就是路徑;否則 require 檢查環境變數 lua_path 的值,如果兩個都失敗 require 使用固定的路徑(典型的」?;?.lua」)
require 的另乙個功能是避免重複載入同乙個檔案兩次。lua 保留一張所有已經載入 的檔案的列表(使用 table 儲存)。如果乙個載入的檔案在表中存在 require 簡單的返回; 表中保留載入的檔案的虛名,而不是實檔名。所以如果你使用不同的虛檔名 require 同乙個檔案兩次,將會載入兩次該檔案。比如require 「foo」和require 「foo.lua」,路徑為 「?;?.lua」將會載入 foo.lua 兩次。我們也可以通過全域性變數_loaded 訪問檔名列表, 這樣我們就可以判斷檔案是否被載入過;同樣我們也可以使用一點小技巧讓require載入 乙個檔案兩次。比如,require 「foo」之後_loaded[「foo」]將不為 nil,我們可以將其賦值 為 nil,require 「foo.lua」將會再次載入該檔案。
乙個路徑中的模式也可以不包含問號而只是乙個固定的路徑,比如:
?;?.lua;/usr/local/default.lua
這種情況下,require 沒有匹配的時候就會使用這個固定的檔案(當然這個固定的路 徑必須放在模式列表的最後才有意義)。在 require 執行乙個 chunk 以前,它定義了乙個 全域性變數_requiredname 用來儲存被 required 的虛檔案的檔名。我們可以通過使 用這個技巧擴充套件 require 的功能。舉個極端的例子,我們可以把路徑設為 「/usr/local/lua/newrequire.lua」,這樣以後每次呼叫 require 都會執行 newrequire.lua,這種 情況下可以通過使用_requiredname 的值去實際載入 required 的檔案。 Lua學習筆記之模組
模組require 使用模組 module 建立模組 通過require 來載入乙個模組,返回乙個全域性變數table型別。local a require mod foo require 函式,搜尋模組名時,使用乙個 分隔的路徑。我遇到過乙個載入路徑的問題,最後得到的結論是 那一串路徑中一般第乙個 ...
c 學習之 封裝
封裝 封閉 讓你的隱私,屬於你個人 有乙個保護性的外殼或膜抱起來。1.封裝意味著保證類中的一些資料是私有的。使用封裝來控制對類的方法和字段的訪問。私有欄位和方法只能從類的內部訪問 乙個物件要想得到另乙個物件私有欄位中儲存的資料,只有乙個辦法,就是使用返回該資料的公共欄位和方法。相關問題 問 我需要通...
Lua語言學習之模組與包
一 lua基本庫中的 載入函式 lua基本庫中有一些函式,能夠在執行原始碼之前,先將原始碼預編譯為一種中間形式,或者是 載入別的 lua 1.loadfile filename 該函式會從乙個檔案載入 lua 塊,但它不會執行 只是編譯 然後將編譯結果作為乙個函式返回,當沒有指定filename時裝...