在学习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
都会抛出错误。