拿到程序有两条路:现成的可执行文件或拿源码自己编;源码安装多花一道编译,换来的是能改、能换平台、能自己调。
7.3 讲的是系统的差异,这一节换到使用者的角度:程序要怎么弄到自己的机器上。
一、两条路
第一条:直接用可执行文件。 复制过去就能跑,简单但换平台就得等别人出包。 第二条:拿源代码自己编译。 多一道工序,但能改、能换平台、能针对自己的环境调优。 开源软件多半走第二条路——因为源码是公开的,编与不编由你决定。 这两条路的取舍,本质上是【省事】和【掌控】之间的选择。
二、源码安装多出来的那道工序:编译
编译做的事只有一件:把给人看的源码,翻成给机器看的代码。 但这一步往往不是一行命令:要先装编译器、装依赖库、配好参数,再等它编完。 所以源码安装最常卡住的地方不是编译本身,而是环境和依赖。 这也是它最被诟病的一点:明明只是想装个软件,却先要解决一堆前置问题。
三、Python 也有【编译】这一步
只不过程序员通常感觉不到,因为它是自动做的。 Python 把源码翻成字节码——一种给解释器看的中间产物,存在缓存文件里。 所以第二次运行同一个程序会快一点,因为字节码已经编好了。 注意这个产物不是本机代码:它换一台 CPU 照样能用,真正跟 CPU 打交道的活儿由解释器干。
四、这一节的落点
两条路的选择,可以按三句话来判断: 只想用 → 装可执行文件。 省时省事。 要用在别的平台上 → 拿源码编。 或者等别人编好。 想改、想调优、想跟进去看 → 只能走源码。 而【编译出来的产物是不是给 CPU 看的】,决定了这个程序能不能跨平台——这正是下一节的主题。
五、动手 Demo:使用源代码进行安装
拿到一个程序,两条路:用现成的可执行文件,或者拿源代码自己编。 Python 也有编译这一步,只是它的产物是字节码。
import dis
src = "total = 0" + chr(10)
src += "for i in range(1, 6):" + chr(10)
src += " total = total + i" + chr(10)
src += "print(total)" + chr(10)
code = compile(src, "<demo>", "exec")
print("指令条数", len(list(dis.get_instructions(code))))
实跑输出:
--------------------------------------------------------------------
使用源代码进行安装
--------------------------------------------------------------------
拿到一个程序,两条路:**用现成的可执行文件**,或者**拿源代码自己编。**
对比项 用可执行文件 用源代码
-------------------------------------------------------
要装什么 复制过去就能用 还得装编译器、依赖库
快不快 立刻可用 要编几分钟到几小时
换平台 要等别人出新版本 自己重新编一遍就行
能不能改 改不了 想改哪行改哪行
源码安装的核心就一步:**编译——把给人看的源码翻成给机器看的代码。**
Python 也有这一步,只不过它的产物是【字节码】,**由解释器在运行时执行。**
拿一段三行的源码走一遍:
源码字符数 67
源码行数 4(含末尾空行)
编出来 code 对象,共 24 条指令
它是给谁看的 给解释器看的中间产物,**不是本机代码**
编译出来的指令:
RESUME 0
LOAD_CONST 0
STORE_NAME total
LOAD_NAME range
PUSH_NULL
LOAD_CONST 1
LOAD_CONST 6
CALL 2
**注意最后一行:这个产物换一台 CPU 照样能跑——**
因为它交给的是【解释器】,**真正跟 CPU 打交道的活儿由解释器干。**
这正是下一页要讲的虚拟机。
67 个字符的源码编成了 24 条指令——这就是【字节码】。 它是给解释器看的中间产物,不是本机代码:换一台 CPU 照样能用。
30 秒实验
- 找一段开源的 C 程序,看看它的安装说明里第一步要装什么。
- 把同一段 Python 源码在笔记本和树莓派上各跑一次,看看字节码是不是通用的。
常见误区
- 以为源码安装只是【多一步】。它还要准备编译器、依赖库和环境。
- 以为字节码就是本机代码。它给解释器看,换 CPU 也不用改。
自测三问(点开对答案)
1. 源码安装比可执行文件多出哪一步? —— 编译——把源码翻成机器(或解释器)能执行的形式。 2. 源码安装最容易卡在哪? —— 编译器、依赖库和环境配置,而不是编译本身。 3. Python 的字节码是什么性质? —— 给解释器看的中间产物,不是本机代码,因此跨 CPU 仍然可用。- ☐ 下一节(7.5 在任何地方都能提供相同运行环境的Java虚拟机)
相关笔记
- 每种操作系统的API都是不同的 — 为什么不干脆编成本机代码
- 在任何地方都能提供相同运行环境的Java虚拟机 — 把中间产物做成统一标准
- 文件是以字节为单位记录的 — 源码本身也是字节
- ⌨️ 编程原理 · 索引 — 把编程全貌理一遍
- ⚙️ 程序是怎样跑起来的 · 索引