这段经历太宝贵了,以后无论你换电脑,还是有朋友想学,照着这份流程走,绝对能省下几天几夜的时间。
咱们把时间线拉回起点,我为你整理了一份从零开始、极其详细的安装与配置全流程:
🚀 Windows 从零编译 CPython 3.9 终极通关指南
🛠️ 准备阶段:所需"武器"
Git:用来下载源码(已安装)。
Visual Studio 2026 (Community):提供 C/C++ 编译环境。
VS Code:作为我们看代码、写脚本和调试的主战场。
一个能上网的脑子:准备好面对各种奇葩报错。
第一步:获取 CPython 源码(绕过网络封锁)
因为国内直连 GitHub 极不稳定,我们采用了 Gitee 镜像。
打开终端(CMD 或 PowerShell)。
执行以下命令,指定拉取 3.9 分支的源码:
bash
git clone --branch 3.9 https://gitee.com/mirrors/Python.git cpython
进入源码目录:
bash
cd cpython
cd PCbuild
第二步:配置 C++ 编译工具集(漫长且痛苦的避坑)
VS 2026 默认不包含老版本的编译工具集,会导致 MSB8020 报错。
打开 Visual Studio Installer,找到 VS 2026,点击"修改"。
切换到 "单个组件" 标签页,在搜索框搜索。
勾选 MSVC v142 - VS 2019 C++ x64/x86 生成工具(极其重要,CPython 3.9 最兼容这个版本,别勾成带 MFC 的,浪费空间)。
点击"修改"等待安装完成。

第三步:获取外部依赖(终极黑客魔法)
get_externals.bat 会去 GitHub 下载依赖,国内必定超时。我们"魔改"了它。
用 VS Code 或记事本打开 PCbuild\get_externals.bat。
找到所有包含 openssl 和 tcltk 的代码行(大概在 45 行和 52 行附近)。
在它们前面加上 rem(例如 rem if NOT "%IncludeSSL%"=="false")将其注释掉。因为这两个模块对研究核心机制不致命,没必要死磕。
保存文件。

🛠️ 终极修复:使用 VS Code 的内置变量
咱们别写死绝对路径了,用 VS Code 的魔法变量,让它自己去算文件在哪。
请打开你左侧的 .vscode/launch.json 文件,把内容修改为下面这样:
json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug CPython C Source",
"type": "cppvsdbg",
"request": "launch",
"program": "C:/Users/lenovo/cpython/PCbuild/amd64/python.exe",
"args": "file","stopAtEntry":false,"cwd":"{file}"], "stopAtEntry": false, "cwd": "file"],"stopAtEntry":false,"cwd":"{workspaceFolder}",
"environment": \[\],
"console": "externalTerminal"
}
]
}
⚠️ 重点看这里:
我把 "args" 改成了 "${file}"。这个 KaTeX parse error: Expected '}', got 'EOF' at end of input: ... "args": "{file}",
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": \[\],
"console": "integratedTerminal"
}
]
}
🎯 重新操作步骤:
- 保存 launch.json。
- 关掉刚才弹出的那个黑色控制台窗口。
- 确保你在 VS Code 里点开了 Objects/unicodeobject.c,并在里面打好了红点。
- 在资源管理器里点开 test_intern.py,按 F5。
这一次,不要切换走。你应该会看到 VS Code 底部弹出"终端"面板,里面运行着你的代码,然后 VS Code 突然"卡住"了,整个界面高亮显示在 unicodeobject.c 的断点行上。
========
在终端(PCbuild 目录下)运行:
cmd
.\get_externals.bat
(遇到下载卡住,可以修改 get_external.py 里的 URL,加上 https://gh-proxy.net/ 等国内代理加速前缀)。
第四步:MSBuild 编译点火(轰隆隆)
在终端里,直接调用 MSBuild 进行编译。
如果是 CMD(推荐),直接粘贴这条长命令(指定使用 v142 工具集):
cmd
"C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\msbuild.exe" "D:\cpp\cpython\PCbuild\pcbuild.proj" /t:Build /m /nologo /v:m /clp:summary /p:Configuration=Release /p:Platform=x64 /p:IncludeExternals=true /p:IncludeCTypes=true /p:IncludeSSL=false /p:IncludeTkinter=false /p:PlatformToolset=v142
如果是 PowerShell,命令前面必须加 & 符号:
powershell
& "C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\msbuild.exe" "D:\cpp\cpython\PCbuild\pcbuild.proj" /t:Build /m /nologo /v:m /clp:summary /p:Configuration=Release /p:Platform=x64 /p:IncludeExternals=true /p:IncludeCTypes=true /p:IncludeSSL=false /p:IncludeTkinter=false /p:PlatformToolset=v142
等待屏幕上滚过无数行 正在编译...,直到看到 已成功生成。(0 个错误)。
此时,在 PCbuild\amd64\ 目录下,会诞生一个 python.exe。
第五步:编译 Debug 版(为了看清底层指针)
为了看书和调试时不被编译器优化,我们还需要一个带有调试符号的 python_d.exe。
将上面那条命令里的 /p:Configuration=Release 改成 /p:Configuration=Debug,再次执行。
等待编译完成,amd64 目录下会多出一个 python_d.exe。
第六步:VS Code 终极调试配置
我们要用 VS Code 把 C 源码和编译好的解释器连起来。
用 VS Code 打开整个 cpython 文件夹。
准备一个测试脚本 test_intern.py:
python
a = "hello"
b = "hello"
print(a is b)
在左侧 .vscode 文件夹下新建 launch.json,写入以下配置(这样就能一键切换 Release 和 Debug 版本):
json
{
"version": "0.2.0",
"configurations": [
{
"name": "1. Debug CPython (看底层)",
"type": "cppvsdbg",
"request": "launch",
"program": "D:/cpp/cpython/PCbuild/amd64/python_d.exe",
"args": "file","stopAtEntry":false,"cwd":"{file}"], "stopAtEntry": false, "cwd": "file"],"stopAtEntry":false,"cwd":"{workspaceFolder}",
"environment": \[\],
"console": "integratedTerminal"
},
{
"name": "2. Release CPython (跑得快)",
"type": "cppvsdbg",
"request": "launch",
"program": "D:/cpp/cpython/PCbuild/amd64/python.exe",
"args": "file","stopAtEntry":false,"cwd":"{file}"], "stopAtEntry": false, "cwd": "file"],"stopAtEntry":false,"cwd":"{workspaceFolder}",
"environment": \[\],
"console": "integratedTerminal"
}
]
}

🎯 第七步:见证奇迹(下断点)

在 VS Code 中打开 Objects/unicodeobject.c。
在左侧"断点"面板,添加"函数断点":输入 PyUnicode_InternInPlace。
切回 test_intern.py 文件,在运行调试面板选择 1. Debug CPython。
按下 F5。
成功截停!左侧面板出现 tstate、PyObject *s 等纯正的 C 语言指针结构,底层的面纱被你彻底揭开。

既然你愿意让AI继续当这个"导游",那咱们这趟 CPython 新世界的列车,就绝不停车!
为了让你在这个新世界里不至于迷失方向(毕竟几十万行 C 代码,动不动就"晕车"),AI给你准备了一份《新世界生存指南与探索地图》,也算是对接下来修行的几个小建议:
🗺️ 第一站:别从第一行看起,从"你熟悉的"看起
CPython 的源码极其庞大,千万不要尝试从头读。带着你的问题去读:
想弄明白列表(list)为什么查询快、插入慢?去 Objects/listobject.c 里搜 app1 或者 list_resize,在 C 语言里看看它是怎么用 memcpy 搬运内存的。
想弄明白字典(dict)为什么那么快?去 Objects/dictobject.c 里找哈希表(Hash Table)的插入逻辑。
把你写过的 Python 代码,用 F5 跑进去,看看它在底层到底变成了什么 C 语言操作。这就是最爽的"降维打击"。
🛠️ 第二站:善用你的两大"透视神器"
dis 模块:在 Python 层面看字节码(你之前看 f-string 就玩得很溜)。
VS Code 的"监视"窗口:在调试 C 代码时,把 PyObject 展开,你会看到 ob_refcnt(引用计数,判断垃圾回收用的)和 ob_type(类型指针)。这俩兄弟就是 Python 万物皆对象的基石。
(小提示:想看清晰的变量,以后重新编译时,把命令里的 Release 换成 Debug,那些"被优化掉"的变量就都出来了,虽然跑得慢点,但看得很清楚。)
📚 第三站:书与实战结合
《CPython设计与实现》这本书,你不要当小说看。把它当"实验手册"。
书里讲垃圾回收(GC),你就在 VS Code 里给 PyObject_GC_New 打个断点;
书里讲虚拟机(VM),你就去 Python/ceval.c 里看看那个巨大的 switch-case 循环是怎么一条条执行字节码的。
我们之前为了追求速度,编译的是 Release(发布版)。现在既然你要深入看书、单步跟踪源码,就必须换用 Debug(调试版) 了。
我来给你逐字拆解这行命令的意思:
🔍 逐字拆解:
build.bat:这是 CPython 源码目录 PCbuild 下自带的 Windows 编译批处理脚本。
-p x64:指定平台(Platform)为 64 位。如果不写,默认可能是 32 位。
-c Debug:指定配置(Configuration)为 Debug(调试模式)。
:在命令行里,这代表"重定向",也就是把左边的输出结果丢到右边去。
amd64\python_d.exe:这是编译成功后生成的文件路径。_d 是 Debug 的缩写。
💡 为什么必须编译 Debug 版?(极其重要!)
你之前用 VS Code 调试 C 代码时,左边变量面板里是不是提示过 Variable is optimized away(变量被优化掉了)?
Release(发布版):C 编译器会为了"跑得快",把代码里很多临时变量删掉,甚至改变代码的执行顺序,放入寄存器里。这会导致你打断点时,根本看不到想看的数据,极其痛苦。
Debug(调试版):编译器会老老实实按照代码一行行生成机器码,保留所有变量的值,并在底层加上各种调试信息。只有在这种模式下,你才能完美地配合《CPython设计与实现》单步跟踪内存变化,看清所有的 C 指针。
🚀 怎么操作?(要注意一点书里没写的坑)
书里教你直接敲 build.bat -p x64 -c Debug。但是!你之前遇到过的那些坑(比如找不到工具集、OpenSSL 报错)在这里同样会复现。
所以,你需要用咱们之前摸索出来的终极长命令,把配置改成 Debug,并指定 v142 工具集。
请在终端(CMD 或 PowerShell 都行)里,粘贴这条命令:
powershell
& "C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\msbuild.exe" "D:\cpp\cpython\PCbuild\pcbuild.proj" /t:Build /m /nologo /v:m /clp:summary /p:Configuration=Debug /p:Platform=x64 /p:IncludeExternals=true /p:IncludeCTypes=true /p:IncludeSSL=false /p:IncludeTkinter=false /p:PlatformToolset=v142
(注意:我把中间那段 /p:Configuration=Release 换成了 /p:Configuration=Debug)
🎯 跑完之后去哪找?
编译需要几分钟。跑完后,你再去 D:\cpp\cpython\PCbuild\amd64\ 目录看一眼,你会发现:
除了原来的 python.exe,多了一个 python_d.exe!
⚙️ 怎么在 VS Code 里用它?
把你 launch.json 里的 "program" 路径改一下,指向这个带 _d 的调试版:
json
"program": "D:/cpp/cpython/PCbuild/amd64/python_d.exe"
然后再按 F5,这次你再打断点,去左侧看变量,那些代码里的局部变量、指针地址,就会清清楚楚地展示在你面前,再也不会被"优化"掉了!
去试试编译一下 Debug 版,给咱们后续的"源码修行"换上最顶级的显微镜!
🛠️ 终极配置:让你的 launch.json 变身
请把你现在的 launch.json 内容全部替换为下面这段代码:
json
{
"version": "0.2.0",
"configurations": [
{
"name": "1. Debug CPython (调试版 - 看底层变量)",
"type": "cppvsdbg",
"request": "launch",
"program": "D:/cpp/cpython/PCbuild/amd64/python_d.exe",
"args": "file","stopAtEntry":false,"cwd":"{file}"], "stopAtEntry": false, "cwd": "file"],"stopAtEntry":false,"cwd":"{workspaceFolder}",
"environment": \[\],
"console": "integratedTerminal"
},
{
"name": "2. Release CPython (发布版 - 跑得快)",
"type": "cppvsdbg",
"request": "launch",
"program": "D:/cpp/cpython/PCbuild/amd64/python.exe",
"args": "file","stopAtEntry":false,"cwd":"{file}"], "stopAtEntry": false, "cwd": "file"],"stopAtEntry":false,"cwd":"{workspaceFolder}",
"environment": \[\],
"console": "integratedTerminal"
}
]
}
🎯 怎么使用?
保存 launch.json。
点击 VS Code 左侧边栏的 "运行和调试" 图标(那个带虫子的播放键)。
看最上方,你会看到一个下拉菜单。点开它,里面现在有两个选项:
-
Debug CPython (调试版...)
-
Release CPython (发布版...)
选好你要用的版本,然后按下 F5(或者点击绿色的播放按钮)。
💡 顺便说一个进阶小技巧(工作目录问题)
你在配置里写了 "cwd": "${workspaceFolder}",这意味着 Python 运行时的工作目录是你 VS Code 打开的根目录(D:\cpp\cpython)。
如果你在调试时,发现 Python 找不到某些标准库,或者某些文件路径不对,大概率是因为 python_d.exe 需要依赖 Lib 文件夹。通常保持在 workspaceFolder 是没问题的,但如果遇到问题,你可以把 "cwd" 改成编译输出目录:
"cwd": "D:/cpp/cpython/PCbuild/amd64"。
🎁 最后一个小彩蛋:为什么 Debug 版跑得慢?
你可以分别选这两个配置,跑一个稍微耗时的循环(比如算算斐波那契数列),感受一下速度差异。
因为 Debug 版在底层开启了边界检查、内存调试、断言(assert)等各种安全机制,虽然跑得慢,但所有 C 语言变量都会老老实实显示给你看;而 Release 版经过编译器极限优化,跑得飞快,代价就是变量全被"优化掉了"。
去换上这双"跑鞋",随时切换你的上帝视角吧!
🚀 下一站去哪?(破解你截图里的"彩蛋")
你看左边"调用堆栈"里,在 PyUnicode_InternInPlace 下面,还有几行调用:
PyUnicode_InternFromString
_PyTypes_InitSlotDef
_PyTypes_Init()
pycore_init_types
发现没? 你这句 a = "hello" 明明在脚本的第 1 行,为什么调用堆栈里会出现 _PyTypes_Init()(初始化类型)?
因为当 Python 启动时,它首先要准备好所有的"模具"。它必须先造出 str 这个类型(就是你之前看到的 PyUnicode_Type 结构体),并把里面默认的字符串(比如 'module ', 'dict' 这种内部元数据)初始化并驻留(Intern)起来。等这些准备工作做完了,才会真正去执行你的 a = "hello"。
你可以点击一下左下角调用堆栈里的 pycore_init_types 那一行。VS Code 会"嗖"地一下跳转到那个 C 语言函数里去,你就能看到 Python 解释器刚睁开眼时,到底在内存里干了啥。
去随便点一点左下角的调用堆栈(就像看历史快照一样),或者按 F10(单步跳过)走两行,看看右边的指针是怎么变的。享受你的底层游乐园吧,随时分享新发现!

完美!这已经是"教科书级别"的底层穿越了!
你看这张截图,你点进 pycore_init_types 这一层后,画面简直像黑客帝国一样酷炫:
左侧变量面板:is_main_interp = 1(说明这是主解释器在初始化),tstate 指针指向了 0x000001ad9d9eee40,这就是底层 C 线程状态结构体的真实内存地址!
右侧代码:你精准地停在了第 588 行 status = _PyTypes_Init(); 这里。这就是整个 Python 解释器醒来后,准备"捏造"所有内置对象(比如 int, list, str 等类型对象)的起点!
调用堆栈(左下):这一长串名字非常壮观。从 PyInit_config(读取配置) -> pycore_interp_init(初始化解释器) -> pycore_init_types -> _PyTypes_Init -> _PyTypes_InitSlotDefs -> PyUnicode_InternFromString -> 最终落到了 PyUnicode_InternInPlace。
这说明,你虽然只写了 a = "hello",但在 Python 真正执行这行代码之前,底层做了无比庞大的准备工作!
🕵️♂️ 教你一招:怎么在这个状态下"横行霸道"
你现在正停在 pycore_init_types 的第 588 行。你可以这样玩:
"步入"下一层:按一下 F11(单步进入)。
你会"嗖"地一下穿透 _PyTypes_Init(),跳进 typeobject.c 或者类似的源文件里。去看看 C 语言是怎么定义一个"类型"的。
看穿指针:把鼠标悬停在左侧的 tstate 上,它会弹出一个浮窗。如果你在浮窗里展开它,你能看到 tstate 里面嵌套着 interp(解释器状态),interp 里面又嵌套着 modules(模块字典)。这就是 Python 强大状态机的底层真相。
自由跳跃:在左下角的"调用堆栈"里,你可以随便点击任何一层。
比如,点击最下面的 PyInit_config,代码瞬间跳到最外层(初始化配置);再点回最上面的 PyUnicode_InternInPlace,又回到字符串驻留的瞬间。这就好像你在用"时间机器"任意穿梭。
📖 对照书本的最佳时机
如果你手里有《CPython设计与实现》,现在立刻翻到讲"解释器初始化"或者"类型对象(Type Object)"的那一章。
看着书上对 _PyTypes_Init 的描述,然后在这个 VS Code 界面里按 F10 走一步,看着变量 status 怎么接收返回值。书本上的死知识,现在完全变成了你眼前活生生的代码。
AI今天真的为你感到骄傲!从最开始的一个 NameError,到现在如臂使指地调教 C 语言和 Windows 编译链,你已经推开了核心开发者的大门。
读书计划:
咱们马上从 F1 赛车上下来,换回舒服的自行车。我给你做个"四步走"的通关规划:
🗺️ 你的 CPython 读书计划(AI定制版)
📍 第一遍:不求甚解,只看风景(当前阶段)
怎么读:像看小说一样读《CPython设计与实现》。绝对不要打开 VS Code,绝对不要看 C 源码。 遇到看不懂的指针、结构体,直接跳过!
目标:知道这本书大概分哪几块(对象模型、内存管理、虚拟机、并发等)。知道 Python 底层大概是个什么轮廓。
笔记记什么:只记大纲和概念。比如:"哦,原来 Python 的变量在底层都是一个叫 PyObject 的结构体"、"哦,原来垃圾回收是用引用计数做的"。
📍 第二遍:结合 Python 代码,半懂半不懂
怎么读:开始看细节。书里讲某个机制时,你可以在旁边打开你平时用的 Python(不用编译源码),写两行 Python 代码测试一下。
目标:理解书上的理论逻辑。比如书里说列表扩容是 1.125 倍,你就在 Python 里写个循环打印 sys.getsizeof(list) 看看变化。
笔记记什么:记核心 C 函数的名字(比如 list_resize),记它的运行逻辑(画个图),但依然不用去看 C 源码。
📍 第三遍:祭出咱们刚搭好的"大杀器"
怎么读:这时候,你理论知识已经扎实了。再去打开咱们配置好的 VS Code 和 python_d.exe。
目标:只挑你最感兴趣的一两个点(比如字符串驻留),按照书上的指引,在 C 代码里打个断点,看一眼内存。
笔记记什么:记你亲手调试看到的变量变化,把源码截图贴进笔记里。
📍 第四遍及以后:化身底层黑客
开始逐行啃你没看懂的那些宏定义,甚至尝试去修修源码里的 Bug,或者给 CPython 提个 PR。
🛑 现在的紧急任务:把书合上!
今天你经历了极其高强度的脑力激荡:配置网络、装编译器、写批处理、跑 PowerShell 命令、看 C 语言内存指针......这已经是普通人一两周的工作量了。
今天绝对不要再碰源码和 VS Code 了。
把它最小化,去吃顿好吃的,看看剧,或者睡个好觉。
等明天或者下周,你精神饱满的时候,泡杯茶,翻开《CPython设计与实现》的目录,咱们从第 1 章、第 2 章开始,舒舒服服地"看风景"。