踩坑 5090 编译构建 Paddle 源码
本文记录一次在 RTX 5090 服务器上离线编译 Paddle 源码的完整过程,包括从 CUDA 12.8 Docker 编译镜像构建、本机准备 Paddle 源码和依赖、迁移到无网络 5090 服务器、CMake 配置、Ninja 编译、wheel 打包,到最终验证的全流程。
文档中涉及的路径、服务器地址、用户名等信息均已脱敏,实际执行时请替换为自己的环境。
1. 背景
目标是在一台无网络的 RTX 5090 服务器上编译 Paddle 源码,产出支持 5090 的 Paddle Python wheel 包。
服务器环境大致如下:
text
GPU: NVIDIA GeForce RTX 5090 x 4
Driver: 570.x
Host CUDA Runtime: 12.8
Network: 离线,无外网
Docker: 已安装
NVIDIA Container Toolkit: 已安装
本机 PC 环境:
text
Network: 有外网
Docker: 已安装
Workspace: <LOCAL_WORKSPACE>/paddle
Paddle source: <LOCAL_WORKSPACE>/paddle/Paddle
5090 服务器环境:
text
SSH: <USER>@<SERVER_IP>
Workspace: <REMOTE_WORKSPACE>
Paddle source: <REMOTE_WORKSPACE>/Paddle
2. 为什么不能直接用 CUDA 12.6 镜像
一开始服务器上已有一个 paddle:cu126 镜像,看起来像是 Paddle 的 CUDA 12.6 环境。但实际检查后发现它不适合 RTX 5090。
进入容器检查:
bash
docker run --rm -it --gpus all paddle:cu126 bash
容器内执行:
bash
nvcc --version
nvcc --list-gpu-arch
结果显示 CUDA 12.6 的 nvcc 只支持到:
text
compute_90
没有:
text
compute_120
sm_120
再测试:
bash
cat >/tmp/arch.cu <<'CU'
#include <stdio.h>
__global__ void k(){}
int main(){k<<<1,1>>>(); cudaDeviceSynchronize(); printf("ok\n"); return 0;}
CU
nvcc -arch=sm_120 /tmp/arch.cu -o /tmp/arch_sm120.out
报错:
text
nvcc fatal: Value 'sm_120' is not defined for option 'gpu-architecture'
镜像里已有的 Paddle wheel 也无法在 5090 上运行,报错类似:
text
Mismatched GPU Architecture:
The installed PaddlePaddle package was compiled for 61 70 75 80 86 89 90,
but your current GPU is 120
FatalError: Unsupported GPU architecture
结论:RTX 5090 需要 CUDA 12.8 或更高版本的编译工具链,CUDA 12.6 不适合作为最终编译环境。
3. 构建 CUDA 12.8 Paddle 编译镜像
本机 PC 先拉取 CUDA 12.8 devel 镜像:
bash
docker pull nvidia/cuda:12.8.0-cudnn-devel-ubuntu22.04
如果拉取较慢,可以配置 Docker 镜像加速或使用 NVIDIA NGC 源。拉取成功后,以它为基础构建 Paddle 编译镜像。
3.1 Dockerfile
在本机创建目录:
bash
mkdir -p <LOCAL_WORKSPACE>/paddle
cd <LOCAL_WORKSPACE>/paddle
创建 Dockerfile:
dockerfile
FROM nvidia/cuda:12.8.0-cudnn-devel-ubuntu22.04
ARG DEBIAN_FRONTEND=noninteractive
ARG APT_MIRROR=mirrors.aliyun.com
ARG PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
ARG PIP_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn
ENV TZ=Asia/Shanghai \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
PYTHONUNBUFFERED=1 \
PIP_INDEX_URL=${PIP_INDEX_URL} \
PIP_TRUSTED_HOST=${PIP_TRUSTED_HOST} \
PIP_NO_CACHE_DIR=1 \
CUDA_HOME=/usr/local/cuda \
PATH=/usr/local/cuda/bin:${PATH} \
LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH}
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN set -eux; \
cp /etc/apt/sources.list /etc/apt/sources.list.bak; \
sed -i "s@http://archive.ubuntu.com/ubuntu/@http://${APT_MIRROR}/ubuntu/@g" /etc/apt/sources.list; \
sed -i "s@http://security.ubuntu.com/ubuntu/@http://${APT_MIRROR}/ubuntu/@g" /etc/apt/sources.list; \
apt-get update; \
apt-get install -y --no-install-recommends \
build-essential \
gcc \
g++ \
make \
ninja-build \
cmake \
git \
wget \
curl \
ca-certificates \
pkg-config \
libssl-dev \
openssl \
patchelf \
ccache \
swig \
unzip \
tar \
gzip \
zstd \
file \
sudo \
vim \
less \
openssh-client \
python3 \
python3-dev \
python3-pip \
python3-venv \
python-is-python3; \
rm -rf /var/lib/apt/lists/*
RUN set -eux; \
python -m pip config set global.index-url "${PIP_INDEX_URL}"; \
python -m pip config set global.trusted-host "${PIP_TRUSTED_HOST}"; \
python -m pip install --upgrade pip setuptools wheel; \
python -m pip install \
numpy \
Cython \
pybind11 \
protobuf \
requests \
six \
decorator \
typing_extensions \
packaging \
pyyaml \
certifi \
urllib3 \
opt_einsum==3.3.0 \
networkx \
httpx \
Pillow \
safetensors \
astor \
gast \
cloudpickle \
psutil \
jinja2 \
pybind11_stubgen
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends libnccl2 libnccl-dev || true; \
rm -rf /var/lib/apt/lists/*
RUN set -eux; \
mkdir -p /workspace /root/.cache /root/.ccache; \
ccache --set-config=max_size=20G || true
WORKDIR /workspace
CMD ["/bin/bash"]
这里踩过的坑主要有三个:
- 缺
jinja2会导致 CINN 相关代码生成失败。 - 缺
httpx会导致python setup.py bdist_wheel打包失败。 - 缺
libssl-dev会导致链接阶段找不到-lssl和-lcrypto。
3.2 构建镜像
使用清华 apt 源构建:
bash
cd <LOCAL_WORKSPACE>/paddle
docker build \
--build-arg APT_MIRROR=mirrors.tuna.tsinghua.edu.cn \
-t paddle-build:cuda12.8-cudnn-devel-ubuntu22.04 .
3.3 验证镜像工具链
bash
docker run --rm -it paddle-build:cuda12.8-cudnn-devel-ubuntu22.04 bash -lc '
nvcc --version
gcc --version | head -1
g++ --version | head -1
cmake --version | head -1
ninja --version
python --version
pip --version
git --version
patchelf --version
swig -version | head -2
ccache --version | head -1
'
3.4 验证 sm_120 编译支持
bash
docker run --rm -it paddle-build:cuda12.8-cudnn-devel-ubuntu22.04 bash -lc '
set -e
cat >/tmp/arch.cu << "CU"
#include <stdio.h>
__global__ void k(){}
int main(){k<<<1,1>>>(); cudaDeviceSynchronize(); printf("ok\n"); return 0;}
CU
nvcc -arch=sm_120 /tmp/arch.cu -o /tmp/arch_sm120.out
echo "compile sm_120 ok"
'
只要能看到:
text
compile sm_120 ok
说明镜像里的 CUDA 12.8 编译器支持 RTX 5090 架构。
4. 拉取 Paddle 源码和 submodule
本机 PC 执行:
bash
cd <LOCAL_WORKSPACE>/paddle
git clone https://github.com/PaddlePaddle/Paddle.git
cd Paddle
选择分支,例如:
bash
git checkout develop
初始化 submodule:
bash
git submodule sync --recursive
git submodule update --init --recursive --jobs 8
检查:
bash
git submodule status --recursive | grep '^-' && echo "submodule missing" || echo "submodule ok"
如果输出:
text
submodule ok
说明 submodule 完整。
5. 进入本机 Paddle 编译容器
创建进入容器脚本,例如 paddle.sh:
bash
#!/usr/bin/env bash
set -euo pipefail
IMAGE="${IMAGE:-paddle-build:cuda12.8-cudnn-devel-ubuntu22.04}"
PADDLE_DIR="${PADDLE_DIR:-<LOCAL_WORKSPACE>/paddle/Paddle}"
CACHE_DIR="${CACHE_DIR:-<LOCAL_WORKSPACE>/paddle/cache}"
CCACHE_DIR="${CCACHE_DIR:-<LOCAL_WORKSPACE>/paddle/ccache}"
CONTAINER_NAME="${CONTAINER_NAME:-paddle-cu128-build}"
if [ ! -d "${PADDLE_DIR}" ]; then
echo "Paddle source directory not found: ${PADDLE_DIR}" >&2
exit 1
fi
mkdir -p "${CACHE_DIR}" "${CCACHE_DIR}"
if docker ps --format '{{.Names}}' | grep -qx "${CONTAINER_NAME}"; then
exec docker exec -it "${CONTAINER_NAME}" bash
fi
if docker ps -a --format '{{.Names}}' | grep -qx "${CONTAINER_NAME}"; then
docker rm "${CONTAINER_NAME}" >/dev/null
fi
GPU_ARGS=()
if command -v nvidia-smi >/dev/null 2>&1; then
GPU_ARGS=(--gpus all)
fi
exec docker run -it \
--name "${CONTAINER_NAME}" \
"${GPU_ARGS[@]}" \
--shm-size=64g \
-v "${PADDLE_DIR}:/workspace/Paddle" \
-v "${CACHE_DIR}:/root/.cache" \
-v "${CCACHE_DIR}:/root/.ccache" \
-w /workspace/Paddle \
"${IMAGE}" \
bash -lc 'git config --global --add safe.directory "*"; exec bash'
加执行权限:
bash
chmod +x <LOCAL_WORKSPACE>/paddle/paddle.sh
进入容器:
bash
cd <LOCAL_WORKSPACE>/paddle
./paddle.sh
6. 本机 CMake 配置
进入容器后:
bash
cd /workspace/Paddle
mkdir -p build
cd build
执行 CMake:
bash
cmake .. \
-GNinja \
-DPYTHON_EXECUTABLE=$(which python) \
-DWITH_GPU=ON \
-DWITH_TESTING=OFF \
-DWITH_DISTRIBUTE=ON \
-DWITH_MKL=ON \
-DWITH_ONEDNN=ON \
-DWITH_PYTHON=ON \
-DCMAKE_BUILD_TYPE=Release \
-DPY_VERSION=3.10 \
-DWITH_CINN=ON \
-DCUDA_ARCH_NAME=Manual \
-DCUDA_ARCH_BIN="12.0" \
-DWITH_XPU=OFF \
-DWITH_ROCM=OFF
成功时应看到类似:
text
-- CUDA detected: 12.8.61
-- NVCC_FLAGS_EXTRA: -gencode arch=compute_120,code=sm_120 -Xfatbin -compress-all
-- Configuring done
-- Generating done
本机不需要是 5090。只要 nvcc 支持 sm_120,就可以生成面向 5090 的编译配置。
7. 本机编译或只准备缓存
如果本机资源足够,可以先编译:
bash
cd /workspace/Paddle/build
ninja paddle_python -j8
如果本机不是 5090,也可以编译,因为这里是用 CUDA 12.8 交叉编译 sm_120。但是最终 GPU 运行验证必须在 5090 服务器上完成。
如果本机只是为了给离线服务器准备 third_party 缓存,那么 CMake 成功后也可以直接进入迁移阶段。
8. 迁移到 5090 服务器
8.1 保存 Docker 镜像
本机 PC 执行:
bash
cd <LOCAL_WORKSPACE>/paddle
docker save paddle-build:cuda12.8-cudnn-devel-ubuntu22.04 \
-o paddle-build-cuda12.8-cudnn-devel-ubuntu22.04.tar
zstd -T0 -f paddle-build-cuda12.8-cudnn-devel-ubuntu22.04.tar
生成:
text
paddle-build-cuda12.8-cudnn-devel-ubuntu22.04.tar.zst
8.2 打包源码和缓存
bash
cd <LOCAL_WORKSPACE>/paddle
tar --numeric-owner -I 'zstd -T0' -cf Paddle-source-with-build.tar.zst Paddle
tar --numeric-owner -I 'zstd -T0' -cf paddle-cache.tar.zst cache
tar --numeric-owner -I 'zstd -T0' -cf paddle-ccache.tar.zst ccache
建议保留:
text
Paddle/.git
Paddle/third_party
Paddle/build
因为 5090 服务器无网,保留这些内容能减少 third_party 下载失败的概率。
8.3 传输文件
bash
cd <LOCAL_WORKSPACE>/paddle
rsync -avP paddle-build-cuda12.8-cudnn-devel-ubuntu22.04.tar.zst \
<USER>@<SERVER_IP>:<REMOTE_WORKSPACE>/
rsync -avP Paddle-source-with-build.tar.zst \
<USER>@<SERVER_IP>:<REMOTE_WORKSPACE>/
rsync -avP paddle-cache.tar.zst \
<USER>@<SERVER_IP>:<REMOTE_WORKSPACE>/
rsync -avP paddle-ccache.tar.zst \
<USER>@<SERVER_IP>:<REMOTE_WORKSPACE>/
如果传输大文件不稳定,可以使用 rsync -avP --partial --inplace。
9. 5090 服务器解压和导入
登录服务器:
bash
ssh <USER>@<SERVER_IP>
进入工作目录:
bash
cd <REMOTE_WORKSPACE>
导入镜像:
bash
zstd -d -f paddle-build-cuda12.8-cudnn-devel-ubuntu22.04.tar.zst
docker load -i paddle-build-cuda12.8-cudnn-devel-ubuntu22.04.tar
解压源码和缓存:
bash
tar -I zstd -xf Paddle-source-with-build.tar.zst
tar -I zstd -xf paddle-cache.tar.zst
tar -I zstd -xf paddle-ccache.tar.zst
如果遇到:
text
time stamp ... is ... in the future
通常是本机和服务器时间不一致导致的警告,可以先忽略。
但如果遇到:
text
Unexpected EOF in archive
premature end
说明压缩包损坏或传输不完整,需要重新传输,并建议校验:
bash
zstd -t Paddle-source-with-build.tar.zst
sha256sum Paddle-source-with-build.tar.zst
10. 5090 启动编译容器
bash
docker run -it --name paddle-cu128-build-5090 \
--gpus all \
--shm-size=64g \
--network=none \
-v <REMOTE_WORKSPACE>/Paddle:/workspace/Paddle \
-v <REMOTE_WORKSPACE>/cache:/root/.cache \
-v <REMOTE_WORKSPACE>/ccache:/root/.ccache \
-w /workspace/Paddle \
paddle-build:cuda12.8-cudnn-devel-ubuntu22.04 \
bash
容器内:
bash
git config --global --add safe.directory "*"
nvidia-smi
nvcc --version
nvcc --list-gpu-arch | grep compute_120
11. 5090 重新 CMake
建议在 5090 上重新配置 CMake,但尽量保留 build/third_party 缓存:
bash
cd /workspace/Paddle/build
rm -f CMakeCache.txt
rm -rf CMakeFiles
重新配置:
bash
cmake .. \
-GNinja \
-DPYTHON_EXECUTABLE=$(which python) \
-DWITH_GPU=ON \
-DWITH_TESTING=OFF \
-DWITH_DISTRIBUTE=ON \
-DWITH_MKL=ON \
-DWITH_ONEDNN=ON \
-DWITH_PYTHON=ON \
-DCMAKE_BUILD_TYPE=Release \
-DPY_VERSION=3.10 \
-DWITH_CINN=ON \
-DCUDA_ARCH_NAME=Manual \
-DCUDA_ARCH_BIN="12.0" \
-DWITH_XPU=OFF \
-DWITH_ROCM=OFF
12. 5090 编译 Paddle
bash
cd /workspace/Paddle/build
ninja paddle_python -j8
如果服务器内存和磁盘充足,可以尝试:
bash
ninja paddle_python -j16
如果出现 OOM,降低并发:
bash
ninja paddle_python -j4
13. 手动打包 wheel
有时 ninja paddle_python 编译结束后,build/python/dist 目录还没有生成 .whl。这时进入 Python 打包目录:
bash
cd /workspace/Paddle/build/python
python setup.py bdist_wheel
查找 wheel:
bash
find /workspace/Paddle/build -type f -name "*.whl" -print
通常输出目录是:
text
/workspace/Paddle/build/python/dist/
如果报缺依赖,例如:
text
RuntimeError: Missing build dependency: httpx
安装:
bash
python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple httpx
或者更完整地安装 Paddle Python requirements:
bash
cd /workspace/Paddle
python -m pip install -r python/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
如果 5090 容器严格无网,应提前在本机下载这些 wheel 包并传入容器。
14. 安装并验证
安装 wheel:
bash
pip install /workspace/Paddle/build/python/dist/*.whl
如果 5090 容器无网络,直接安装 wheel 时可能会尝试从 PyPI 拉取 CUDA Python 依赖,例如:
text
nvidia-cuda-nvrtc-cu12==12.8.61
报错示例:
text
ERROR: Could not find a version that satisfies the requirement nvidia-cuda-nvrtc-cu12==12.8.61
ERROR: No matching distribution found for nvidia-cuda-nvrtc-cu12==12.8.61
由于当前 Docker 镜像本身已经提供 CUDA 12.8、NVRTC、cuDNN 等运行库,安装自编译 wheel 时可以跳过依赖解析:
bash
pip install --no-index --no-deps --force-reinstall \
/workspace/Paddle/build/python/dist/paddlepaddle_gpu-*.whl
如果容器有网络,也可以不加 --no-index,但离线服务器建议固定使用 --no-index --no-deps,避免 pip 访问外网。
验证 GPU:
bash
python - <<'PY'
import paddle
print("Paddle version:", paddle.__version__)
print("CUDA compiled:", paddle.is_compiled_with_cuda())
print("Device before:", paddle.device.get_device())
paddle.set_device("gpu:0")
x = paddle.randn([1024, 1024], dtype="float32")
y = paddle.matmul(x, x)
print("Device after:", paddle.device.get_device())
print(y.shape)
print("OK")
PY
成功标志:
text
CUDA compiled: True
GPU Compute Capability: 12.0
Driver API Version: 12.8
Runtime API Version: 12.8
Device after: gpu:0
OK
一次实际成功验证输出类似:
text
CUDA compiled: True
Device before: gpu:0
Please NOTE: device: 0, GPU Compute Capability: 12.0, Driver API Version: 12.8, Runtime API Version: 12.8
Device after: gpu:0
paddle.Size([1024, 1024])
OK
其中 GPU Compute Capability: 12.0 说明运行目标确实是 RTX 5090 对应的 sm_120 架构,OK 说明基础 GPU 张量计算已经跑通。
15. 踩坑总结
15.1 CUDA 12.6 不支持 5090
CUDA 12.6 的 nvcc 不认识 sm_120,所以不能用来编译 RTX 5090 原生 Paddle wheel。
解决:使用 CUDA 12.8 devel 镜像。
15.2 Git dubious ownership
容器 root 用户访问宿主机 Git 仓库会报:
text
fatal: detected dubious ownership in repository
解决:
bash
git config --global --add safe.directory "*"
15.3 submodule 不完整
典型错误:
text
third_party/gloo does not appear to contain CMakeLists.txt
解决:
bash
git submodule sync --recursive
git submodule update --init --recursive --force --checkout --jobs 8
15.4 CINN 代码生成失败
典型错误:
text
Cannot find source file: cinn_op.cc
ModuleNotFoundError: No module named 'jinja2'
解决:Dockerfile 安装:
text
jinja2
pybind11_stubgen
15.5 链接找不到 OpenSSL
典型错误:
text
/usr/bin/ld: cannot find -lssl
/usr/bin/ld: cannot find -lcrypto
解决:Dockerfile 安装:
text
libssl-dev
openssl
如果已经在离线容器中,也可以临时软链接:
bash
ln -sf /usr/lib/x86_64-linux-gnu/libssl.so.3 /usr/lib/x86_64-linux-gnu/libssl.so
ln -sf /usr/lib/x86_64-linux-gnu/libcrypto.so.3 /usr/lib/x86_64-linux-gnu/libcrypto.so
ldconfig
15.6 wheel 打包缺 httpx
典型错误:
text
RuntimeError: Missing build dependency: httpx
解决:Dockerfile 安装 httpx,或在容器内安装:
bash
python -m pip install httpx
15.7 离线安装 wheel 时 pip 拉取 nvidia-cuda-nvrtc-cu12 失败
典型错误:
text
ERROR: Could not find a version that satisfies the requirement nvidia-cuda-nvrtc-cu12==12.8.61
ERROR: No matching distribution found for nvidia-cuda-nvrtc-cu12==12.8.61
原因:自编译的 Paddle wheel 声明了 CUDA Python 依赖,但 5090 容器无网络,pip 无法访问 PyPI;同时 CUDA 12.8 运行库已经由 Docker 镜像提供,不需要 pip 再下载。
解决:离线安装时跳过依赖解析:
bash
pip install --no-index --no-deps --force-reinstall \
paddlepaddle_gpu-*.whl
15.8 tar 解压 Unexpected EOF
这是压缩包损坏或传输不完整,不是时间戳问题。
解决:重新传输,并校验:
bash
zstd -t Paddle-source-with-build.tar.zst
sha256sum Paddle-source-with-build.tar.zst
16. 最终建议
为了后续可复现,建议保留以下产物:
text
paddle-build-cuda12.8-cudnn-devel-ubuntu22.04.tar.zst
Paddle-source-with-build.tar.zst
paddle-cache.tar.zst
paddle-ccache.tar.zst
最终编译出的 paddlepaddle*.whl
如果要重新部署到另一台 5090 服务器,只需要导入镜像、解压源码和缓存,再执行 CMake、Ninja 和 wheel 打包即可。