一、前言

昇腾 NPU 驱动是连接操作系统内核、硬件设备与 CANN 应用栈的核心中间组件。在 CANN 算子开发、内核模块编译、自定义内核、驱动二次调试场景,GCC 编译器版本、系统库头文件、编译选项会直接影响驱动模块、内核态组件、用户态业务程序编译成败。

很多开发者在环境部署、自定义算子、内核模块编译时,经常遇到:头文件找不到、符号未定义、ABI 不兼容、ko 模块编译失败、用户态程序运行段错误等问题,根源大多来自 GCC 版本不匹配、内核头文件缺失、编译依赖配置错误。本文从昇腾 NPU 驱动基础原理入手,讲解驱动分层结构、GCC 编译依赖关系、编译环境配置、常见报错排查,帮助开发者处理驱动与业务代码编译问题。

二、昇腾 NPU 驱动基础原理

2.1 NPU 驱动分层架构

昇腾驱动软件整体分为内核态驱动与用户态驱动库两层,二者协同完成硬件资源管理。

  1. 内核态驱动(kernel‑mode) 以内核模块.ko形式运行于 Linux 内核空间,主要完成硬件设备初始化、PCIe 设备枚举、寄存器配置、中断处理、内存管理(SMMU、DMA 内存)、硬件异常上报。内核模块编译必须与当前运行 Linux 内核版本、内核头文件、编译 GCC 版本保持严格对齐。

  2. 用户态驱动库(user‑mode)libAscendHal.so等动态库,运行在应用进程空间,提供 rt 系列 Runtime API;通过字符设备节点(/dev/davinci*)与内核驱动交互,完成任务下发、流管理、内存申请释放。用户态代码编译依赖系统 GCC、C 标准库,同时需要匹配驱动版本 ABI 接口。

2.2 数据流简要流程

  1. 用户态 CANN 应用调用 Runtime 接口;

  2. 用户态驱动库通过 ioctl 向内核态 ko 驱动下发命令;

  3. 内核驱动完成 DMA 内存映射、硬件寄存器配置,把任务交给 NPU 硬件执行;

  4. 硬件中断上报执行状态,内核驱动回传结果至用户态。

关键约束:内核模块 ko 的编译 GCC、内核头文件必须和编译当前正在运行操作系统内核的 GCC 版本保持一致,否则 ko 无法加载,报 version magic 不匹配;用户态程序 GCC 可以和内核编译 GCC 不一致,但要注意 GLIBC 版本 ABI 兼容性。

三、GCC 编译依赖梳理

3.1 内核态 ko 模块编译依赖

编译昇腾内核驱动模块(或自定义内核模块),必须具备下面依赖:

  1. Linux 内核头文件 kernel‑devel / kernel‑headers 版本必须和uname‑r显示的正在运行内核版本完全一致。内核头文件提供数据结构、宏定义、函数声明。版本不一致会出现结构体定义不一致、magic 版本校验失败,ko 模块 insmod 失败。

  2. GCC 编译器版本 编译 ko 的 GCC 版本必须等于厂商编译操作系统内核时使用的 GCC 版本。openEuler、CentOS、Ubuntu 不同发行版默认 GCC 版本各不相同。

# 查看当前系统内核版本
uname -r
# 查看系统内核编译时使用的gcc版本
cat /proc/version
# 查看本机gcc版本
gcc --version
  1. Makefile/Kbuild 编译框架 Linux 内核模块必须基于 Kbuild 体系编译,不能直接使用 gcc 命令单独编译 c 文件。

常见误区:系统升级 gcc 之后直接重新编译 ko,此时 gcc 版本和内核编译 gcc 不一致,生成 ko 无法加载。

3.2 用户态 CANN 组件编译依赖(自定义算子 so、业务程序)

用户态编译自定义算子插件、业务程序,依赖如下:

  1. GCC/G++ 编译器,C++ 标准版本需要与 CANN 库 ABI 兼容。

  • CANN 8.x 推荐 GCC 8.5 ~ GCC 11;不建议使用 GCC‑12 及以上高版本,容易发生 C++ ABI 不兼容。

  1. GLIBC 系统库,运行环境 GLIBC 版本不能低于编译机 GLIBC 版本。

  2. CANN 头文件与动态库:opbase、ascend_hal、CATLASS 头文件库。

  3. C++ 标准库libstdc++.so,编译环境与运行环境版本尽量对齐。

用户态注意:用户态 GCC 不需要和内核编译 GCC 版本一致,但是 C++ ABI 版本必须和 CANN 预编译库保持匹配。CANN 预编译库使用‑D_GLIBCXX_USE_CXX11_ABI=0或 1,编译业务代码必须保持同样的宏定义。

3.3 如何检查环境依赖完整性

# 1、查看内核信息
uname -r
cat /proc/version

# 2、检查内核头文件是否安装(openEuler示例)
rpm -qa | grep kernel‑devel

# 3、检查gcc/g++版本
gcc --version
g++ --version

# 4、查看GLIBC版本
ldd --version

# 5、检查CANN环境是否加载
source /usr/local/Ascend/ascend‑toolkit/latest/bin/set_env.sh
echo $ASCEND_TOOLKIT_PATH

四、不同编译对象完整编译实践

4.1 内核驱动 ko 模块编译(Kbuild 方式)

不能直接 gcc 编译,必须使用内核 Make 编译框架。 Kbuild 示例片段:

obj‑m += ascend_custom_mod.o
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	make -C $(KDIR) M=$(PWD) clean

编译执行命令:

make

编译产出.ko文件,加载模块:

insmod ascend_custom_mod.ko

如果出现version magic mismatch:说明 gcc 版本或者内核头文件与运行内核不匹配。

4.2 CANN 自定义算子 so 编译(用户态,CMake+GCC)

CMakeLists 关键片段,控制 GCC 与 ABI 宏:

set(CMAKE_CXX_COMPILER gcc)
set(CMAKE_CXX_STANDARD 17)
# 必须与CANN库ABI保持一致
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)

include_directories(${CANN_INC_PATH})

add_library(custom_op SHARED kernel_demo.cc)
target_link_libraries(custom_op opbase ascend_hal)

编译流程:

source /usr/local/Ascend/ascend‑toolkit/latest/bin/set_env.sh
mkdir build && cd build
cmake ..
make -j

产出libcustom_op.so用户态算子插件。

4.3 AI‑Core 设备内核编译说明

AI‑Core 内核不使用主机 gcc,使用 CANN 自带ascend‑cc编译器。

# 编译AI‑core内核示例
ascend‑cc‑c‑o kernel.o kernel.cc

很多初学者把 GCC 用于编译设备端代码,会报大量未知指令、类型不识别错误。

五、常见编译报错与问题排查

5.1 内核模块 ko 编译 & 加载问题

1.No such file or directory /lib/modules/xxx/build

未安装内核头文件包kernel‑devel,安装与uname‑r版本完全一致的内核开发包。

2.insmod 报错 version magic 不匹配

编译 ko 的 gcc 版本、内核头文件和当前运行内核编译环境不一致。不要升级 gcc 后直接编译 ko,使用系统原生配套 gcc。

3.隐式声明函数,结构体成员找不到

内核头文件版本与运行内核版本不一致。

5.2 用户态 C++ 算子编译报错

1.大量未定义引用 undefined reference(opbase 符号)

CANN 库链接缺失,CMake 没有配置target_link_libraries链接 opbase、ascend_hal。

2.运行时 so 加载失败:undefined symbol

  • GCC 版本过高,C++ ABI 不匹配;

  • GLIBCXXUSE_CXX11_ABI宏编译前后不一致;

  • 算子 so 运行时没有找到 CANN 动态库,未执行 set_env.sh。

3.编译报头文件找不到 opbase/kernel_ascend.h

CANN 头文件路径没有加入 include_directories,确认已经 source CANN 环境变量。

5.3 GLIB 版本不匹配(跨机器拷贝程序)

报错:version GLIBC_2.27 not found

编译机器 GLIBC 版本高于目标运行机器。解决方案:在低版本 GLIBC 机器上编译,或者使用容器统一编译环境。

5.4 混淆 GCC 与 ascend‑cc

编译 AI‑core 内核使用 gcc,报语法错误、不识别__aicore__关键字。

AI‑Core 设备代码只能使用ascend‑cc,GCC 只能编译主机侧代码。

六、GCC 版本选型最佳实践

  1. 内核 ko 模块编译:必须使用操作系统发行版原生配套 GCC,不要手动升级 GCC,内核头文件版本严格匹配uname -r。

  2. CANN 自定义算子用户态 so

    1. CANN 7.x:推荐 GCC 7.5 ~ GCC8.5

    2. CANN 8.x:推荐 GCC8.5 ~ GCC11

    3. 避免 GCC‑12、GCC‑13 等高版本,防止 ABI 兼容性问题。

  3. 编译环境与运行环境尽量保持一致,优先使用容器镜像固化 GCC、CANN、内核头文件环境,避免机器环境差异。

  4. 统一_GLIBCXX_USE_CXX11_ABI宏,CANN 预编译库默认大多为0,业务代码也要保持一致。

  5. AI‑Core 设备端代码坚决不使用主机 GCC,使用 CANN 自带 ascend‑cc。

七、驱动、内核头文件、GCC 三者关系总结

昇腾 NPU 驱动分为内核态 ko 模块与用户态动态库两部分:

  • 内核 ko 模块:强依赖运行内核版本、内核头文件、编译内核时所用 GCC,三者任意一项不一致会造成 ko 无法加载;必须使用 Kbuild 框架编译,不可直接调用 gcc 编译单个 c 文件。

  • 用户态 CANN 算子 / 业务程序:使用主机 GCC/G++ 编译,GCC 版本不需要匹配内核编译 GCC,但必须匹配 CANN 库 C++ ABI 与 GLIBC 版本。

  • AI‑Core 设备内核:和主机 GCC 完全无关,由 CANN 自带ascend‑cc设备编译器完成编译。

实际开发部署中,很多编译、加载异常,本质是 GCC 版本、内核头文件、ABI 三者不匹配;优先使用官方容器镜像固化整套编译环境,可以规避绝大多数依赖问题。排查时优先核对uname‑r内核版本、/proc/version编译环境、gcc 版本、内核 devel 包版本。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐