Ubuntu 16.04源码编译安装Python 3.7/3.8/3.9多版本共存与虚拟环境配置
2026/7/29 11:10:17 网站建设 项目流程

1. 项目概述与核心需求解析

在Linux开发环境里,尤其是像Ubuntu 16.04这样的长期支持版本,系统自带的Python版本往往比较老旧。我手头这台机器,默认还是Python 3.5。现在很多项目依赖的库,比如TensorFlow 2.x、PyTorch新版本,或者一些前沿的数据科学工具包,最低要求都是Python 3.7起步,有的甚至推荐3.8或3.9以获得更好的性能和新特性支持。直接升级系统Python版本是高风险操作,因为Ubuntu系统本身的很多组件(比如apt包管理器、桌面环境)都依赖特定的Python版本,强行替换可能导致系统崩溃。所以,最稳妥、最专业的方式,就是在系统里同时安装多个Python版本,让它们和平共处,然后根据项目需要灵活切换。这不仅仅是“装一个Python”那么简单,它涉及到源码编译、环境隔离、版本管理和工具链配置等一系列操作。今天,我就以Ubuntu 16.04为例,把从Python 3.7到3.9这几个主流版本的安装、共存管理,以及如何干净地卸载某个版本,从头到尾捋一遍,分享我这些年积累下来的实操经验和避坑指南。

2. 环境准备与依赖库安装

在开始编译安装Python之前,准备工作至关重要。很多编译失败或者后续使用中的奇怪问题,根源都出在这一步。Ubuntu 16.04的软件源比较老,我们需要先更新源列表并安装一整套编译工具和开发库。

2.1 更新系统与安装基础编译工具

首先,确保你的系统软件包列表是最新的。打开终端,执行:

sudo apt update sudo apt upgrade -y

这个操作会更新可用软件包列表并升级所有可升级的包。虽然不升级也能继续,但更新后能确保我们安装的依赖是最新的,减少潜在的兼容性问题。

接下来,安装编译Python所必需的基础工具链:

sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev

我解释一下这几个包是干什么的,以后你遇到其他软件编译问题也能举一反三:

  • build-essential: 这是编译器的元包,包含了gcc, g++, make等核心编译工具。没有它,源码编译无从谈起。
  • zlib1g-dev: 提供压缩库的开发文件,Python的zipfile模块等依赖它。
  • libncurses5-dev: 终端屏幕控制的开发库,Python的curses模块需要。
  • libgdbm-dev: GNU数据库管理器的开发文件,用于dbm模块。
  • libnss3-dev,libssl-dev: 网络安全服务相关的开发库,编译Python的ssl模块(用于pip通过HTTPS下载包)必不可少。缺少它,pip安装会报ssl错误,这是最常见的坑之一。
  • libreadline-dev: 提供命令行编辑功能,让你在Python交互式环境里可以用方向键翻看历史命令。
  • libffi-dev: 外部函数接口库,用于Python调用C代码,很多底层扩展模块依赖它。
  • libsqlite3-dev: SQLite数据库的开发文件,Python内置的sqlite3模块需要。
  • libbz2-dev: BZ2压缩库的开发文件。

注意:这里安装的都是-dev结尾的开发包,它们包含了头文件(.h)和链接库,是编译时必需的。如果只安装运行时库(如zlib1g),编译时会因为找不到头文件而失败,错误信息通常是“fatal error: xxx.h: No such file or directory”。

2.2 规划安装目录与用户权限

默认情况下,如果我们使用make altinstall(后面会详细解释),Python会被安装到/usr/local/bin/usr/local/lib目录下。/usr/local是系统级的本地安装目录,适合安装多个版本共存。我们需要确保对这个目录有写入权限,这通常需要sudo

我个人的习惯是,在/usr/local/src目录下下载和解压Python源码,因为这里本来就是放源码的惯例位置,编译完的临时文件也方便集中清理。

cd /usr/local/src sudo mkdir -p python_src cd python_src

使用sudo是因为/usr/local目录通常属于root用户。整个编译安装过程,我们大部分操作都需要在sudo下进行,除非你特意配置了/usr/local目录给当前用户写权限(不推荐,有安全风险)。

3. Python多版本编译安装实战

准备好了基础环境,我们就可以开始下载和编译Python源码了。我选择同时安装3.7.15, 3.8.18和3.9.18这三个版本,它们都是各自大版本的最终维护版本,相对最稳定。我会详细展示3.8.18的完整过程,并指出其他版本的关键差异。

3.1 下载Python源码包

我们可以从Python官网下载,但国内访问可能较慢。我通常使用华为开源镜像站,速度非常快。

# 下载 Python 3.7.15 sudo wget https://mirrors.huaweicloud.com/python/3.7.15/Python-3.7.15.tgz # 下载 Python 3.8.18 sudo wget https://mirrors.huaweicloud.com/python/3.8.18/Python-3.8.18.tgz # 下载 Python 3.9.18 sudo wget https://mirrors.huaweicloud.com/python/3.9.18/Python-3.9.18.tgz

下载完成后,分别解压:

sudo tar -xzf Python-3.7.15.tgz sudo tar -xzf Python-3.8.18.tgz sudo tar -xzf Python-3.9.18.tgz

3.2 编译与安装 Python 3.8.18

我们以Python 3.8.18为例,进入解压后的目录开始配置和编译。

cd Python-3.8.18

在编译之前,有一个非常重要的配置步骤。我们使用./configure脚本,并带上一些关键参数:

sudo ./configure --enable-optimizations --with-ensurepip=install --enable-shared

我来拆解这几个参数:

  • --enable-optimizations: 这个参数会启用PGO(Profile Guided Optimization)优化。编译过程会先构建一个基础的解释器,然后用它运行一组测试套件,收集热点代码的执行情况,再基于这些数据重新编译一次,生成性能更优的二进制文件。这会让编译时间大幅增加(可能多出30%-50%),但最终得到的Python解释器性能会有可观的提升(5%-20%)。对于生产环境或追求极致性能的开发者,我建议开启。如果你只是想快速安装测试,可以去掉这个参数。
  • --with-ensurepip=install: 确保编译安装完成后,pip包管理器也会被一并安装。这样我们就不需要手动再去安装get-pip.py了。
  • --enable-shared: 生成共享库(libpython3.8.so)。这个非常重要!如果你打算后续安装像PyInstaller这样的工具,或者某些通过ctypes调用Python的C/C++程序,它们需要链接Python的共享库。不开启这个选项,这些工具可能会报找不到libpython库的错误。这是另一个大坑,很多教程会漏掉。

配置完成后,开始编译。这里-j参数后面跟的数字表示并行编译的作业数,通常设置为你的CPU核心数,可以加快编译速度。你可以用nproc命令查看核心数。

sudo make -j$(nproc)

编译过程视机器性能而定,开启优化的情况下,可能需要10到30分钟。期间终端会输出大量编译信息,只要没有以error结尾的红色错误信息,就耐心等待。

编译成功后,进行安装。这里绝对不要使用make install!这是关键区别:

sudo make altinstall

make install会创建python3pip3这样的软链接,直接指向新安装的版本,这可能会覆盖系统原有的/usr/bin/python3链接,导致依赖系统Python3的工具(如apt)崩溃。而make altinstall则不会创建python3pip3链接,它会将可执行文件安装为python3.8pip3.8,完美实现多版本共存。

安装完成后,验证一下:

python3.8 --version pip3.8 --version

如果看到Python 3.8.18pip的版本信息,说明安装成功。pip3.8默认可能还需要升级自身,可以运行pip3.8 install --upgrade pip

3.3 编译安装 Python 3.7.15 与 3.9.18

其他版本的流程完全一致,只是目录和最终的可执行文件名不同。

# 安装 Python 3.7.15 cd ../Python-3.7.15 sudo ./configure --enable-optimizations --with-ensurepip=install --enable-shared sudo make -j$(nproc) sudo make altinstall # 安装 Python 3.9.18 cd ../Python-3.9.18 sudo ./configure --enable-optimizations --with-ensurepip=install --enable-shared sudo make -j$(nproc) sudo make altinstall

安装后,你会在/usr/local/bin目录下看到python3.7,pip3.7,python3.8,pip3.8,python3.9,pip3.9等一系列命令。它们互不干扰。

3.4 解决共享库链接问题

如果你在安装后运行python3.8时遇到类似“error while loading shared libraries: libpython3.8.so.1.0: cannot open shared object file”的错误,这是因为系统找不到我们编译的共享库。我们需要告诉系统动态链接器这个库的位置。

首先,找到库文件。它通常在/usr/local/lib目录下。

sudo find /usr/local -name "libpython3.8*.so*"

假设找到的是/usr/local/lib/libpython3.8.so.1.0。我们需要更新动态链接器的缓存:

# 将库文件所在目录添加到配置中 echo '/usr/local/lib' | sudo tee /etc/ld.so.conf.d/python3.8.conf # 更新缓存 sudo ldconfig

然后再次运行python3.8 --version,应该就正常了。对于3.7和3.9版本,如果遇到同样问题,如法炮制,创建对应的.conf文件(如python3.7.conf)并执行ldconfig即可。

4. 多版本共存管理与虚拟环境配置

现在我们有多个Python版本了,如何高效地管理和使用它们呢?直接调用python3.7python3.8是一种方式,但更专业的做法是结合虚拟环境(virtual environment)。

4.1 使用 update-alternatives 进行系统级版本管理

update-alternatives是Debian/Ubuntu系统管理多个同类型命令版本的工具。我们可以用它来设置python3pip3这两个通用命令指向哪个具体版本。

首先,为我们安装的每个版本向系统注册替代项:

# 注册 python3.7 sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.7 1 # 注册 python3.8,并设置优先级为2(数字越大,优先级越高) sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.8 2 # 注册 python3.9,优先级为3 sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.9 3

同理,注册pip3

sudo update-alternatives --install /usr/bin/pip3 pip3 /usr/local/bin/pip3.7 1 sudo update-alternatives --install /usr/bin/pip3 pip3 /usr/local/bin/pip3.8 2 sudo update-alternatives --install /usr/bin/pip3 pip3 /usr/local/bin/pip3.9 3

现在,当你运行sudo update-alternatives --config python3时,会看到一个交互菜单,让你选择/usr/bin/python3默认指向哪个版本。pip3同理。这给了你一个全局的、灵活的切换方式,而不需要修改每个项目的配置。

4.2 为不同项目创建独立的虚拟环境

系统级切换虽然方便,但不同项目可能依赖不同版本的第三方库,甚至同一个库的不同版本。直接在系统Python里安装所有包会导致依赖冲突。虚拟环境(venv)就是为每个项目创建一个独立的Python运行环境,包含独立的解释器副本和包目录。

从Python 3.3开始,标准库就内置了venv模块。创建虚拟环境时,需要指定基于哪个Python版本。

# 为项目A创建基于Python 3.7的虚拟环境 python3.7 -m venv ~/venvs/project_a_venv # 为项目B创建基于Python 3.8的虚拟环境 python3.8 -m venv ~/venvs/project_b_venv # 为项目C创建基于Python 3.9的虚拟环境 python3.9 -m venv ~/venvs/project_c_venv

创建后,激活虚拟环境:

source ~/venvs/project_b_venv/bin/activate

激活后,终端提示符通常会变化,显示环境名。此时,你运行的pythonpip命令都只在这个隔离环境内生效,安装的包也只会放在这个环境的目录下,完全不影响系统或其他项目。

退出虚拟环境使用deactivate命令。

4.3 在PyCharm等IDE中调用特定版本

以PyCharm为例,在创建或打开一个项目后:

  1. 进入File -> Settings -> Project: <项目名> -> Python Interpreter
  2. 点击右上角的齿轮图标,选择Add...
  3. 在添加解释器窗口,选择System Interpreter
  4. 在解释器路径那里,点击...,然后浏览到/usr/local/bin/python3.8(或其他你需要的版本),选中它。
  5. PyCharm会自动识别出对应的pip和包目录。如果你想使用虚拟环境,也可以在这里选择虚拟环境目录下的python可执行文件(如~/venvs/project_b_venv/bin/python)。

这样,这个项目就会固定使用你指定的Python解释器和其对应的包环境,与IDE的全局设置和其他项目完全隔离。

5. 如何安全彻底地卸载某个Python版本

有时候你可能需要卸载某个自己编译安装的Python版本,比如为了释放空间,或者那个版本出现了无法解决的问题。卸载不能简单地删除可执行文件,还要清理相关的库、头文件、包目录等。

5.1 标准的卸载流程

假设我们要卸载自己安装的Python 3.8.18。因为我们是用make altinstall安装的,所以没有覆盖系统文件,卸载相对安全。

首先,回到源码编译目录,使用make的卸载功能(如果可用):

cd /usr/local/src/python_src/Python-3.8.18 sudo make altuninstall

但是请注意make altuninstall这个目标并不总是存在,这取决于Python源码的Makefile是否提供了它。很多时候,我们需要手动删除。

5.2 手动清理安装的文件

如果make altuninstall无效或不存在,我们就需要手动定位并删除相关文件。主要涉及以下几个位置:

  1. 可执行文件与脚本:在/usr/local/bin目录下,删除所有以python3.8pip3.8开头的文件,以及可能存在的idle3.8pydoc3.8等。

    sudo rm -f /usr/local/bin/python3.8 sudo rm -f /usr/local/bin/pip3.8 sudo rm -f /usr/local/bin/python3.8-config # 使用通配符删除相关文件,操作前最好先用ls查看确认 sudo rm -f /usr/local/bin/*3.8*
  2. 库文件与头文件

    • 删除Python标准库目录:sudo rm -rf /usr/local/lib/python3.8/
    • 删除共享库文件:sudo rm -f /usr/local/lib/libpython3.8*
    • 删除头文件目录:sudo rm -rf /usr/local/include/python3.8/
  3. 包安装目录:通过pip3.8 install安装的第三方包,通常位于/usr/local/lib/python3.8/site-packages/,但上一步已经删除了整个python3.8目录,所以一般已清理。用户目录下的缓存包(~/.cache/pip)是全局共享的,可以不用删除,但如果想彻底清理,可以删除该缓存目录。

  4. 清理 update-alternatives 注册项

    sudo update-alternatives --remove python3 /usr/local/bin/python3.8 sudo update-alternatives --remove pip3 /usr/local/bin/pip3.8
  5. 清理动态链接器配置(如果之前添加过):

    sudo rm -f /etc/ld.so.conf.d/python3.8.conf sudo ldconfig

5.3 卸载时的注意事项与风险规避

手动删除文件风险较高,一个误操作可能删掉其他重要文件。我的经验是,在执行rm -rf之前,务必先使用ls命令列出要删除的内容进行确认。也可以编写一个简单的脚本来记录安装的文件,便于日后卸载。一个更安全的方法是,在编译安装时使用--prefix参数指定一个独立的安装目录,例如:

./configure --prefix=/opt/python3.8 --enable-optimizations --with-ensurepip=install --enable-shared

这样,所有文件都会安装在/opt/python3.8目录下。以后要卸载,直接删除整个/opt/python3.8目录即可,完全不影响系统其他部分。代价是你需要手动将这个目录下的bin子目录加入PATH环境变量,或者为python3.8创建软链接。

6. 常见问题排查与实战技巧实录

即便按照步骤操作,在实际环境中还是会遇到各种问题。我把这些年遇到的高频问题和解决方法整理出来,你可以当成一个速查手册。

6.1 编译安装过程中的典型错误

问题1:ModuleNotFoundError: No module named '_ctypes'或在make阶段报错提到ctypes

  • 原因:缺少libffi的开发库。虽然我们一开始安装了libffi-dev,但有时系统里存在多个版本或安装不完整。
  • 解决:重新安装并确认该包。
    sudo apt install --reinstall libffi-dev
    如果还不行,可以尝试在configure时指定libffi的路径,但这种情况在Ubuntu 16.04上较少见。

问题2:pip安装包时提示SSL: CERTIFICATE_VERIFY_FAILED

  • 原因:Python编译时没有正确链接系统的SSL库,或者系统的证书路径不对。
  • 解决:首先确保libssl-dev已安装。然后,在编译Python之前,可以尝试设置一个环境变量,让configure脚本更容易找到SSL:
    export LDFLAGS="-L/usr/lib/ssl" export CPPFLAGS="-I/usr/include/openssl"
    执行完这两条命令后,再运行./configure ...和后续的make。如果问题依旧,可以尝试更新系统的CA证书:sudo apt install --reinstall ca-certificates

问题3:使用python3.8命令时报错Illegal instruction (core dumped)

  • 原因:这通常是因为编译时启用了针对特定CPU指令集(如AVX)的优化,但你的老CPU不支持。在虚拟机或某些云服务器上可能遇到。
  • 解决:最根本的方法是重新编译,并在configure不添加--enable-optimizations参数。这个参数进行的PGO优化有时会产生与特定硬件过于绑定的代码。去掉它后,虽然性能有微小损失,但兼容性最好。

6.2 多版本环境下的 pip 与包管理技巧

技巧1:明确指定 pip 版本安装包。当系统有多个pip时,一定要用完整命令指定版本,避免装错地方。

# 为 Python 3.8 安装 numpy pip3.8 install numpy # 为 Python 3.9 安装 pandas pip3.9 install pandas

技巧2:使用虚拟环境是终极解决方案。对于任何正式项目,我的第一条建议都是:“先创建一个虚拟环境”。这能一劳永逸地解决版本冲突问题。激活虚拟环境后,你只需要用pip install,它会自动关联到当前环境的Python版本。

技巧3:升级 pip 自身。新安装的Python,其自带的pip版本可能较旧。首先升级它,可以避免很多后续安装包的兼容性问题。

python3.8 -m pip install --upgrade pip

注意,有时直接运行pip3.8 install --upgrade pip可能会因为路径问题失败,使用python3.8 -m pip的方式更稳妥。

6.3 与系统组件冲突的预防与修复

预防:永远不要动/usr/bin/python3Ubuntu 16.04的aptgnome-terminal等系统工具依赖/usr/bin/python3(通常是Python 3.5)。一旦你将它指向3.8或3.9,系统更新或某些图形界面操作就可能崩溃。这也是我们坚持使用make altinstallupdate-alternatives的原因,它们都不会去动这个关键链接。

修复:如果不小心破坏了系统Python链接。如果/usr/bin/python3被错误修改,导致apt无法使用,可以通过以下命令强制恢复:

sudo rm /usr/bin/python3 sudo ln -s /usr/bin/python3.5 /usr/bin/python3

这里假设系统自带的Python 3.5可执行文件路径是/usr/bin/python3.5。执行后,系统的包管理功能应该会恢复正常。

7. 进阶应用:PyInstaller打包与版本选择

很多开发者安装新版本Python是为了使用像PyInstaller这样的打包工具的新特性。这里简单提一下PyInstaller与Python版本的关联。

从Python 3.8开始,到3.9、3.10,每个版本在打包方面都有一些细微变化。例如,某些库的依赖查找方式、二进制兼容性等。如果你用PyInstaller打包程序,并且目标用户环境多样,我建议选择Python 3.8或3.9的长期支持版本,它们的兼容性和社区支持都比较好。

在虚拟环境中安装PyInstaller:

# 激活你的项目虚拟环境 source ~/venvs/my_project_venv/bin/activate # 安装 pyinstaller pip install pyinstaller

打包时,PyInstaller会自动使用当前虚拟环境中的Python解释器和所有已安装的包。这样能确保打包出来的可执行文件,其运行环境与你开发测试的环境完全一致,避免出现“在我机器上好好的,到别人那就不行”的问题。

关于网络热词中提到的“防反编译”,这通常不是PyInstaller或Python版本本身直接提供的功能,而是通过代码混淆、加密或使用Cython编译成二进制扩展等方式实现。选择较新的Python版本(如3.9)可能在这些第三方工具链上有更好的支持,但核心还是在于你采用的代码保护方案。

整个流程走下来,从系统准备、编译参数选择、多版本管理到虚拟环境使用和问题排查,每一个环节都有需要注意的细节。在Ubuntu 16.04上管理多版本Python,核心思想就是“隔离”与“明确”:通过altinstall隔离系统环境,通过虚拟环境隔离项目依赖,通过带版本号的命令(python3.8pip3.8)明确每一次操作的对象。按照这个思路操作,你就能在稳定的系统基础上,构建一个灵活且强大的Python开发环境。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询