在學習ulua時,require
模塊的根路徑能夠爲項目的Lua文件夾或者ToLua文件夾(Editor下),可是在package.path
和package.cpath
中並無看到當前項目的路徑,那require是如何找到Lua和ToLua文件夾的路徑的呢?html
LuaState
時,會先解析package.path
, 並將其存入LuaFileUtils
的SearchPaths
中(LuaState.cs line:603),並將Lua和ToLua的目錄添加其中(LuaState.cs line:187)。ToLua.OpenLib(T)
,該方法定義了一下特殊方法,能夠在lua中使用,如typeof
等。OpenLib
方法會在package.loaders
數組中,再添加一個loader,而且將其放到數組的第二個位置。(ToLua.cs line:192)注:Lua require模塊時,會依次調用package.loader中的方法,找到則返回LuaFileUtils
的SearchPaths
,若是存在就讀取文件,若不存在則返回空(LuaFileUitls.cs line:170)摘自http://cloudwu.github.io/lua53doc/manual.html#6.3
根據lua5.1 手冊作了部分修改git
爲指定的模塊,設置loader,在require模塊時,先去查詢這張表,若是有值,則使用preload中的loader(能夠用於修改特殊模塊的加載策略)github
這個路徑被 require 在 Lua 加載器中作搜索時用到。
在啓動時,Lua 用環境變量 LUA_PATH
來初始化這個變量。 或採用 luaconf.h
中的默認路徑。 環境變量中出現的全部 ";;
" 都會被替換成默認路徑。數組
這個路徑被 require
在 C 加載器中作搜索時用到。函數
Lua 用和初始化 Lua 路徑 package.path
相同的方式初始化 C 路徑 package.cpath
。 它會使用環境變量LUA_CPATH
初始化。 要麼就採用 luaconf.h
中定義的默認路徑。學習
用於 require
控制如何加載模塊的表。ui
這張表內的每一項都是一個 查找器函數。 當查找一個模塊時, require
按次序調用這些查找器, 並傳入模塊名(require
的參數)做爲惟一的一個參數。 此函數能夠返回另外一個函數(模塊的 加載器)加上另外一個將傳遞給這個加載器的參數。 或是返回一個描述爲什麼沒有找到這個模塊的字符串 (或是返回 nil 什麼也不想說)。lua
Lua 用四個查找器函數初始化這張表。3d
第一個查找器就是簡單的在 package.preload
表中查找加載器。code
第二個查找器用於查找 Lua 庫的加載庫。 它使用儲存在 package.path
中的路徑來作查找工做。路徑是一個包含有一系列以分號分割的 模板 構成的字符串。 對於每一個模板,都會用 name
替換其中的每一個問號(若是有的話)。 且將其中的 點替換爲系統的目錄分割符(如 Unix中的"/")。 而後嘗試打開這個文件名。
例如,若是路徑是字符串
"./?.lua;./?.lc;/usr/local/?/init.lua"
搜索 foo.a
這個名字將 依次嘗試打開文件 ./foo/a.lua
, ./foo/a.lc
,以及 /usr/local/foo/a/init.lua
。
第三個查找器用於查找 C 庫的加載庫。 它使用儲存在 package.cpath
中的路徑來作查找工做。 例如,若是 C 路徑是這樣一個字符串
"./?.so;./?.dll;/usr/local/?/init.so"
查找器查找模塊 foo
會依次嘗試打開文件 ./foo.so
,./foo.dll
, 以及 /usr/local/foo/init.so
。 一旦它找到一個 C 庫, 查找器首先使用動態連接機制鏈接該庫。 而後嘗試在該庫中找到能夠用做加載器的 C 函數。 這個 C 函數的名字是 "luaopen_
" 緊接模塊名的字符串, 其中字符串中全部的下劃線都會被替換成點。 此外,若是模塊名中有橫線, 橫線後面的部分(包括橫線)都被去掉。 例如,若是模塊名爲 a.b.c-v2.1
, 函數名就是luaopen_a_b_c
。
第四個搜索器是 一體化加載器。 它從 C 路徑中查找指定模塊的根名字。 例如,當請求 a.b.c
時, 它將查找 a
這個 C 庫。 若是找獲得,它會在裏面找子模塊的加載函數。 在咱們的例子中,就是找 luaopen_a_b_c
。 利用這個機制,能夠把若干 C 子模塊打包進單個庫。 每一個子模塊均可以有本來的加載函數名。
加載一個模塊。 這個函數首先查找 package.loaded
表, 檢測 modname
是否被加載過。 若是被加載過,require
返回 package.loaded[modname]
中保存的值。(防止重複加載) 不然,它試着爲模塊尋找 加載器 。
首先 require
查找 package.preload[modname]
。 若是這裏有一個值,這個值(必須是一個函數)就是那個加載器。 不然 require
使用 Lua 加載器去查找 package.path
的路徑。 若是查找失敗,接着使用 C 加載器去查找 package.cpath
的路徑。 若是都失敗了,再嘗試 一體化 加載器 (參見 package.loaders
。
每次找到一個加載器,require
都用一個參數調用加載器: modname
。 若是加載器返回非空值, require
將這個值賦給package.loaded[modname]
。 若是加載器沒能返回一個非空值用於賦給 package.loaded[modname]
, require
會在那裏設入 true 。 不管是什麼狀況,require
都會返回 package.loaded[modname]
的最終值。
若是在加載或運行模塊時有錯誤, 或是沒法爲模塊找到加載器, require
都會拋出錯誤。