Ubuntu 24.04 从源码编译安装 ONNX 与 ONNX Runtime
目标:让同学在 Ubuntu 24.04 上从源码构建并安装:
• ONNX Python 包 • ONNX C++ 库与头文件 • ONNX Runtime Python wheel • ONNX Runtime C++ 动态库与头文件 最终完成 Linux 环境 ONNX 开发环境的定制化搭建 
0. 概念
• ONNX:模型交换格式、operator schema、protobuf 表达。 • ONNX Runtime:模型执行引擎。
1. 版本与目录约定
export ONNX_VERSION=v1.22.0
export ORT_VERSION=v1.25.1
export PROTOBUF_VERSION=v5.29.2建议目录:
export ROOT=$HOME/onnx_lab
export SRC=$ROOT/src
export BUILD=$ROOT/build
export INSTALL=$ROOT/install
export WHEELHOUSE=$ROOT/wheelhouse
export VENV=$ROOT/venv2. 安装系统依赖
sudo apt update
sudo apt install -y \
build-essential \
git \
curl \
wget \
ca-certificates \
pkg-config \
ninja-build \
cmake \
python3 \
python3-dev \
python3-venv \
python3-pip \
patchelf \
zlib1g-dev \
libssl-dev \
libffi-dev \
libbz2-dev \
liblzma-dev \
libreadline-dev \
libsqlite3-dev \
uuid-dev检查工具版本:
gcc --version
g++ --version
cmake --version
python3 --version
git --version
ninja --version建议最低状态:
gcc >= 10
g++ >= 10
cmake >= 3.28
python >= 3.11Ubuntu 24.04 通常是:
GCC 13
Python 3.12
CMake 3.28.x3. 创建工作目录与 Python 虚拟环境
export ROOT=$HOME/onnx_lab
export SRC=$ROOT/src
export BUILD=$ROOT/build
export INSTALL=$ROOT/install
export WHEELHOUSE=$ROOT/wheelhouse
export VENV=$ROOT/venv
mkdir -p "$SRC" "$BUILD" "$INSTALL" "$WHEELHOUSE"创建 venv:
python3 -m venv "$VENV"
source "$VENV/bin/activate"升级 Python 构建工具:
python -m pip install --upgrade pip setuptools wheel build packaging
python -m pip install numpy protobuf typing_extensions ml_dtypes nanobind pybind11 cmake ninja确认当前 Python 来自 venv:
which python
python --version
python -c "import sys; print(sys.executable)"预期路径类似:
/home/cpp/onnx_lab/venv/bin/python4. 从源码构建 Protobuf
ONNX 的核心文件格式基于 Protobuf。
为了减少系统 Protobuf、pip Protobuf、源码 Protobuf 混用,本手册单独构建一份静态 Protobuf 给 ONNX 使用。
cd "$SRC"
git clone --recursive https://github.com/protocolbuffers/protobuf.git
cd protobuf
git checkout "$PROTOBUF_VERSION"
git submodule update --init --recursive配置:
cmake -S . -B "$BUILD/protobuf" \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$INSTALL/protobuf" \
-Dprotobuf_BUILD_SHARED_LIBS=OFF \
-Dprotobuf_BUILD_TESTS=OFF \
-Dprotobuf_BUILD_EXAMPLES=OFF \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON编译安装:
cmake --build "$BUILD/protobuf" --parallel
cmake --install "$BUILD/protobuf"设置当前 shell 环境:
export PATH="$INSTALL/protobuf/bin:$PATH"
export CMAKE_PREFIX_PATH="$INSTALL/protobuf:${CMAKE_PREFIX_PATH:-}"
export LD_LIBRARY_PATH="$INSTALL/protobuf/lib:${LD_LIBRARY_PATH:-}"检查:
which protoc
protoc --version预期类似:
libprotoc 29.25. 从源码构建并安装 ONNX Python 包
cd "$SRC"
git clone --recursive https://github.com/onnx/onnx.git
cd onnx
git checkout "$ONNX_VERSION"
git submodule update --init --recursive先清理已有 ONNX,避免误用 pip wheel:
python -m pip uninstall -y onnx设置 ONNX 构建参数:
export ONNX_PROTOC_EXECUTABLE="$INSTALL/protobuf/bin/protoc"
export CMAKE_PREFIX_PATH="$INSTALL/protobuf:${CMAKE_PREFIX_PATH:-}"
export CMAKE_ARGS="-DONNX_USE_LITE_PROTO=ON \
-DONNX_USE_PROTOBUF_SHARED_LIBS=OFF \
-DONNX_CUSTOM_PROTOC_EXECUTABLE=$INSTALL/protobuf/bin/protoc \
-DCMAKE_PREFIX_PATH=$INSTALL/protobuf"构建 wheel:
python -m build --wheel --no-isolation安装 wheel:
python -m pip install --force-reinstall dist/onnx-*.whl验证:
python - <<'PY'
import onnx
print("onnx =", onnx.__version__)
print("onnx path =", onnx.__file__)
PY预期路径应该位于当前 venv 中。
6. 从源码构建并安装 ONNX C++ 库
ONNX Python 包用于 Python 侧模型构造、检查、序列化。
如果你希望课堂上也展示 ONNX 的 C 侧模型结构,可以单独安装 ONNX C 库。
cd "$SRC/onnx"配置 C++ 构建:
cmake -S . -B "$BUILD/onnx-cpp" \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$INSTALL/onnx" \
-DCMAKE_PREFIX_PATH="$INSTALL/protobuf" \
-DONNX_BUILD_PYTHON=OFF \
-DONNX_BUILD_TESTS=OFF \
-DONNX_USE_LITE_PROTO=ON \
-DONNX_USE_PROTOBUF_SHARED_LIBS=OFF \
-DONNX_CUSTOM_PROTOC_EXECUTABLE="$INSTALL/protobuf/bin/protoc" \
-DCMAKE_CXX_STANDARD=17编译安装:
cmake --build "$BUILD/onnx-cpp" --parallel
cmake --install "$BUILD/onnx-cpp"检查安装结果:
find "$INSTALL/onnx" -maxdepth 3 -type f | head -50
find "$INSTALL/onnx" -maxdepth 5 -type f | grep -E 'onnx.*Config|\.so$|\.a$|\.h$' | head -50通常应看到:
include/onnx
lib
lib/cmake/ONNX7. ONNX C++ 最小验证
创建测试目录:
mkdir -p "$ROOT/smoke_onnx_cpp"
cd "$ROOT/smoke_onnx_cpp"创建 main.cpp:
#include <onnx/onnx_pb.h>
#include <iostream>
int main(){
onnx::ModelProto model;
model.set_ir_version(10);
std::cout << "ONNX C++ smoke test OK\n";
std::cout << "ir_version = " << model.ir_version() << "\n";
return 0;
}创建 CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(onnx_cpp_smoke LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT DEFINED ONNX_ROOT)
message(FATAL_ERROR "Please pass -DONNX_ROOT=/path/to/install/onnx")
endif()
if(NOT DEFINED PROTOBUF_ROOT)
message(FATAL_ERROR "Please pass -DPROTOBUF_ROOT=/path/to/install/protobuf")
endif()
list(APPEND CMAKE_PREFIX_PATH "${ONNX_ROOT}" "${PROTOBUF_ROOT}")
find_package(Protobuf CONFIG REQUIRED)
find_package(ONNX CONFIG REQUIRED)
add_executable(onnx_cpp_smoke main.cpp)
if(TARGET ONNX::onnx)
target_link_libraries(onnx_cpp_smoke PRIVATE ONNX::onnx ONNX::onnx_proto)
elseif(TARGET onnx)
target_link_libraries(onnx_cpp_smoke PRIVATE onnx onnx_proto)
else()
message(FATAL_ERROR "Cannot find ONNX CMake targets")
endif()配置、编译、运行:
cmake -S . -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DONNX_ROOT="$INSTALL/onnx" \
-DPROTOBUF_ROOT="$INSTALL/protobuf"
cmake --build build --parallel
./build/onnx_cpp_smoke预期输出:
ONNX C++ smoke test OK
ir_version = 10如果运行时报找不到 .so,临时设置:
export LD_LIBRARY_PATH="$INSTALL/onnx/lib:$INSTALL/protobuf/lib:${LD_LIBRARY_PATH:-}"然后重试。
8. 从源码构建 ONNX Runtime:Python wheel + C++ 动态库
获取源码:
cd "$SRC"
git clone --recursive https://github.com/microsoft/onnxruntime.git
cd onnxruntime
git checkout "$ORT_VERSION"
git submodule update --init --recursive确保没有装过其他 ORT 包:
python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-training构建 CPU:
./build.sh \
--config Release \
--update \
--build \
--parallel \
--build_shared_lib \
--build_wheel \
--compile_no_warning_as_error9. 安装 ONNX Runtime Python wheel
ORT wheel 通常位于:
$SRC/onnxruntime/build/Linux/Release/dist安装:
cd "$SRC/onnxruntime"
python -m pip install --force-reinstall build/Linux/Release/dist/onnxruntime-*.whl验证:
python - <<'PY'
import onnxruntime as ort
print("onnxruntime =", ort.__version__)
print("providers =", ort.get_available_providers())
PY预期至少包含:
CPUExecutionProvider10. 整理 ONNX Runtime C++ 安装目录
ORT 构建产物通常在:
$SRC/onnxruntime/build/Linux/Release创建安装目录:
mkdir -p "$INSTALL/onnxruntime/include"
mkdir -p "$INSTALL/onnxruntime/lib"复制头文件:
cp -a "$SRC/onnxruntime/include/onnxruntime" "$INSTALL/onnxruntime/include/"复制动态库和静态导入相关文件:
find "$SRC/onnxruntime/build/Linux/Release" \
-maxdepth 3 \
\( -name "libonnxruntime.so*" -o -name "onnxruntime*.so*" \) \
-exec cp -a {} "$INSTALL/onnxruntime/lib/" \;检查:
find "$INSTALL/onnxruntime/include" -type f | grep "onnxruntime_cxx_api.h"
find "$INSTALL/onnxruntime/lib" -maxdepth 1 -type f -o -type l应该看到:
onnxruntime_c_api.h
onnxruntime_cxx_api.h
libonnxruntime.so设置运行时库路径:
export LD_LIBRARY_PATH="$INSTALL/onnxruntime/lib:${LD_LIBRARY_PATH:-}"也可以写入当前 venv 的激活脚本:
cat >> "$VENV/bin/activate" <<EOF
# ONNX / ONNX Runtime lab paths
export PATH="$INSTALL/protobuf/bin:\$PATH"
export LD_LIBRARY_PATH="$INSTALL/onnxruntime/lib:$INSTALL/onnx/lib:$INSTALL/protobuf/lib:\${LD_LIBRARY_PATH:-}"
export CMAKE_PREFIX_PATH="$INSTALL/onnxruntime:$INSTALL/onnx:$INSTALL/protobuf:\${CMAKE_PREFIX_PATH:-}"
EOF重新激活:
deactivate
source "$VENV/bin/activate"11. Python 端完整验证:构造 ONNX 模型并用 ORT CPU 推理
创建验证目录:
mkdir -p "$ROOT/smoke_python"
cd "$ROOT/smoke_python"创建 verify_python.py:
import numpy as np
import onnx
import onnxruntime as ort
from onnx import helper, TensorProto
print("onnx =", onnx.__version__)
print("onnxruntime =", ort.__version__)
print("providers =", ort.get_available_providers())
X = helper.make_tensor_value_info("x", TensorProto.FLOAT, [None, 3])
Y = helper.make_tensor_value_info("y", TensorProto.FLOAT, [None, 3])
one = helper.make_tensor("one", TensorProto.FLOAT, [1], [1.0])
node = helper.make_node("Add", ["x", "one"], ["y"])
graph = helper.make_graph(
[node],
"add_one_graph",
[X],
[Y],
[one],
)
model = helper.make_model(
graph,
producer_name="onnx_lab",
opset_imports=[helper.make_operatorsetid("", 13)],
)
# 使用保守 IR version,避免 ONNX 生成的模型过新而 ORT 无法加载。
model.ir_version = 10
onnx.checker.check_model(model)
onnx.save(model, "add_one.onnx")
sess = ort.InferenceSession(
"add_one.onnx",
providers=["CPUExecutionProvider"],
)
x = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]], dtype=np.float32)
y = sess.run(None, {"x": x})[0]
print("input:")
print(x)
print("output:")
print(y)
expected = x + 1.0
np.testing.assert_allclose(y, expected)
print("Python ONNX + ONNX Runtime CPU smoke test OK")运行:
python verify_python.py预期输出包含:
CPUExecutionProvider
Python ONNX + ONNX Runtime CPU smoke test OK12. C++ 端完整验证:用 ONNX Runtime C++ API 推理
复用 Python 端生成的模型:
$ROOT/smoke_python/add_one.onnx创建 C++ 测试目录:
mkdir -p "$ROOT/smoke_ort_cpp"
cd "$ROOT/smoke_ort_cpp"
cp "$ROOT/smoke_python/add_one.onnx" .创建 main.cpp:
#include <onnxruntime_cxx_api.h>
#include <array>
#include <iostream>
#include <vector>
int main(){
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "ort_cpp_smoke");
Ort::SessionOptions session_options;
session_options.SetIntraOpNumThreads(1);
session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_BASIC);
const char* model_path = "add_one.onnx";
Ort::Session session(env, model_path, session_options);
std::array<float, 6> input_data{
1.0f, 2.0f, 3.0f,
4.0f, 5.0f, 6.0f
};
std::array<int64_t, 2> input_shape{2, 3};
Ort::MemoryInfo memory_info =
Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
memory_info,
input_data.data(),
input_data.size(),
input_shape.data(),
input_shape.size()
);
const char* input_names[] = {"x"};
const char* output_names[] = {"y"};
auto outputs = session.Run(
Ort::RunOptions{nullptr},
input_names,
&input_tensor,
1,
output_names,
1
);
float* y = outputs[0].GetTensorMutableData<float>();
std::cout << "output:\n";
for (size_t i = 0; i < input_data.size(); ++i) {
std::cout << y[i] << " ";
}
std::cout << "\n";
if (y[0] != 2.0f || y[5] != 7.0f) {
std::cerr << "Unexpected result\n";
return 1;
}
std::cout << "C++ ONNX Runtime CPU smoke test OK\n";
return 0;
}创建 CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(ort_cpp_smoke LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT DEFINED ORT_ROOT)
message(FATAL_ERROR "Please pass -DORT_ROOT=/path/to/install/onnxruntime")
endif()
add_executable(ort_cpp_smoke main.cpp)
target_include_directories(ort_cpp_smoke PRIVATE
"${ORT_ROOT}/include/onnxruntime/core/session"
)
target_link_directories(ort_cpp_smoke PRIVATE
"${ORT_ROOT}/lib"
)
target_link_libraries(ort_cpp_smoke PRIVATE onnxruntime)
set_target_properties(ort_cpp_smoke PROPERTIES
BUILD_RPATH "${ORT_ROOT}/lib"
INSTALL_RPATH "${ORT_ROOT}/lib"
)配置、构建、运行:
cmake -S . -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DORT_ROOT="$INSTALL/onnxruntime"
cmake --build build --parallel
export LD_LIBRARY_PATH="$INSTALL/onnxruntime/lib:${LD_LIBRARY_PATH:-}"
./build/ort_cpp_smoke预期输出:
output:
2 3 4 5 6 7
C++ ONNX Runtime CPU smoke test OK13. 最终检查清单
13.1 Python 检查
python - <<'PY'
import onnx
import onnxruntime as ort
print("onnx =", onnx.__version__)
print("onnxruntime =", ort.__version__)
print("providers =", ort.get_available_providers())
PY必须看到:
CPUExecutionProvider13.2 ONNX C++ 检查
"$ROOT/smoke_onnx_cpp/build/onnx_cpp_smoke"必须输出:
ONNX C++ smoke test OK13.3 ONNX Runtime C++ 检查
"$ROOT/smoke_ort_cpp/build/ort_cpp_smoke"必须输出:
C++ ONNX Runtime CPU smoke test OK14. 常见失败与修复
问题 1:误用了系统 Python,而不是 venv Python
检查:
which python
python -c "import sys; print(sys.executable)"正确路径应类似:
/home/your_name/onnx_lab/venv/bin/python修复:
source "$VENV/bin/activate"问题 2:protoc 不是手工构建的版本
检查:
which protoc
protoc --version正确路径应类似:
/home/your_name/onnx_lab/install/protobuf/bin/protoc修复:
export PATH="$INSTALL/protobuf/bin:$PATH"
export CMAKE_PREFIX_PATH="$INSTALL/protobuf:${CMAKE_PREFIX_PATH:-}"问题 3:ONNX 构建时找不到 Protobuf
检查:
echo "$CMAKE_PREFIX_PATH"
echo "$ONNX_PROTOC_EXECUTABLE"
echo "$CMAKE_ARGS"修复:
export ONNX_PROTOC_EXECUTABLE="$INSTALL/protobuf/bin/protoc"
export CMAKE_PREFIX_PATH="$INSTALL/protobuf:${CMAKE_PREFIX_PATH:-}"
export CMAKE_ARGS="-DONNX_USE_LITE_PROTO=ON \
-DONNX_USE_PROTOBUF_SHARED_LIBS=OFF \
-DONNX_CUSTOM_PROTOC_EXECUTABLE=$INSTALL/protobuf/bin/protoc \
-DCMAKE_PREFIX_PATH=$INSTALL/protobuf"然后重新构建 ONNX wheel:
cd "$SRC/onnx"
rm -rf build dist *.egg-info
python -m build --wheel --no-isolation
python -m pip install --force-reinstall dist/onnx-*.whl问题 4:libonnxruntime.so: cannot open shared object file
现象:
error while loading shared libraries: libonnxruntime.so: cannot open shared object file修复:
export LD_LIBRARY_PATH="$INSTALL/onnxruntime/lib:${LD_LIBRARY_PATH:-}"或者在 CMake 中设置 rpath:
set_target_properties(your_target PROPERTIES
BUILD_RPATH "/home/your_name/onnx_lab/install/onnxruntime/lib"
INSTALL_RPATH "/home/your_name/onnx_lab/install/onnxruntime/lib"
)问题 5:ORT 构建中途下载依赖失败
原因通常是:
• 网络不稳定; • GitHub 连接慢; • 子模块未初始化完整; • 依赖缓存损坏。
修复:
cd "$SRC/onnxruntime"
git submodule sync --recursive
git submodule update --init --recursive然后重试:
./build.sh \
--config Release \
--update \
--build \
--parallel \
--build_shared_lib \
--build_wheel \
--compile_no_warning_as_error如果仍失败,尝试:
./build.sh \
--config Release \
--update \
--build \
--parallel \
--build_shared_lib \
--build_wheel \
--compile_no_warning_as_error \
--use_vcpkg问题 6:内存不足,编译被 killed
现象:
c++: fatal error: Killed signal terminated program cc1plus原因:
并行编译过多导致内存不足。
修复:
降低并行度:
export MAX_JOBS=2或者:
./build.sh \
--config Release \
--update \
--build \
--build_shared_lib \
--build_wheel \
--compile_no_warning_as_error \
--parallel 1如果 --parallel 2 不被当前脚本接受,就去掉 --parallel,让构建系统使用较保守并行度。
问题 7:模型 ONNX checker 通过,但 ORT 加载失败
这不是矛盾。
onnx.checker.check_model(model) 只说明:
这个模型在 ONNX 格式层面是合法的。它不说明:
当前 ONNX Runtime 版本一定实现了这些 operator。
当前 CPUExecutionProvider 一定支持这些 dtype。
当前 ORT 一定支持这个 IR version。所以课堂最小模型里故意使用:
model.ir_version = 10
opset_imports=[helper.make_operatorsetid("", 13)]这是为了降低“模型格式比 runtime 新”的风险。
夜雨聆风