2018年4月

从c语言层分析python的实现原理

python作为一门开源的、跨平台的脚本语言,其底层全部用c来实现,下面从c语言的角度来分析python的执行过程

1. python解释器

编译python源码后,会在根目录生成python程序,此程序就是python脚本的解释器,python解释器主要由语法解析、编译和执行三个模块组成

2. python语法解析模块

python语法解析模块负责把python字符串或脚本文件根据其语法解析成c语言的数据结构

3. python编译模块

python编译模块负责把解析后的数据结构转换成虚拟机可执行的字节码对象PyCodeObject

4. python执行模块

python执行模块负责执行python字节码,通常也叫做python虚拟机

当执行python file时,python首先会判断file是否为字节码文件,通常字节码文件的扩展名为pyc或pyo,而普通python脚本为py,判断的逻辑如下:

if (maybe_pyc_file(fp, filename, ext, closeit)) {
        /* Try to run a pyc file. First, re-open in binary */
        if (closeit)
            fclose(fp);
        if ((fp = fopen(filename, "rb")) == NULL) {
            fprintf(stderr, "python: Can't reopen .pyc file\n");
            goto done;
        }
        /* Turn on optimization if a .pyo file is given */
        if (strcmp(ext, ".pyo") == 0)
            Py_OptimizeFlag = 1;
        v = run_pyc_file(fp, filename, d, d, flags);
    } else {
        v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d,
                              closeit, flags);
    }

若是字节码文件,则直接调用执行模块来执行,执行函数如下:

PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
                    PyObject *globals,
                    PyObject *locals,
                    PyObject **args, int argc,
                    PyObject **kwds, int kwdc,
                    PyObject **defs, int defc,
                    PyObject *closure);

若是脚本文件,则先调用解析模块再调用编译模块,执行函数如下:

PyAPI_FUNC(struct _mod *) PyParser_ASTFromString(const char *, const char *,
                                                 int, PyCompilerFlags *flags,
                                                 PyArena *);
PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile(FILE *, const char *, int,
                                               char *, char *,
                                               PyCompilerFlags *, int *,
                                               PyArena *);
PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,
                        PyCompilerFlags *, PyArena *);

通常很多人会认为,编译后的python脚本会执行很快,但事实并非如此,编译后的字节码文件只是省去了语法解析和编译两部分,所以执行效率和普通python脚本一样,只是加载速度相对较快。目前由于个人能力有限,暂时大概分析了python的执行过程,至于语法解析、编译和执行的细节,逻辑比较复杂,待内功修炼到一定层次,再一一揭开python的神秘面纱

自动生成GNU项目的configure和Makefile

通常开源的GNU项目编译和安装只需以下两步:

./configure
make && make install

而我们发布自己的个人项目通常手工写Makefile文件,总感觉跟GNU的Makefile文件相比很low,而且很多时候依赖系统的配置,因此就有以下工具帮助我们自动生成标准的configure文件和Makefile文件,下图就是工具的流程图:
2009052517385173.png

1. 自动扫描工具autoscan

在工程的根目录下运行autoscan命令,autoscan会自动扫描工程中的源码,生成configure.scan文件,然后把configure.scan文件重命名为configure.ac或configure.in,并做相应的修改,详细可参考文末的demo

2. m4文件生成工具aclocal

aclocal是一个perl脚本,可根据configure.ac生成aclocal.m4

3. configure文件生成工具autoconf

autoconf可根据configure.ac和aclocal.m4文件生成configure文件,configure是一个shell脚本,能根据不同的操作系统生成相应的Makefile

4. Makefile.in文件生成工具automake

首先编写Makefile.am文件,详细可参考文末的demo,automake会根据configure.ac和Makefile.am文件生成Makefile.in文件,运行automake通常带--add-missing选项,此选项会让automake加入一个标准的软件包所必须的一些文件

5. 生成最终Makefile文件

运行./confiugre,configure会根据Makfile.in文件生成最终的Makefile文件

由此可见,为了生成标准的Makefile文件,需要以上复杂的步骤,因此很多项目通常会有configure.ac、Makefile.am、autogen.sh三个文件,由autogen.sh根据configure.ac和Makefile.am文件自动完成以上步骤来生成Makefile文件,详情参考github地址:https://github.com/song2010040402102/autoconf_demo.git

对于autoconf系列的工具集,目前我也是仅知其然而不知其所以然,按以往的性格会把这整块吃透,只是最近才突然感觉到,时间和精力有限,应把主要的时间和精力放在内功修炼上,而不是类似工具这种外功上,工具会用即可,想搞明白只是时间问题,体现不出一个人的能力高低,所以此篇只介绍使用而不了解其细节实现