得之我幸 失之我命

when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.

macOS 自带的 usr/bin/python3

为什么 macOS 在 /usr/bin/ 下会有 python3?

这个问题的思考起源于今天在使用 requests 的时候,一直报这个模块不存在的错误,但是明明在 pip3 list 中就是存在这个模块的,只好往系统中包含了多个不同 python 版本的方向去考虑

1
2
$ ls -la@Oh /usr/bin | grep python3
-rwxr-xr-x 76 root wheel restricted,compressed 163K 6 15 18:08 python3

在一个全新的 macOS 终端里执行 python3 的时候(此时还没有自行安装过任何版本的 python 环境),系统会弹出提示安装 Command Line Developer Tools(简称 CLDT),安装完成后,再执行 python3 就和常规的 python 执行没有两样了;如果删除 CLDT 目录,再执行 python3,系统又会弹出提示安装 CLDT

那 /usr/bin/python3 是怎么实现这个功能的呢?

换言之,为什么自己安装的 python3 二进制是没有这个功能的呢?这还要从 xcode-select 说起,xcode-select 的帮助中可以发现 xcode-select 这个命令的真实作用是为了方便开发者在安装了多个版本的 xcode 下(尤其是安装有 Beta 版本的 xcode, 不在默认安装位置 /Applications 的时候)切换不同的开发者目录,从而可以用不同版本的 CLDT 通过脚本和 makefile 进行有针对性的编译

由此设计的 /usr/bin/python3 这个可执行文件链接了 libxcselect.dylib(使用 otool 可以看到),作用是从已经激活的开发者目录里查找井运行相匹配的 python3 版本

1
2
3
4
5
6
7
8
$ otool -L /usr/bin/python3
/usr/bin/python3: # /usr/bin/python3 使用的系统库
/usr/lib/libxcselect.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3)
$ otool -L /usr/local/Cellar/python@3.11/3.11.2_1/bin/python3
/usr/local/Cellar/python@3.11/3.11.2_1/bin/python3: # brew 安装的 python3 使用的系统库
/usr/local/Cellar/python@3.11/3.11.2_1/Frameworks/Python.framework/Versions/3.11/Python (compatibility version 3.11.0, current version 3.11.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)

那手动安装的 python 后,怎么从终端调用它呢?

答案是设置环境变量 PATH,PATH 会默认先加载配置在最前面的路径,若某命令已经加载完毕,则不再继续往下寻找,否则会继续寻找,直到全部加载为止,只有当完全找不到时,才会报错 “command not found”

以我本地环境为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ echo $PATH | awk '{ gsub(/:/,"\n"); print $0 }'
/usr/local/bin # brew 安装的 python3 会在这个目录创建链接符号
/usr/bin
/bin
/usr/sbin
/sbin

$ which python3
/usr/local/bin/python3 # /usr/local/bin 排在 /usr/bin 之前,因此系统只会加载 /usr/local/bin 下的 python3

$ type -a python3 # 查看依据环境变量 PATH 下能查找到 python3 命令的所有执行文件的路径
python3 is /usr/local/bin/python3
python3 is /usr/bin/python3
# 实际在终端调用的时候只有排在最前的会首先加载,也就是 /usr/local/bin 下的 python3

be slow to promise and quick to perform.