如何编译和调试Python内核源码?
博客:blog.shinelee.me | 博客园 | CSDN
写在前面
如果对Python源码感兴趣,那“窥探”其实现的最佳方式就是调教它,不,调试它。
获取源代码
Python的官方默认实现为CPython,即C语言实现(主要指解释器的实现,其他实现见Other Interpreter Implementations)。CPython的源代码可以从官网pyhton.org或者github.com/python/cpython获取,目前最新的稳定版本为3.8.0,于2019.10.14发布。这里,从官网 https://www.python.org/downloads/release/python-380/ 下载源码压缩包,如下图所示,

源代码的组织
解压后,目录结构如下
{ Python-3.8.0 } » tree -d -L 1 .
.
├── Doc # rst(reStructuredText)格式官方文档,用其生成https://docs.python.org/
├── Grammar # Python的EBNF(Extended Backus–Naur form)语法定义文件
├── Include # .h 头文件
├── Lib # .py 纯Python实现的标准库
├── m4 # ?
├── Mac # Mac-specific code,支持MacOS
├── Misc # Things that do not belong elsewhere.
├── Modules # C实现的标准库,内含.c .asm .macros .h
├── Objects # 内置数据类型实现
├── Parser # Python语法分析器源码
├── PC # Windows-specific code,支持Windows
├── PCbuild # Windows生成文件,for MSVC
├── Programs # main函数文件,用于生成可执行文件,如python.exe的入口文件
├── Python # CPython解释器源码
└── Tools # 独立工具代码,used to maintain Python
CPython的源码组织结构如下,摘抄自CPython Source Code Layout,

源码文件分门别类存放,而且,无论是py实现的标准库、c实现的标准库、内置数据类型还是内置函数,在Lib/test/和Doc/library/目录下都有与之对应的test_x.py测试文件和rst文档文件(对于内置数据类型和函数,其文档集中保存在stdtypes.rst和functions.rst)。比如,内置类型int位于Objects/longobject.c文件中。
下面正式开始编译CPython。
windows下编译CPython
据Compile and build on Windows,Python3.6及之后的版本可以使用VS2017编译,安装VS2017时,记得勾选 Python development 和 Python native development tools,有备无患。
安装好VS2017后,双击PCbuild/pcbuild.sln,打开解决方案。因为我们的关注点仅在Python内核和解释器部分,所以仅编译python和pythoncore,其他模块暂时忽略,具体地,
- 切换到debug win32
- 右键解决方案→属性→配置属性
- 仅勾选项目python和pythoncore
- 确定

此时再“生成解决方案”,生成目录为PCbuild/win32,内容如下,含解释器python_d.exe和内核python38_d.dll,

接下来,将项目python设为启动项目(默认状态即是启动项目),点击调试,运行得到如下控制台,可以像平时使用python一样,与之交互。

如果想生成全部模块,需要运行PCbuild\get_externals.bat下载依赖,再编译,具体可参见Build CPython on Windows。
调试CPython
只要程序能运行起来,一切就好办了。凭借“宇宙最强IDE”,我们可以任性地设断点调试甚至修改代码。
F5重新启动调试,弹出控制台。在上面我们知道int类型位于Objects/longobject.c文件,打开文件,简单浏览后在函数PyObject * PyLong_FromLong(long ival)入口处打个断点。然后,在弹出的控制台中输入a = 1来创建int对象,回车,程序停在了断点处,查看变量ival的值为1——恰为我们输入的数值,这个函数会跟根据输入的C long int创建一个int对象,返回对象指针。

再来看看函数调用堆栈,如下图所示,

调用顺序从下至上,从中可以推断出,
- 从python_d.exe的入口main运行起来后,进入python38_d.dll
- 从标准输入stdin中读取键入的字符串
- 解析字符串,建立了语法树AST(abstract syntax tree)
- 解析语法树中的节点,判断字符为number,将字符串转化为C long int
- 由C long int创建Python的
int对象
继续运行,弹出的控制台中光标前出现<<<,等待输入。这时如果我们点击调试中的停止按钮(全部中断),会发现程序停在Parser/myreadline.c文件_PyOS_WindowsConsoleReadline函数中的ReadConsoleW一行,
if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) {
err = GetLastError();
goto exit;
}
ReadConsoleW为WINAPI,详见ReadConsole function,其等待并读取控制台的输入,读取的字符保存在wbuf中。如果有输入,则进入上面的流程,解析→建立语法树→……
小结
至此,我们揭开了Python面纱的一角——不过是一个可运行、可调试的程序而已(微笑)。
参考
- Directory structure
- reStructuredText
- Extended Backus–Naur form
- Exploring CPython’s Internals
- Compile and build on Windows
如何编译和调试Python内核源码?的更多相关文章
- ubuntu14.04 64位系统下编译3.13.11内核源码
该过程一共分为四步: 1.下载内核:我下载的是3.13.11这个版本的内核! 2.解压内核:我将其解压/home/jello/Downloads/linux-3.13.11目录下!下文将会基于此目录编 ...
- centos7编译linux的内核源码
昨天编译了一个linux 内核源码,遇到一些问题, 今天把我遇到的问题和解决方法分享给大家.希望可以帮助到需要的人. 1.检查是否安装了相应的包 我第一次编译的时候只安装的“Development T ...
- Linux内核源码特殊用法
崇拜并且转载的: http://ilinuxkernel.com/files/5/Linux_Kernel_Source_Code.htm Linux内核源码特殊用法 1 前言 Linux内核源码主要 ...
- 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 百篇博客分析OpenHarmony源码 | v59.01
百篇博客系列篇.本篇为: v59.xx 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿 ...
- 鸿蒙内核源码分析(编译脚本篇) | 如何防编译环境中的牛皮癣 | 百篇博客分析OpenHarmony源码 | v58.01
百篇博客系列篇.本篇为: v58.xx 鸿蒙内核源码分析(环境脚本篇) | 编译鸿蒙原来如此简单 | 51.c.h.o 本篇用两个脚本完成鸿蒙(L1)的编译环境安装/源码下载/编译过程,让编译,调试鸿 ...
- ubuntu下linux内核源码阅读工具和调试方法总结
http://blog.chinaunix.net/uid-20940095-id-66148.html 一 linux内核源码阅读工具 windows下当然首选source insight, 但是l ...
- 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视GCC编译全过程 | 百篇博客分析OpenHarmony源码| v57.01
百篇博客系列篇.本篇为: v57.xx 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视编译全过程 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙 ...
- 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙看这篇或许真的够了 | 百篇博客分析OpenHarmony源码 | v50.06
百篇博客系列篇.本篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉坑指南 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉 ...
- 编译Debian内核源码
参考: <鸟哥的Linux私房菜>第26章 http://hi.baidu.com/wg_wang/item/f9375c2f00ca75c0ee10f1db http://www.lin ...
随机推荐
- Dokit支持iOS本地crash查看功能
一.前言 在日常开发中或者测试过程中,我们的应用可能会出现Crash的问题.对于这类问题我们要抱着零容忍的态度,因为如果线上出现了这类问题,将会严重影响用户的体验. 如果Crash出现的时候恰好是在开 ...
- 微信小程序实现pdf,word等格式文件上传
目前微信只支持从聊天记录里面获取文件 一.前言 目前微信提供了一个接口 wx.chooseMessageFile 它能让用户从聊天记录里面选择一个或者多个文件,然后返回它的一些信息,列入文件的path ...
- js 大量数据优化,通用方法
当页面渲染太多标签时,会出现卡顿的,典型就是类似table数据太多时,非常卡顿.如果选择分页,没必要讨论,这儿只讨论采用滚动的情况.解决思路很简单,就是页面不展示出来的元素,从页面上删除掉,最难点在于 ...
- Spring Boot2 系列教程(四)理解Spring Boot 配置文件 application.properties
在 Spring Boot 中,配置文件有两种不同的格式,一个是 properties ,另一个是 yaml . 虽然 properties 文件比较常见,但是相对于 properties 而言,ya ...
- Container容器crontab错误问题
问题描述 容器中的cron定时计划任务不执行 问题分析 排查一:检查Container容器是否安装cron # rpm -qa | grep cron # ls /etc/init.d/ 若没有安装, ...
- FreeSql (三十一)分区分表
分区 分区就是把一个数据表的文件和索引分散存储在不同的物理文件中.把一张表的数据分成N多个区块,这些区块可以在同一个磁盘上,也可以在不同的磁盘上,数据库不同实现方式有所不同. 与分表不同,一张大表进行 ...
- Spring MVC+ajax进行信息验证
本文是一个ajax结合Spring MVC使用的入门,首先我们来了解一下什么是Ajax AJAX 不是新的编程语言,而是一种使用现有标准的新方法.AJAX 最大的优点是在不重新加载整个页面的情况下,可 ...
- Winform中设置ZedGraph曲线图的水平与竖直参考线
场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...
- 花果山第一届猿类分级考试实录--Talk is cheap,Show me the code
本故事纯属虚构,如有雷同,纯属巧合! 故事背景 悟空师徒4人取经回来后,因不耐收到管教,就回到了花果山,带领一帮猴子猴孙逍遥自在的过日子,奈何因在阎王殿里将生死薄中的猴子猴孙的名字都划去了,猴子猴孙是 ...
- 初识Node.js之Node与java作为后台服务器的对比
> 文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. ![file](https://img2018.cnblogs.com/blog/830272/20 ...