软连接

这个可以在 /usr/bin 目录中找到:

(base) jetson@ubuntu:~$ cd /usr/bin/
(base) jetson@ubuntu:/usr/bin$ ls python*
python   python2.7         python2-config  python3.8         python3.8-coverage  python3-config    python3-futurize    python-argcomplete-check-easy-install-script3
python2  python2.7-config  python3         python3.8-config  python3.9           python3-coverage  python3-pasteurize  python-argcomplete-tcsh3

其中的 python 和 python3 都可能是软连接,具体链接到哪里可以用下述命令查看:

(base) jetson@ubuntu:/usr/bin$ ls -l python
lrwxrwxrwx 1 root root 7 Apr 15  2020 python -> python3

(base) jetson@ubuntu:/usr/bin$ ls -l python3
lrwxrwxrwx 1 root root 9 Mar 13  2020 python3 -> python3.8

同时,也可以使用 which python 命令查看当前 shell 中实际解析到的 Python 路径:

(base) jetson@ubuntu:~$ which python
/home/jetson/anaconda3/bin/python

可以看到我的系统中,默认 Python 是 Anaconda 的。虽然 conda 的虚拟环境可以为不同类型的项目提供诸多便利,但是有些时候也会导致 C++ 代码编译出现问题。

下面先用软连接方式把 /usr/bin 目录的 Python 修改为 python2。之所以这样操作,不是说一定要这样,只是记录一下操作流程:

(base) jetson@ubuntu:/usr/bin$ sudo rm python
(base) jetson@ubuntu:/usr/bin$ sudo ln -s python2 python
(base) jetson@ubuntu:/usr/bin$ ls -l python
lrwxrwxrwx 1 root root 7 Aug  8 11:14 python -> python2

其中,ln -s 的基本格式为:

ln -s [源文件或目录] [符号链接名]

完事。


update-alternatives

如果想要修改系统的 Python,并实现相对方便的多版本管理,可以使用 update-alternatives 命令:

update-alternatives --install <链接名称> <名称> <路径> <优先级>

然后我们试一下,使用 update-alternatives --config python 即可切换 Python 命令对应的版本:

(base) jetson@ubuntu:~$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
update-alternatives: using /usr/bin/python2.7 to provide /usr/bin/python (python) in auto mode

(base) jetson@ubuntu:~$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2
update-alternatives: using /usr/bin/python3.8 to provide /usr/bin/python (python) in auto mode

(base) jetson@ubuntu:~$ sudo update-alternatives --config python
There are 2 choices for the alternative python (providing /usr/bin/python).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.8   2         auto mode
  1            /usr/bin/python2.7   1         manual mode
  2            /usr/bin/python3.8   2         manual mode

Press <enter> to keep the current choice[*], or type selection number: 2

这里配置的是 /usr/bin/python 这个 alternative,不会自动改变 /usr/bin/python3。也就是说,切换完成后,变化的是 Python 命令对应的解释器,而 python3 仍然会按照当前 $PATH、软链接或其他 alternatives 配置去解析。

我们检查一下:

(base) jetson@ubuntu:~$ which python
/home/jetson/anaconda3/bin/python

(base) jetson@ubuntu:~$ which python3
/home/jetson/anaconda3/bin/python3

怎么没改过来……emmm,忘了当前还在 conda 的 base 环境里。

可以使用下面这条命令,不让 Terminal 自动打开 base 环境:

conda config --set auto_activate_base false

但是这条命令只是不自动进入 base 环境,不会删除你手动写入 .bashrc 的 $PATH,也不会退出当前已经激活的环境。你可能还需要重新打开 shell,或者先执行:

conda deactivate

再看看:

jetson@ubuntu:~$ which python
/home/jetson/anaconda3/envs/py37/bin/python

jetson@ubuntu:~$ which python3
/home/jetson/anaconda3/envs/py37/bin/python3

黑人问号.webp

发生甚么事了,我们打开 .bashrc 看看,发现里面有如下内容:

export PATH=/home/jetson/anaconda3/envs/py37/bin/:$PATH
export MVCAM_SDK_PATH=/opt/MVS
export MVCAM_COMMON_RUNENV=/opt/MVS/lib
export MVCAM_GENICAM_CLPROTOCOL=/opt/MVS/lib/CLProtocol
export ALLUSERSPROFILE=/opt/MVS/MVFG
# export LD_LIBRARY_PATH=/opt/MVS/lib/aarch64:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=/home/jetson/libmodbus/install/lib/pkgconfig:$PKG_CONFIG_PATH

# HKVision ARM64 SDK LIB PATH
export LD_LIBRARY_PATH=/home/jetson/libHKVision:$LD_LIBRARY_PATH

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/home/jetson/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/home/jetson/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/home/jetson/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/home/jetson/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

看第一行!谁给我加的!不会是我吧。。。

第一行的内容把 conda 环境路径手动放到了 $PATH 最前面,所以 which pythonwhich python3 仍然会优先找到 /home/jetson/anaconda3/envs/py37/bin/ 里的解释器,而不是 /usr/bin 里的解释器。

把第一行注释掉,然后 source 一下:

source ~/.bashrc

再检查:

jetson@ubuntu:~$ which python
/usr/bin/python

jetson@ubuntu:~$ which python3
/usr/bin/python3

如果出现 which python3 -> /usr/bin/python 这种结果,那就说明环境里还有别的配置在影响解析结果。前面的 update-alternatives 命令只配置了 /usr/bin/python,并没有配置 /usr/bin/python3。这种情况下,可以继续检查 /usr/bin/python3 软链接、shell alias、shell hash,或者 PATH 中是否还有其他路径优先。

所以,这部分的结论是:如果已经关闭了默认打开 base 环境,并且 .bashrc 里没有手动把某个 conda 环境路径放到 PATH 最前面,那么运行 update-alternatives --installupdate-alternatives --config python 后,就可以切换 /usr/bin/python。后面需要修改 .bashrc 文件,纯粹是我个人环境的问题。

回头看,如果只是某个项目需要特定 Python 版本,用 venv、conda 环境、脚本 shebang,或者在 CMake / 编译命令中显式指定 Python 解释器,会比全局修改系统 Python 更省心。