进一步理解Python——编译python

一、python的整体架构

python在执行的过程中,会不断地修改当前解释器所处的状态,在不同的状态之间切换。 解释器与右边的对象/类型系统、内存分配器之间的箭头表示“使用”关系,而与运行时状态之间的箭头表示“修改”关系。

1.1 File Group

内建模块、库、用户自定义模块

1.2 RuntimeEnvironment

运行时环境

1.2.1 Object/Type Structures

对象/类型系统,包含了python中存在的各种内建对象,比如整数、list和dict,以及各种用户自定义的类型和对象。

1.2.2 Memory Allocator

内存分配器,全权负责python中创建对象时,对内存的申请工作,实际上它就是python运行时与c中malloc的一层接口。

1.2.3 Current State of Python

运行时状态信息,维护了教室起在执行字节码时不同的状态之间切换的动作,我们可以将它视为一个巨大而复杂的有穷状态机。

1.3 python核心-interpreter解释器/虚拟机

1.3.1 scanner

词法分析,将文件输入的python源代码或从命令行输入的一行行python代码分为一个个的token

1.3.2 parser

语法分析,在Scanner的分析结果上进行语法分析,简历抽象语法树(AST)

1.3.3 compiler

编译字节码,根据AST生成指令集合——python字节码(byte code)

1.3.4 Code Evaluator

虚拟机,执行字节码。

二、Python源代码的组织

下载源码地址:https://www.python.org/downloads/release/python-372/

2.1 Include

该目录下包含了Python提供的所有头文件,如果用户需要用C/C++来编写自定义模块扩展Python,那么久需要用到这里提供的头文件。

2.2 Lib

包含了Python自带的所有标准库,Lib中的库都是Python语言编写的。

2.3 Modules

包含了所有用C语言编写的模块,比如random,cStringIO等。Modules中的模块是那些对速度要求非常严格的模块,而有一些对速度没有太严格要求的模块,用Python编写,放在Lib下。

2.4 Parser

包含了Python解释器中的Scanner和Parser部分,即对Python源代码进行词法分析和语法分析部分。

2.5 Objects

包含了所有Python的内建对象,包括整数、list、dict等。同时,该目录还包括了Python在运行时需要的所有的内部使用对象的实现。

2.6 Python

包含了Python解释器中的Compiler和执行引擎部分,是python运行的核心所在。

2.7 PCBuild

包含了Visual Studio的工程文件,研究Python源代码就从这里开始。

三、Unix/Linux 环境下编译Python

3.1 进入解压文件夹

/Users/kenwu/Desktop/pythonsyscode/pythonsource/Python-3.7.2

3.2 添加配置

./configure --prefix=/usr/python372 注意:这里配置 python 的安装目录,自带的 python 一般安装在 /usr/bin/ 目录下。 configure 命令执行完之后,会生成一个 Makefile 文件,这个 Makefile主要是被下一步的 make 命令所使用。打开 Makefile 你就会发现,里边制定了构建的顺序

3.3 编译源码

make

3.4 执行安装

make install

注意:报错:zipimport.ZipImportError: can't decompress data; zlib not available 解决方案参见:http://www.code4fs.xyz/article/39/

安装完之后,执行 python 命令,你会发现默认的 python 命令仍旧是指向旧的版本 2.7.10

sudo ln -s /usr/python372/bin/python3 /usr/bin/python3 

bin目录下存放的是可执行文件。 lib目录下存放的是python标准库 /usr/python372/lib/libpython3.7m.a 用c语言对python进行扩展时,需要用到这个静态库。

四、Windows下安装编译python

该学习记录来源于陈儒《Python源码剖析》,所以我们按照书本中的版本来创建,同时为了看看新版3的区别,此处我们选择Cpython2.7与3.7

python版本:

Cpython  2.7
https://github.com/python/cpython/tree/2.7

Cpython 3.7
https://github.com/python/cpython/tree/3.7

vs版本:

2017 
https://www.python.org/downloads/release/python-250/

.net framework:

4.6.2 
https://dotnet.microsoft.com/download/thank-you/net462

4.1 编译Cpython 2.7

1、打开VS2017打开项目cpython-2.7\PCbuild\pcbuild.sln,会提示升级SDK,确定,这会帮我们自动重定向SDK

2、移除冗余目录 我们只关心 pythoncore 目录下的源码,因此可以在解决方案资源管理器中,把其他目录从管理器中移出,避免对后期搜索结果的影响。 但要保留 python 目录,因为该目录下的 python.c 是程序入口。 也就是说最后只保留 pythoncore 和 python 这两个目录在解决方案资源管理器中即可,后期所有的调试工作都在 pythoncore 目录下进行。

3、编译 点击编译报错,如上图。timemodule.c下的标识符timezone、daylight和tzname未定义,这是升级SDK的缘故。 修改文件: a、首先把 cpython-2.7\Modules\posixmodule.c 下的 _PyVerify_fd 函数内容替换为如下代码:

int
_PyVerify_fd(int fd)
{
    if (_get_osfhandle(fd) == INVALID_HANDLE_VALUE)
        return 0;
    else
        return 1;
}

b、修改cpython-2.7\Modules\timemodule.c 中 inittimezone 函数中报错的变量 timezone、daylight 和 tzname 分别改为 _timezone、_daylight 和 _tzname

c、点击“本地windows调试器”,编译源码,方案为debug-win32 生成文件目录如下:cpython-2.7\PCbuild

4.2 编译Cpython 3.7

1、打开cpython-3.7\PCbuild\pcbuild.sln

2、在解决方案资源管理器中:右键 “python” -> 重定向项目 -> 选择 Windows SDK 版本为 10.0.17134.0 (或其他 Win10 版本的SDK即可),pythoncore 同样的操作,移除这两项之外的目录。

3、在解决方案资源管理器中:右键 “pythoncore” -> 属性 -> 配置属性 -> C/C++ -> 预处理器 -> 右侧编辑“预处理器定义” -> 添加 “X86

4、编译点击 “本地windows调试器” 开始编译源码,方案为 Debug-Win32

编译成功后在 cpython-3.7\PCbuild\ 目录下会多出两个目录:obj 和 win32 其中win32 目录中存放着编译好的 python二进制可执行文件 由于我们的编译模式为Debug,所以该文件名为 python_d.exe 而不是python.exe

五、修改Python源代码

比如在int_print中输出一个整数:

```c int_print(PyIntObject v, FILE fp, int flags) / flags -- not used but required by interface / { //add by kenwu PyObject* str = PyString_FromString("I am in func int_print"); PyObject_Print(str, stdout, 0); printf("\n");

long int_val = v->ob_ival;
Py_BEGIN_ALLOW_THREADS
fprintf(fp, "%ld", int_val);
Py_END_ALLOW_THREADS
return 0;

} ```


评论(0 ) 点赞(12)


暂未登录,请登录之后发表评论。 QQ