1. 如果你看下各模块下的生成的文件,你会发现so文件都是空的,如pyjnius,jnius.so就是空的
2. 这就奇了怪了,根据我们的知识储备,如果是调用了import jnius,并且jnius不是一个py,pyo或者pyc文件的话,那么python就会从动态库里去找initjnius进行模块的初始化了。
3. 但是现在动态库是空了,这是什么情况?
4. 还记得distribute.sh里的run_biglink吗?
5. 该函数把所有模块的o文件链接到libpymodules.so中
6. 但是python是怎么从里面取出相应的模块进行初始化的呢?
7. 答案在recipes\python\patches\custom-loader.patch里
8. 这是一个对dynload_shlib.c的patch,patch完后,dynload_shlib.c的_PyImport_GetDynLoadFunc就变成:
dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, const char *pathname, FILE *fp) { dl_funcptr p; void *handle; char funcname[258]; char pathbuf[260]; int dlopenflags=0; static void *libpymodules = NULL; void *rv = NULL; /* Ensure we have access to libpymodules. */ if (libpymodules == NULL) { printf("ANDROID_PRIVATE = %s\n", getenv("ANDROID_PRIVATE")); PyOS_snprintf(pathbuf, sizeof(pathbuf), "%s/libpymodules.so", getenv("ANDROID_PRIVATE")); libpymodules = dlopen(pathbuf, RTLD_NOW); if (libpymodules == NULL) { //abort(); } } if (strchr(pathname, '/') == NULL) { /* Prefix bare filename with "./" */ PyOS_snprintf(pathbuf, sizeof(pathbuf), "./%-.255s", pathname); pathname = pathbuf; } PyOS_snprintf(funcname, sizeof(funcname), LEAD_UNDERSCORE "init%.200s", shortname); /* Read symbols that have been linked into the main binary. */ if (libpymodules) { rv = dlsym(libpymodules, funcname); if (rv != NULL) { return rv; } } if (fp != NULL) { int i; struct stat statb; fstat(fileno(fp), &statb); for (i = 0; i < nhandles; i++) { if (statb.st_dev == handles[i].dev && statb.st_ino == handles[i].ino) { p = (dl_funcptr) dlsym(handles[i].handle, funcname); return p; } } if (nhandles < 128) { handles[nhandles].dev = statb.st_dev; #ifdef __VMS handles[nhandles].ino[0] = statb.st_ino[0]; handles[nhandles].ino[1] = statb.st_ino[1]; handles[nhandles].ino[2] = statb.st_ino[2]; #else handles[nhandles].ino = statb.st_ino; #endif } } #if !(defined(PYOS_OS2) && defined(PYCC_GCC)) dlopenflags = PyThreadState_GET()->interp->dlopenflags; #endif if (Py_VerboseFlag) PySys_WriteStderr("dlopen(\"%s\", %x);\n", pathname, dlopenflags); #ifdef __VMS /* VMS currently don't allow a pathname, use a logical name instead */ /* Concatenate 'python_module_' and shortname */ /* so "import vms.bar" will use the logical python_module_bar */ /* As C module use only one name space this is probably not a */ /* important limitation */ PyOS_snprintf(pathbuf, sizeof(pathbuf), "python_module_%-.200s", shortname); pathname = pathbuf; #endif handle = dlopen(pathname, dlopenflags); if (handle == NULL) { const char *error = dlerror(); if (error == NULL) error = "unknown dlopen() error"; PyErr_SetString(PyExc_ImportError, error); return NULL; } if (fp != NULL && nhandles < 128) handles[nhandles++].handle = handle; p = (dl_funcptr) dlsym(handle, funcname); return p; }
9. 该函数会加载libpymodules.so
10. 并且会先判断initxxx是否在libpymodules里存在
11. 如果存在,则会返加该函数的指针
12. 好,又消除了心中的一个大疑问!
(完)