Lua學習之Mac下封裝C模組

2021-07-05 15:53:12 字數 3862 閱讀 1071

堅持 成長 每日一篇

平時用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時裝...