Windows 环境下硬核编译 CPython 避坑指南

这段经历太宝贵了,以后无论你换电脑,还是有朋友想学,照着这份流程走,绝对能省下几天几夜的时间。

咱们把时间线拉回起点,我为你整理了一份从零开始、极其详细的安装与配置全流程:

🚀 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"

}

]

}

🎯 重新操作步骤:

  1. 保存 launch.json。
  2. 关掉刚才弹出的那个黑色控制台窗口。
  3. 确保你在 VS Code 里点开了 Objects/unicodeobject.c,并在里面打好了红点。
  4. 在资源管理器里点开 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 左侧边栏的 "运行和调试" 图标(那个带虫子的播放键)。

看最上方,你会看到一个下拉菜单。点开它,里面现在有两个选项:

  1. Debug CPython (调试版...)

  2. 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 章开始,舒舒服服地"看风景"。

相关推荐
成成爱质评4 小时前
Windows 任务计划程序 + 唤醒定时器:让电脑按时开机干活
windows·单片机·电脑
禁默4 小时前
iPhone远程控制Windows电脑哪款好?四款工具实测横评
windows·电脑·iphone
Sakura_j_h_13 小时前
Python 在定时任务里输出 emoji,UnicodeEncodeError 从哪来
开发语言·字符编码·windows·python·定时任务
隔窗听雨眠16 小时前
PostgreSQL单表从Windows迁移到Linux:差异剖析、方案对比与全流程实战
linux·windows·postgresql
Helix25019 小时前
Ansible混合环境自动化:Windows与Linux统一配置管理实战
windows·自动化·ansible·playbook·配置管理·winrm·混合环境
Java开发追求者20 小时前
windows快速安装docker
windows·docker·安装·1024程序员节
Helix2501 天前
Windows ETW与KQL实战:终端性能诊断与遥测数据分析指南
windows·性能诊断·kql·etw·azure monitor·遥测数据·tracert
陈葛杰1 天前
Adobe Premiere Pro2025安装教程
windows·adobe·开源软件·1024程序员节
承渊政道1 天前
iOS远程控制电脑用什么好?iPhoneiPad远程控制Windows电脑最佳方案2026横评
windows·ios·远程控制·1024程序员节·iphone ipad