为什么要写阅读源码
上篇写了lua的数据类型之后,思考了下,觉得还是要先写下源码阅读相关的。不然的话,很多东西都是死记硬背的,不知其然,也不知其所以然。这篇简单写下我所阅读过的吧,对自己有个小结,也希望能帮助到更多的人。
库阅读顺序I
一般而言,都是从main函数来阅读的。首先,找到lua.c,可以找到main函数如下:
int main (int argc, char **argv) { int status, result; lua_State *L = luaL_newstate(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushinteger(L, argc); /* 1st argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */ status = lua_pcall(L, 2, 1, 0); /* do the call */ result = lua_toboolean(L, -1); /* get result */ report(L, status); lua_close(L); return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; }
其实,最重要的就是pmain这个函数了。pmain函数,如下截图:
从上图可以看到很多,最重要的只有一个luaL_openlibs(L)这个函数;
进入到这个函数,可以看到如下代码:
LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* "require" functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } }
再看下loadedlibs这个定义,如下:
/* ** these libs are loaded by lua.c and are readily available to any Lua ** program */ static const luaL_Reg loadedlibs[] = { {LUA_GNAME, luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} };
这就找到了各个库代码的定义的地方。
当然,这是1种方法;接下来,我们说下方法二;
库阅读顺序II
再从中找到公共部分,就是lualib.h,再看下这个头文件,
/* version suffix for environment variable names */ #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR LUAMOD_API int (luaopen_base) (lua_State *L); #define LUA_COLIBNAME "coroutine" LUAMOD_API int (luaopen_coroutine) (lua_State *L); #define LUA_TABLIBNAME "table" LUAMOD_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" LUAMOD_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUAMOD_API int (luaopen_string) (lua_State *L); #define LUA_UTF8LIBNAME "utf8" LUAMOD_API int (luaopen_utf8) (lua_State *L); #define LUA_MATHLIBNAME "math" LUAMOD_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" LUAMOD_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" LUAMOD_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ LUALIB_API void (luaL_openlibs) (lua_State *L); #if !defined(lua_assert) #define lua_assert(x) ((void)0) #endif
这里,我们大概可以找到最主要的一些库文件,了解到我们想知道的代码,或者扩展一些我们自己定义的方法。
找个简单的函数,比如print函数:这个在luaopen_base里,我们可以找到base_func,然后找到print函数
如下图,为luaopen_base函数,在lbaselib.h中,
LUAMOD_API int luaopen_base (lua_State *L) { /* open lib into global table */ lua_pushglobaltable(L); luaL_setfuncs(L, base_funcs, 0); /* set global _G */ lua_pushvalue(L, -1); lua_setfield(L, -2, LUA_GNAME); /* set global _VERSION */ lua_pushliteral(L, LUA_VERSION); lua_setfield(L, -2, "_VERSION"); return 1; }
下图为base_funcs,可以找到print函数,从而进一步找到print函数的实现
static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, {"getmetatable", luaB_getmetatable}, {"ipairs", luaB_ipairs}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, {"next", luaB_next}, {"pairs", luaB_pairs}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"warn", luaB_warn}, {"rawequal", luaB_rawequal}, {"rawlen", luaB_rawlen}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, {"select", luaB_select}, {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, {"xpcall", luaB_xpcall}, /* placeholders */ {LUA_GNAME, NULL}, {"_VERSION", NULL}, {NULL, NULL} };
下图为print函数的实现:
static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; for (i = 1; i <= n; i++) { /* for each argument */ size_t l; const char *s = luaL_tolstring(L, i, &l); /* convert it to string */ if (i > 1) /* not the first element? */ lua_writestring("\t", 1); /* add a tab before it */ lua_writestring(s, l); /* print it */ lua_pop(L, 1); /* pop result */ } lua_writeline(); return 0; }
好了,大致流程如此。这些只是我的个人理解,希望真的帮助到正在看的你,也希望你又更深的理解。