# Python 3.12 编译安装脚本
# 使用清华源加速 pip
# 特性:自动检测并优先使用同目录的源码包(支持 .tgz 或 .tar.xz 格式)
set -e # 遇到错误立即退出
echo "========================================"
echo " Python 3.12 编译安装脚本"
echo " pip 使用清华源"
echo "========================================"
# 检查是否为 root 用户
if [ "$EUID" -ne 0 ]; then
echo "请使用 root 权限运行此脚本 (sudo ./install_python312.sh)"
exit 1
fi
PYTHON_VERSION="3.12.13"
INSTALL_PREFIX="/usr/local"
SRC_DIR="/usr/local/src"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # 获取脚本所在目录
echo ""
echo "[1/7] 安装编译依赖..."
if command -v apt-get &> /dev/null; then
# Debian/Ubuntu
apt-get update
apt-get install -y build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev git
elif command -v dnf &> /dev/null; then
# RHEL 8+/CentOS 8+/Rocky Linux/AlmaLinux (使用 dnf)
echo "检测到 DNF 包管理器 (RHEL/CentOS 8+)..."
# 尝试启用 CRB 仓库 (CodeReady Builder)
if ! dnf repolist | grep -q "crb"; then
echo "启用 CRB 仓库以获取 xmlsec1-devel..."
dnf install -y yum-utils || true
dnf config-manager --set-enabled crb || true
# 备选方案:尝试使用 subscription-manager (RHEL) 或直接安装 epel
subscription-manager repos --enable codeready-builder-for-rhel-9-x86_64-rpms 2>/dev/null || true
fi
dnf groupinstall -y "Development Tools"
dnf install -y openssl-devel bzip2-devel libffi-devel zlib-devel readline-devel sqlite-devel wget curl xz-devel tk-devel libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel libxslt-devel || {
echo "警告: 部分包安装失败,尝试继续..."
}
elif command -v yum &> /dev/null; then
# CentOS 7/RHEL 7 (使用 yum)
echo "检测到 YUM 包管理器..."
# 尝试启用 CRB/CodeReady Builder 仓库
if yum repolist | grep -q "extras"; then
yum install -y yum-utils
yum-config-manager --enable crb 2>/dev/null || true
fi
yum groupinstall -y "Development Tools"
yum install -y openssl-devel bzip2-devel libffi-devel zlib-devel readline-devel sqlite-devel wget curl xz-devel tk-devel libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel libxslt-devel || {
echo "警告: 部分包安装失败,尝试继续..."
}
else
echo "不支持的包管理器,请手动安装编译依赖"
exit 1
fi
echo ""
echo "[2/7] 准备 Python ${PYTHON_VERSION} 源码..."
# 定义可能的本地源码包文件名
TARBALL_TGZ="Python-${PYTHON_VERSION}.tgz"
TARBALL_XZ="Python-${PYTHON_VERSION}.tar.xz"
LOCAL_TGZ="${SCRIPT_DIR}/${TARBALL_TGZ}"
LOCAL_XZ="${SCRIPT_DIR}/${TARBALL_XZ}"
# 检查脚本同目录是否有源码包(优先使用 .tar.xz,其次 .tgz)
if [ -f "${LOCAL_XZ}" ]; then
echo "✓ 在脚本同目录发现源码包: ${LOCAL_XZ}"
echo " 将使用该本地文件,跳过下载"
SOURCE_TARBALL="${TARBALL_XZ}"
mkdir -p ${SRC_DIR}
cp "${LOCAL_XZ}" ${SRC_DIR}/
USE_LOCAL=true
elif [ -f "${LOCAL_TGZ}" ]; then
echo "✓ 在脚本同目录发现源码包: ${LOCAL_TGZ}"
echo " 将使用该本地文件,跳过下载"
SOURCE_TARBALL="${TARBALL_TGZ}"
mkdir -p ${SRC_DIR}
cp "${LOCAL_TGZ}" ${SRC_DIR}/
USE_LOCAL=true
else
echo " 本地未找到源码包,将从官网下载 .tar.xz 版本..."
SOURCE_TARBALL="${TARBALL_XZ}"
mkdir -p ${SRC_DIR}
cd ${SRC_DIR}
wget https://www.python.org/ftp/python/${PYTHON_VERSION}/${SOURCE_TARBALL}
USE_LOCAL=false
fi
cd ${SRC_DIR}
echo ""
echo "[3/7] 解压源码..."
if [ -d "Python-${PYTHON_VERSION}" ]; then
echo " 检测到已解压的源码目录,将重新使用"
rm -rf Python-${PYTHON_VERSION}
fi
# 根据文件扩展名选择解压方式
if [[ "${SOURCE_TARBALL}" == *.tar.xz ]]; then
tar -xf ${SOURCE_TARBALL}
else
tar -xzf ${SOURCE_TARBALL}
fi
cd Python-${PYTHON_VERSION}
echo ""
echo "[4/7] 配置编译选项..."
./configure --prefix=${INSTALL_PREFIX} --enable-optimizations --with-ensurepip=install --enable-shared --with-system-ffi --enable-loadable-sqlite-extensions
echo ""
echo "[5/7] 编译 (这可能需要几分钟)..."
make -j$(nproc)
echo ""
echo "[6/7] 安装 Python..."
make altinstall
echo ""
echo "[7/7] 配置环境..."
# 配置动态链接库路径
echo "配置动态链接库..."
# 方法1: 创建 ldconfig 配置文件
echo "${INSTALL_PREFIX}/lib" > /etc/ld.so.conf.d/python3.12.conf
# 方法2: 更新动态链接库缓存
ldconfig
# 验证库文件是否存在
if [ -f "${INSTALL_PREFIX}/lib/libpython3.12.so.1.0" ]; then
echo "✓ 库文件已安装: ${INSTALL_PREFIX}/lib/libpython3.12.so.1.0"
else
echo "警告: 未找到 libpython3.12.so.1.0"
fi
# 方法3: 创建软链接到系统库目录(备选方案)
if [ -d "/usr/lib64" ] && [ ! -f "/usr/lib64/libpython3.12.so.1.0" ]; then
ln -sf ${INSTALL_PREFIX}/lib/libpython3.12.so.1.0 /usr/lib64/libpython3.12.so.1.0 2>/dev/null || true
ln -sf ${INSTALL_PREFIX}/lib/libpython3.12.so /usr/lib64/libpython3.12.so 2>/dev/null || true
ldconfig
fi
# 配置 pip 使用清华源
PIP_CONFIG_DIR="/etc/pip"
mkdir -p ${PIP_CONFIG_DIR}
cat > ${PIP_CONFIG_DIR}/pip.conf << 'EOF'
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
trusted-host = pypi.tuna.tsinghua.edu.cn
[install]
use-mirrors = true
mirrors = https://pypi.tuna.tsinghua.edu.cn
EOF
# 为当前用户也配置 pip
if [ -n "$SUDO_USER" ]; then
USER_HOME=$(eval echo ~$SUDO_USER)
USER_PIP_DIR="${USER_HOME}/.config/pip"
mkdir -p ${USER_PIP_DIR}
cp ${PIP_CONFIG_DIR}/pip.conf ${USER_PIP_DIR}/pip.conf
chown -R $SUDO_USER:$SUDO_USER ${USER_PIP_DIR}
fi
echo ""
echo "========================================"
echo " 安装完成!"
echo "========================================"
echo ""
# 测试 Python 是否能正常运行
if ${INSTALL_PREFIX}/bin/python3.12 --version &>/dev/null; then
echo "Python 版本:"
${INSTALL_PREFIX}/bin/python3.12 --version
else
echo "⚠️ Python 运行测试失败,尝试修复..."
export LD_LIBRARY_PATH=${INSTALL_PREFIX}/lib:$LD_LIBRARY_PATH
echo "临时设置 LD_LIBRARY_PATH=${INSTALL_PREFIX}/lib"
${INSTALL_PREFIX}/bin/python3.12 --version || true
fi
echo ""
echo "pip 版本:"
${INSTALL_PREFIX}/bin/pip3.12 --version || true
echo ""
echo "pip 配置 (清华源):"
${INSTALL_PREFIX}/bin/pip3.12 config list 2>/dev/null || true
echo ""
echo "使用说明:"
echo " - Python 路径: ${INSTALL_PREFIX}/bin/python3.12"
echo " - pip 路径: ${INSTALL_PREFIX}/bin/pip3.12"
echo ""
echo "添加到 PATH (可选):"
echo ' export PATH="${INSTALL_PREFIX}/bin:$PATH"'
echo ""
echo "如果运行时提示找不到库,请执行:"
echo " export LD_LIBRARY_PATH=${INSTALL_PREFIX}/lib:\$LD_LIBRARY_PATH"
echo ""
echo "卸载方法:"
echo " cd ${SRC_DIR}/Python-${PYTHON_VERSION} && make uninstall"
echo "========================================"