已合并
Add devcontainer build environment #5510
Add devcontainer build environment #5510
已合并
mhy创建于 7月20日
4 个文件变更+595-0
@@ -0,0 +1,28 @@
1+{
2+ "name": "OpPlugin Dev (CANN)",
3+ "build": {
4+ "dockerfile": "../docker/devel/Dockerfile",
5+ "context": "..",
6+ "target": "dev",
7+ "args": {
8+ "PY_VERSION": "3.10",
9+ "TORCH_VERSION": "2.13.0.dev20260610",
S
SSCh_zx7月29日

连同pytorch仓一块改成2.13.0吧

likedislike
mhy
7月29日 评论:
10+ "CANN_VERSION": "9.1.0_beta.1",
11+ "CANN_PRODUCT": "910b"
12+ }
13+ },
14+ "workspaceMount": "source=${localWorkspaceFolder},target=/home/op-plugin,type=bind,consistency=consistent",
15+ "workspaceFolder": "/home/op-plugin",
16+ "remoteUser": "root",
17+ "privileged": true,
18+ "mounts": [
19+ "source=/dev,target=/dev,type=bind,consistency=consistent",
20+ "source=/usr/local/Ascend/driver,target=/usr/local/Ascend/driver,type=bind,consistency=consistent",
21+ "source=/usr/local/Ascend/add-ons,target=/usr/local/Ascend/add-ons,type=bind,consistency=consistent",
22+ "source=/usr/local/sbin/npu-smi,target=/usr/local/bin/npu-smi,type=bind,consistency=consistent",
23+ "source=/var/log/npu,target=/usr/slog,type=bind,consistency=consistent"
24+ ],
25+ "remoteEnv": {
26+ "LD_LIBRARY_PATH": "${containerEnv:LD_LIBRARY_PATH}:/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/base:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver"
27+ }
28+}
@@ -0,0 +1,130 @@
1+FROM quay.io/pypa/manylinux_2_28 AS base
atomgit-bot
atomgit-botatomgit-bot7月20日

🟡 Medium Priority

Dockerfile 第1行使用 FROM quay.io/pypa/manylinux_2_28 AS base,未指定 digest(如 @sha256:...)。

manylinux_2_28 是一个浮动标签(rolling tag),始终指向该系列的最新构建。不同时间拉取会得到不同镜像,导致:

  • 构建不可重现(同一 Dockerfile、同一天构建可能得到不同结果);
  • 镜像更新可能引入不兼容的系统库变更,导致 CANN 安装或编译流程静默失败。

这是审查指南要求的关注点:unpinned base image tags。

建议:固定到特定 digest,例如 FROM quay.io/pypa/manylinux_2_28@sha256:xxxx。可以在稳定验证后锁定 digest,并在后续有计划地滚动更新。

likedislike
不准确?
2+ 
3+ENV LC_ALL=en_US.UTF-8 \
4+ LANG=en_US.UTF-8 \
5+ LANGUAGE=en_US.UTF-8
6+ 
7+ENV PATH=/usr/local/bin:$PATH
8+ 
9+RUN echo "alias ll='ls -l --color=auto'" >> /root/.bashrc
10+ 
11+ARG PY_VERSION=3.10
12+ 
13+RUN cd /usr/local/bin \
14+ && PY_TAG="cp$(echo ${PY_VERSION} | tr -d .)" \
15+ && if [ ! -d "/opt/python/${PY_TAG}-${PY_TAG}" ]; then echo "Unsupported Python version: ${PY_VERSION}" && exit 1; fi \
16+ && ln -sf /opt/python/${PY_TAG}-${PY_TAG}/bin/pip${PY_VERSION} pip${PY_VERSION} \
17+ && ln -sf /opt/python/${PY_TAG}-${PY_TAG}/bin/pip${PY_VERSION} pip3 \
18+ && ln -sf /opt/python/${PY_TAG}-${PY_TAG}/bin/pip${PY_VERSION} pip \
19+ && ln -sf /opt/python/${PY_TAG}-${PY_TAG}/bin/python${PY_VERSION} python${PY_VERSION} \
20+ && ln -sf /opt/python/${PY_TAG}-${PY_TAG}/bin/python${PY_VERSION} python3 \
21+ && ln -sf /opt/python/${PY_TAG}-${PY_TAG}/bin/python${PY_VERSION} python
22+ 
23+RUN mkdir /root/.pip \
24+ && echo "[global]" > /root/.pip/pip.conf \
25+ && echo "index-url=https://mirrors.huaweicloud.com/repository/pypi/simple" >> /root/.pip/pip.conf \
26+ && echo "trusted-host=repo.huaweicloud.com" >> /root/.pip/pip.conf \
27+ && echo "timeout=120" >> /root/.pip/pip.conf
28+ 
29+RUN yum install -y \
30+ bzip2 \
31+ curl \
32+ file \
33+ git \
34+ sudo \
35+ unzip \
36+ util-linux \
37+ wget \
38+ which && \
39+ yum clean all && \
40+ rm -rf /var/cache/yum && \
41+ rm -rf /tmp/*
42+ 
43+RUN git config --global --add safe.directory "*"
44+ 
45+FROM base AS builder
46+ 
47+ARG PY_VERSION
48+ARG DEVTOOLSET_VERSION=13
49+ARG TORCH_VERSION=2.13.0
50+ARG TARGETARCH
51+ 
52+RUN yum install -y \
53+ autoconf \
54+ automake \
55+ bison \
56+ diffutils \
57+ make \
58+ mold \
59+ ninja-build \
60+ patch \
61+ perl \
62+ yum-utils \
63+ zlib-devel \
64+ gcc-toolset-${DEVTOOLSET_VERSION}-gcc \
65+ gcc-toolset-${DEVTOOLSET_VERSION}-gcc-c++ \
66+ gcc-toolset-${DEVTOOLSET_VERSION}-gcc-gfortran \
67+ gcc-toolset-${DEVTOOLSET_VERSION}-gdb && \
68+ yum clean all && \
69+ rm -rf /var/cache/yum && \
70+ rm -rf /tmp/*
71+ 
72+ENV PATH=/opt/rh/gcc-toolset-${DEVTOOLSET_VERSION}/root/usr/bin:$PATH \
73+ LD_LIBRARY_PATH=/opt/rh/gcc-toolset-${DEVTOOLSET_VERSION}/root/usr/lib64:/opt/rh/gcc-toolset-${DEVTOOLSET_VERSION}/root/usr/lib:$LD_LIBRARY_PATH
74+ 
75+RUN if [ "${TARGETARCH}" = "amd64" ]; then \
76+ python3 -mpip install cmake==3.18.4.post1 && \
77+ ln -sf /usr/local/bin/cmake /usr/bin/cmake3; \
78+ fi
79+ 
80+RUN case "${PY_VERSION}" in \
81+ 3.9) NUMPY_VER=1.22.4 ;; \
82+ 3.10) NUMPY_VER=1.23.2 ;; \
83+ 3.11|3.12) NUMPY_VER=1.26.2 ;; \
84+ 3.13) NUMPY_VER=2.1.2 ;; \
85+ 3.14) NUMPY_VER=2.3.4 ;; \
86+ *) echo "Unsupported Python version: ${PY_VERSION}" && exit 1 ;; \
87+ esac && \
88+ pip${PY_VERSION} install pyyaml && \
89+ pip${PY_VERSION} install setuptools wheel && \
90+ case "${TORCH_VERSION}" in \
91+ *.dev*) pip${PY_VERSION} install torch==${TORCH_VERSION} --index-url https://download.pytorch.org/whl/nightly/cpu ;; \
92+ *) pip${PY_VERSION} install torch==${TORCH_VERSION} --index-url https://download.pytorch.org/whl/cpu ;; \
93+ esac && \
94+ pip${PY_VERSION} install numpy==${NUMPY_VER}
95+ 
96+FROM builder AS dev
97+ 
98+ARG CANN_VERSION=9.1.0_beta.1
99+ARG CANN_PRODUCT=910b
100+ARG INSTALL_NNAL=0
101+ARG CANN_RELEASE_TRAIN=CANN%209.1.T1
102+ 
103+RUN CANN_FILE_VER=$(echo ${CANN_VERSION} | sed 's/_beta/-beta/') && \
104+ ARCH_NAME=$(uname -m) && \
105+ CANN_URL=https://ascend-repo.obs.cn-east-2.myhuaweicloud.com/CANN/${CANN_RELEASE_TRAIN} && \
106+ ln -sf /dev/stdout /dev/tty && \
107+ wget ${CANN_URL}/Ascend-cann-toolkit_${CANN_FILE_VER}_linux-${ARCH_NAME}.run && \
108+ bash Ascend-cann-toolkit_${CANN_FILE_VER}_linux-${ARCH_NAME}.run --install --install-path=/usr/local/Ascend --quiet && \
109+ rm -f Ascend-cann-toolkit_${CANN_FILE_VER}_linux-${ARCH_NAME}.run && \
110+ wget ${CANN_URL}/Ascend-cann-${CANN_PRODUCT}-ops_${CANN_FILE_VER}_linux-${ARCH_NAME}.run && \
111+ bash Ascend-cann-${CANN_PRODUCT}-ops_${CANN_FILE_VER}_linux-${ARCH_NAME}.run --install --type=toolkit --install-path=/usr/local/Ascend --quiet && \
112+ rm -f Ascend-cann-${CANN_PRODUCT}-ops_${CANN_FILE_VER}_linux-${ARCH_NAME}.run && \
113+ if [ "$INSTALL_NNAL" = "1" ]; then \
114+ CANN_NNAL_VER=$(echo ${CANN_VERSION} | sed 's/_beta\.[0-9][0-9]*//') && \
115+ wget ${CANN_URL}/Ascend-cann-nnal_${CANN_NNAL_VER}_linux-${ARCH_NAME}.run && \
116+ bash Ascend-cann-nnal_${CANN_NNAL_VER}_linux-${ARCH_NAME}.run --install --install-path=/usr/local/Ascend --quiet && \
117+ rm -f Ascend-cann-nnal_${CANN_NNAL_VER}_linux-${ARCH_NAME}.run; \
atomgit-bot
atomgit-botatomgit-bot7月20日

🟡 Medium Priority

Dockerfile 第107-117行通过 wget 从远程 OBS 下载 .run 安装包后直接以 bash 执行,未做任何哈希校验(sha256/md5)。

被下载并执行的文件包括:

  • Ascend-cann-toolkit_*.run(第107-108行)
  • Ascend-cann-*-ops_*.run(第110-111行)
  • Ascend-cann-nnal_*.run(第115-116行,条件执行)

这些 .run 文件以 root 身份执行,具有完全的系统访问权限。若 OBS 存储被入侵、网络被中间人攻击(虽然使用 HTTPS,但未做证书 pinning),或包被意外替换,恶意代码将以 root 权限在构建环境中执行,可能窃取构建环境中的凭证或污染最终镜像。

审查指南明确要求关注 wget ... | sh 类模式的安全性。虽然不是管道执行,但 wget + bash 模式本质上等效。

建议:在 wgetbash 之间增加哈希校验步骤。可从昇腾官方渠道获取每个 .run 文件的 SHA256 值,在 Dockerfile 中通过 ARG 传入或在脚本中硬编码期望值,使用 sha256sum -c 校验通过后再执行。同时建议对每个下载单独校验并立即清理,避免一个损坏文件影响后续步骤的清理逻辑。

likedislike
不准确?
118+ fi && \
119+ rm -f /dev/tty && \
120+ echo "source /usr/local/Ascend/cann/set_env.sh" > /etc/profile.d/cann.sh && \
121+ if [ "$INSTALL_NNAL" = "1" ]; then \
122+ echo "source /usr/local/Ascend/nnal/atb/set_env.sh" >> /etc/profile.d/cann.sh; \
123+ fi && \
124+ chmod +x /etc/profile.d/cann.sh && \
125+ echo "source /usr/local/Ascend/cann/set_env.sh" >> /root/.bashrc && \
126+ echo "export ASCEND_GLOBAL_LOG_LEVEL=3" >> /root/.bashrc && \
127+ echo "export ASCEND_SLOG_PRINT_TO_STDOUT=0" >> /root/.bashrc && \
128+ echo "export LD_LIBRARY_PATH=/usr/local/Ascend/cann/lib64:/usr/local/Ascend/cann/opp/op_proto/built-in:\$LD_LIBRARY_PATH" >> /root/.bashrc
129+ 
130+WORKDIR /home
@@ -0,0 +1,212 @@
1+# OpPlugin 开发镜像
2+ 
3+本目录提供 Dockerfile 及构建脚本,用于生成 OpPlugin 的构建与开发镜像:`builder` 镜像提供包含 OpPlugin 源码的 torch_npu wheel 编译环境(不含 CANN),`dev` 镜像在此基础上叠加 CANN 运行环境。
4+ 
5+## 1 镜像介绍
6+ 
7+Dockerfile 采用多阶段构建,分为三个阶段:
8+ 
9+```Text
10+base manylinux + Python 软链接 + pip 源 + 基础系统包(curl/wget/git/libgomp...)
11+ └── builder base + gcc-toolset + cmake + PyTorch CPU 依赖(torch/numpy/pyyaml) ← 编译环境
12+ └── dev builder + CANN(Toolkit + Ops + NNAL 可选) ← 运行环境
13+```
14+ 
15+- **builder**(默认):用于编译包含当前 OpPlugin 源码的 torch_npu wheel,不含 CANN
16+- **dev**:基于 builder,叠加 CANN 运行环境;继承全部编译工具链,可在容器内直接编译和调试 OpPlugin
17+ 
18+> Dockerfile会自动根据当前架构(ARM/X86)拉取对应镜像。
19+> Driver 不包含在镜像中,用户需在宿主机自行安装。镜像仅提供 CANN 编译环境,运行时需宿主机已安装匹配的 NPU 驱动。
20+> 镜像中预装的 PyTorch CPU 版本默认为 v2.13.0 分支对应的版本(`torch==2.13.0`)。可通过构建参数 `TORCH_VERSION` 指定稳定版本(如 `2.7.1`),详见 [构建参数参考](#构建参数参考)。
21+ 
22+## 2 镜像构建
23+ 
24+```Shell
25+cd op-plugin/docker/devel
26+export DOCKER_BUILDKIT=1
27+```
28+ 
29+### 2.1 docker build 构建
30+ 
31+#### 构建参数参考
32+ 
33+| ARG | 默认值 | 说明 | 适用阶段 |
34+|-----|--------|------|---------|
35+| `PY_VERSION` | `3.10` | Python 版本,仅安装对应版本依赖 | all |
36+| `TORCH_VERSION` | `2.13.0` | PyTorch 版本,格式 `x.x.x`(如 `2.13.0`)或 dev 版本(如 `2.13.0.dev20260610`);dev 版本从 nightly 源安装 | all |
37+| `DEVTOOLSET_VERSION` | `13` | GCC toolset 版本 | builder |
38+| `CANN_VERSION` | `9.1.0_beta.1` | CANN 版本号 | dev |
39+| `CANN_PRODUCT` | `910b` | CANN 算子包产品类型 | dev |
40+| `INSTALL_NNAL` | `0` | 是否安装 NNAL 神经网络加速库 | dev |
41+| `CANN_RELEASE_TRAIN` | - | CANN 发布版本号,仅当`CANN_VERSION`与默认值不同时需手动指定 | dev |
42+ 
43+#### 使用示例
44+ 
45+##### 场景一:构建 builder 镜像
46+ 
47+```Shell
48+docker build -t op-plugin-builder:v1 \
49+ --target builder \
50+ --build-arg PY_VERSION=3.10 \
51+ .
52+```
53+ 
54+##### 场景二:构建 dev 镜像
55+ 
56+```Shell
57+docker build -t op-plugin-builder:v1 \
58+ --target dev \
59+ --build-arg PY_VERSION=3.10 \
60+ --build-arg CANN_VERSION=9.1.0_beta.1 \
61+ --build-arg CANN_PRODUCT=910b \
62+ .
63+```
64+ 
65+> dev 阶段基于 builder,继承全部编译工具和 Python 依赖,再叠加 CANN。
66+> 指定 CANN 版本时需同时给出 `CANN_RELEASE_TRAIN`,详见 [构建参数参考](#构建参数参考)。
67+> **关于 CANN 版本与 release train**:OBS 上的 CANN `.run` 包按 release train 分目录存放(如 `CANN%209.1.T1`、`CANN%209.0.0`),目录名无法由版本号自动推导。因此当 `CANN_VERSION` 与默认值 `9.1.0_beta.1` 不同时,必须同时通过 `CANN_RELEASE_TRAIN` 指定对应的发布版本号,否则构建会报错退出。请到 [昇腾官网下载页](https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/910beta1/softwareinst/instg/instg_0008.html?OS=openEuler&InstallType=local) 查找目标版本对应的目录名。
68+ 
69+#### CANN 产品映射
70+ 
71+| 产品代码 | 对应产品 |
72+|----------|----------|
73+| `910b` | Atlas A2 系列 |
74+| `910` | Atlas 训练系列 |
75+| `310p` | Atlas 推理系列 |
76+| `310b` | Atlas 200I/500 A2 推理 |
77+| `A3` | Atlas A3 系列 |
78+| `950` | Atlas 350 加速卡 |
79+ 
80+### 2.2 脚本构建
81+ 
82+> `builder.sh` 为 **Linux 构建脚本**,自动构建镜像并启动容器。
83+ 
84+#### 参数说明
85+ 
86+| 参数 | 说明 |
87+|------|------|
88+| `-p, --python VERSION` | Python 版本:3.10、3.11、3.12、3.13(默认:3.10) |
89+| `--torch-version VER` | PyTorch 版本,格式 `x.x.x`(如 `2.13.0`)或 dev 版本(如 `2.13.0.dev20260610`),默认:`2.13.0` |
90+| `--no-cache` | 构建镜像时不使用 Docker 缓存 |
91+| `--cann` | 构建 dev 镜像(含 CANN 运行环境),默认构建 builder 镜像 |
92+| `--cann-version VER` | CANN 版本(默认:9.1.0_beta.1) |
93+| `--cann-product PROD` | CANN 产品类型:950、A3、910b、910、310p、310b(默认:910b) |
94+| `--cann-release-train VER` | CANN 发布版本号,如 `CANN%209.1.T1`。当 `--cann-version` 与默认值不同时**必填** |
95+| `--nnal` | 安装 CANN NNAL 神经网络加速库(需配合 `--cann`) |
96+| `-h, --help` | 显示帮助信息 |
97+ 
98+#### 使用示例
99+ 
100+```Shell
101+bash builder.sh # 默认:Python 3.10,不含 CANN
102+bash builder.sh -p 3.11 # 使用 Python 3.11
103+bash builder.sh --cann # 含 CANN(默认 910b ops)
104+bash builder.sh --cann --cann-product A3 # 含 CANN for Atlas A3
105+bash builder.sh --cann --cann-version 9.0.0 \
106+ --cann-release-train CANN%209.0.0 \
107+ # 指定 CANN 版本(须同时给出对应release train)
108+bash builder.sh --cann --nnal # 含 CANN + NNAL
109+bash builder.sh --cann --no-cache # 含 CANN 且不使用缓存
110+```
111+ 
112+## 3 启动容器
113+ 
114+> torch_npu **编译**无需 CANN/驱动;CANN 与 NPU 驱动仅在**运行时**(`import torch_npu`、调用 NPU 算子)需要。因此根据镜像类型选择不同的启动方式。
115+>
116+> 若已通过 `builder.sh` 构建,脚本会自动构建镜像并启动容器,可直接执行下方的 `docker exec` 命令进入容器;本节其余命令仅适用于手动执行 `docker build` 后需自行启动容器的场景。
117+ 
118+### 场景一:builder 镜像
119+ 
120+仅需挂载源码,无需 NPU 驱动透传。以下命令须在 `op-plugin/docker/devel` 目录下执行,与手动构建步骤的工作目录一致:
121+ 
122+```Shell
123+docker rm -f op-plugin-builder 2>/dev/null
124+ 
125+docker run -d --rm \
126+ --name op-plugin-builder \
127+ -v $(pwd)/../..:/home/op-plugin \
128+ -e PY_VERSION=3.10 \
129+ op-plugin-builder:v1 \
130+ tail -f /dev/null
131+```
132+ 
133+### 场景二:dev 镜像
134+ 
135+需透传 NPU 驱动、设备节点与 npu-smi 工具:
136+ 
137+```Shell
138+docker rm -f op-plugin-builder 2>/dev/null
139+ 
140+docker run -d --rm \
141+ --name op-plugin-builder \
142+ --privileged \
143+ -v /dev:/dev \
144+ -v $(pwd)/../..:/home/op-plugin \
145+ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
146+ -v /usr/local/Ascend/add-ons:/usr/local/Ascend/add-ons \
147+ -v /usr/local/sbin/npu-smi:/usr/local/bin/npu-smi \
148+ -v /var/log/npu:/usr/slog \
149+ -e PY_VERSION=3.10 \
150+ -e LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/base:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver \
151+ op-plugin-builder:v1 \
152+ tail -f /dev/null
153+```
154+ 
155+参数说明:
156+ 
157+| 参数 | 用途 |
158+|------|------|
159+| `--privileged -v /dev:/dev` | 透传全部 NPU 字符设备(davinci*/davinci_manager/devmm_svm/hisi_hdc),避免逐个 `--device` |
160+| `-v /usr/local/Ascend/driver` | 宿主机驱动库与 firmware,CANN 运行时依赖 |
161+| `-v /usr/local/Ascend/add-ons` | 驱动附加组件(如 profiler) |
162+| `-v /usr/local/sbin/npu-smi` | NPU 状态查看工具(依赖 driver/lib64 下的 so) |
163+| `-v /var/log/npu` | NPU 日志输出目录 |
164+| `-e LD_LIBRARY_PATH=...` | 让 npu-smi 与 CANN 找到 `libc_sec.so`/`libdrvdsmi_host.so` 等依赖 |
165+ 
166+验证容器内 NPU 可见:
167+ 
168+```Shell
169+docker exec op-plugin-builder npu-smi info
170+```
171+ 
172+若输出 NPU 卡列表则挂载成功。
173+ 
174+> `--privileged` 仅用于简化设备透传。如需最小权限,可改为显式 `--device=/dev/davinci0 --device=/dev/davinci_manager --device=/dev/devmm_svm --device=/dev/hisi_hdc`(每张卡需单独 `--device`)。
175+ 
176+进入容器:
177+ 
178+```Shell
179+docker exec -it op-plugin-builder bash
180+```
181+ 
182+进入容器后,切换到 OpPlugin 源码目录:
183+ 
184+```Shell
185+cd /home/op-plugin
186+```
187+ 
188+执行 OpPlugin 构建:
189+ 
190+```Shell
191+bash ci/build.sh --python=3.10
192+```
193+ 
194+构建完成后,生成的 wheel 位于 dist 目录:
195+ 
196+```Shell
197+ls -lh dist/
198+```
199+ 
200+## 附录:Windows 环境参考
201+ 
202+> 本附录仅供 Windows 用户参考。Windows 上 `builder.sh` 依赖的 bash 通常不可用(WSL 入口 `bash.exe` 默认指向 `docker-desktop` 分发,非完整 Linux),且 MSYS 路径转换会导致 `docker run -v` 挂载失败,建议直接使用 PowerShell 等价命令执行前文所述流程。
203+ 
204+Windows 下命令格式与 Linux 的主要差异:
205+ 
206+- **工作目录**:需进入 `op-plugin\docker\devel` 目录。
207+- **路径分隔符**:使用反斜杠 `\`,而非正斜杠 `/`
208+- **续行符**:PowerShell 使用反引号 `` ` ``,而非反斜杠 `\`。
209+- **挂载路径**:使用 Windows 风格(`E:\...`),Docker Desktop for Windows 会自动转换;切勿使用 MSYS 风格(`/e/...`)。
210+- **错误重定向**:删除已存在容器时使用 `2>$null` 而非 `2>/dev/null` 屏蔽错误输出。
211+ 
212+请参照前文 Linux 流程,将相关命令按上述规则改写为 PowerShell 等价命令执行。
@@ -0,0 +1,225 @@
1+#!/bin/bash
2+ 
3+set -euo pipefail
4+ 
5+SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
6+IMAGE_NAME="op-plugin-builder"
7+IMAGE_TAG="v1"
8+CONTAINER_NAME="op-plugin-builder"
9+ 
10+PY_VERSION="3.10"
11+INSTALL_CANN=0
12+CANN_VERSION="9.1.0_beta.1"
13+CANN_PRODUCT="910b"
14+INSTALL_NNAL=0
15+NO_CACHE=0
16+CANN_RELEASE_TRAIN=""
17+IMAGE_TARGET="builder"
18+TORCH_VERSION="2.13.0"
19+ 
20+function usage() {
21+ cat <<EOF
22+Usage: $0 [OPTIONS]
23+ 
24+Options:
25+ -p, --python VERSION Python version: 3.10 3.11 3.12 3.13 3.14 (default: 3.10)
26+ --torch-version VER PyTorch version: x.x.x (e.g. 2.7.1, 2.12.0) or dev version (e.g. 2.13.0.dev20260610) (default: 2.13.0)
27+ --no-cache Build docker image without cache
28+ -h, --help Show this help message
29+ 
30+CANN Options:
31+ --cann Build dev image with CANN (default: builder image without CANN)
32+ --cann-version VER CANN version (default: 9.1.0_beta.1)
33+ --cann-product PROD CANN product: 950, A3, 910b, 910, 310p, 310b (default: 910b)
34+ --cann-release-train VER CANN release train, e.g. CANN%209.1.T1 (required when --cann-version != default)
35+ --nnal Install CANN NNAL (requires --cann)
36+ 
37+Examples:
38+ $0 Build image & launch container with default python 3.10
39+ $0 -p 3.11 Use python 3.11
40+ $0 --cann Build with CANN (default: 910b ops)
41+ $0 --cann --cann-product A3 Build with CANN for Atlas A3
42+ $0 --cann --nnal Build with CANN + NNAL
43+ $0 --cann --cann-version 9.0.0 --cann-release-train CANN%209.0.0
44+ Build with CANN 9.0.0 (release train is version-specific)
45+ 
46+EOF
47+ exit 0
atomgit-bot
atomgit-botatomgit-bot7月20日

🟡 Medium Priority

usage() 函数(第20-48行)函数体末尾固定执行 exit 0,忽略调用方传入的参数。

  • 第85行 -h | --help 分支调用 usage 0,期望退出码 0 —— 行为正确。
  • 第89行未知选项分支调用 usage 1,期望退出码非零以表示错误,但因为函数体内是硬编码的 exit 0,实际仍然以 0 退出。

后果:当用户输入非法选项时,脚本打印帮助信息但以成功状态退出,调用方(如 CI 流水线、外部脚本检测 $?)无法感知到输入错误,可能掩盖配置问题。

建议:将 exit 0 改为 exit "${1:-0}",使调用方传入的退出码生效;同时无参调用时默认退出 0 保持兼容。

likedislike
不准确?
48+}
49+ 
50+while [[ $# -gt 0 ]]; do
51+ case "$1" in
52+ -p | --python)
53+ PY_VERSION="$2"
54+ shift 2
55+ ;;
56+ --no-cache)
57+ NO_CACHE=1
58+ shift
59+ ;;
60+ --torch-version)
61+ TORCH_VERSION="$2"
62+ shift 2
63+ ;;
64+ --cann)
65+ INSTALL_CANN=1
66+ shift
67+ ;;
68+ --cann-version)
69+ CANN_VERSION="$2"
70+ shift 2
71+ ;;
72+ --cann-product)
73+ CANN_PRODUCT="$2"
74+ shift 2
75+ ;;
76+ --cann-release-train)
77+ CANN_RELEASE_TRAIN="$2"
78+ shift 2
79+ ;;
80+ --nnal)
81+ INSTALL_NNAL=1
82+ shift
83+ ;;
84+ -h | --help)
85+ usage 0
86+ ;;
87+ *)
88+ echo "Unknown option: $1"
89+ usage 1
90+ ;;
91+ esac
92+done
93+ 
94+if [ "${INSTALL_NNAL}" -eq 1 ] && [ "${INSTALL_CANN}" -ne 1 ]; then
95+ echo "ERROR: --nnal requires --cann"
96+ exit 1
97+fi
98+ 
99+DEFAULT_CANN_VERSION="9.1.0_beta.1"
100+DEFAULT_CANN_RELEASE_TRAIN="CANN%209.1.T1"
101+if [ "${INSTALL_CANN}" -eq 1 ] && [ "${CANN_VERSION}" != "${DEFAULT_CANN_VERSION}" ] && [ -z "${CANN_RELEASE_TRAIN}" ]; then
102+ echo "ERROR: --cann-version '${CANN_VERSION}' requires --cann-release-train"
103+ echo " The OBS directory name is version-specific and cannot be derived from the version string."
104+ echo " Look up the correct release train at https://www.hiascend.com/ and pass it via --cann-release-train."
105+ echo " Example: --cann-release-train ${DEFAULT_CANN_RELEASE_TRAIN}"
106+ exit 1
107+fi
108+ 
109+VALID_CANN_PRODUCTS="950 A3 910b 910 310p 310b"
110+if [ "${INSTALL_CANN}" -eq 1 ]; then
111+ found=0
112+ for p in ${VALID_CANN_PRODUCTS}; do
113+ if [ "${CANN_PRODUCT}" = "${p}" ]; then
114+ found=1
115+ break
116+ fi
117+ done
118+ if [ "${found}" -eq 0 ]; then
119+ echo "ERROR: invalid --cann-product '${CANN_PRODUCT}', must be one of: ${VALID_CANN_PRODUCTS}"
120+ exit 1
121+ fi
122+fi
123+ 
124+ARCH=$(uname -m)
125+DOCKERFILE_DIR="${SCRIPT_DIR}"
126+ 
127+if [ ! -f "${DOCKERFILE_DIR}/Dockerfile" ]; then
128+ echo "Dockerfile not found: ${DOCKERFILE_DIR}/Dockerfile"
129+ exit 1
130+fi
131+ 
132+SOURCE_DIR=$(cd "${SCRIPT_DIR}/../.." && pwd)
133+if [ ! -d "${SOURCE_DIR}" ]; then
134+ echo "Source directory not found: ${SOURCE_DIR}"
135+ exit 1
136+fi
137+ 
138+BUILD_ARGS=""
139+BUILD_ARGS="${BUILD_ARGS} --build-arg PY_VERSION=${PY_VERSION}"
140+BUILD_ARGS="${BUILD_ARGS} --build-arg TORCH_VERSION=${TORCH_VERSION}"
141+if [ "${INSTALL_CANN}" -eq 1 ]; then
142+ IMAGE_TARGET="dev"
143+ BUILD_ARGS="${BUILD_ARGS} --build-arg CANN_VERSION=${CANN_VERSION}"
144+ BUILD_ARGS="${BUILD_ARGS} --build-arg CANN_PRODUCT=${CANN_PRODUCT}"
145+ if [ -n "${CANN_RELEASE_TRAIN}" ]; then
146+ BUILD_ARGS="${BUILD_ARGS} --build-arg CANN_RELEASE_TRAIN=${CANN_RELEASE_TRAIN}"
147+ fi
148+fi
149+if [ "${INSTALL_NNAL}" -eq 1 ]; then
150+ BUILD_ARGS="${BUILD_ARGS} --build-arg INSTALL_NNAL=1"
151+fi
152+if [ "${NO_CACHE}" -eq 1 ]; then
153+ BUILD_ARGS="${BUILD_ARGS} --no-cache"
154+fi
155+ 
156+echo "=========================================="
157+echo " Building docker image: ${IMAGE_NAME}:${IMAGE_TAG}"
158+echo " Architecture: ${ARCH}"
159+echo " Dockerfile: ${DOCKERFILE_DIR}/Dockerfile"
160+echo " Target: ${IMAGE_TARGET}"
161+echo " Python: ${PY_VERSION}"
162+echo " Torch: ${TORCH_VERSION}"
163+if [ "${INSTALL_CANN}" -eq 1 ]; then
164+ echo " CANN: ${CANN_VERSION} (${CANN_PRODUCT})"
165+ if [ -n "${CANN_RELEASE_TRAIN}" ]; then
166+ echo " CANN Release: ${CANN_RELEASE_TRAIN}"
167+ fi
168+ if [ "${INSTALL_NNAL}" -eq 1 ]; then
169+ echo " NNAL: enabled"
170+ fi
171+fi
172+echo "=========================================="
173+docker build ${BUILD_ARGS} --target ${IMAGE_TARGET} -t "${IMAGE_NAME}:${IMAGE_TAG}" "${DOCKERFILE_DIR}" || {
174+ echo "Failed to build docker image."
175+ exit 1
176+}
177+echo "Docker image built successfully: ${IMAGE_NAME}:${IMAGE_TAG}"
178+ 
179+echo "=========================================="
180+echo " Launching container: ${CONTAINER_NAME}"
181+echo " Source: ${SOURCE_DIR} -> /home/op-plugin"
182+echo " Python: ${PY_VERSION}"
183+if [ "${INSTALL_CANN}" -eq 1 ]; then
184+ echo " Mode: runtime (with NPU driver passthrough)"
185+else
186+ echo " Mode: compile-only (no NPU driver)"
187+fi
188+echo "=========================================="
189+ 
190+docker rm -f "${CONTAINER_NAME}" 2>/dev/null || true
191+if [ "${INSTALL_CANN}" -eq 1 ]; then
192+ docker run -d --rm \
193+ --name "${CONTAINER_NAME}" \
194+ --privileged \
195+ -v /dev:/dev \
196+ -v "${SOURCE_DIR}:/home/op-plugin" \
197+ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
198+ -v /usr/local/Ascend/add-ons:/usr/local/Ascend/add-ons \
199+ -v /usr/local/sbin/npu-smi:/usr/local/bin/npu-smi \
200+ -v /var/log/npu:/usr/slog \
201+ -e PY_VERSION="${PY_VERSION}" \
202+ -e LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/base:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver \
atomgit-bot
atomgit-botatomgit-bot7月20日

🟡 Medium Priority

builder.sh 第202行启动 dev 容器时使用 -e LD_LIBRARY_PATH=... 完全覆盖容器的 LD_LIBRARY_PATH 环境变量,而不是追加。

Dockerfile builder 阶段(第72-73行)通过 ENV 设置了 gcc-toolset 的库路径: 这是编译 OpPlugin 所必需的。dev 阶段继承该 ENV。

但当 builder.sh 启动 dev 容器时,-e LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:... 完全替换了容器内原有的 LD_LIBRARY_PATH,gcc-toolset 路径丢失。而 .bashrc(Dockerfile 第128行)只补充 CANN 路径,不补充 gcc-toolset 路径。

对照 devcontainer.json(第26行)使用 ${containerEnv:LD_LIBRARY_PATH}:... 追加方式,正确保留了容器原始路径。

后果:通过 builder.sh 启动 dev 容器后,用户在容器内编译 OpPlugin 时,链接器找不到 gcc-toolset 提供的 libstdc++/libgcc 等库,编译可能失败。

建议:将 -e LD_LIBRARY_PATH=... 改为 -e LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:...:\$LD_LIBRARY_PATH(注意反斜杠转义 $),使驱动库路径追加到容器原有 LD_LIBRARY_PATH 之前,同时保留 gcc-toolset 路径。这与 devcontainer.json 的做法一致。

改动建议
202
- -e LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/base:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver \
202
+ -e LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/base:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:\$LD_LIBRARY_PATH \
应用建议
likedislike
不准确?
203+ "${IMAGE_NAME}:${IMAGE_TAG}" \
204+ tail -f /dev/null
205+else
206+ docker run -d --rm \
207+ --name "${CONTAINER_NAME}" \
208+ -v "${SOURCE_DIR}:/home/op-plugin" \
209+ -e PY_VERSION="${PY_VERSION}" \
210+ "${IMAGE_NAME}:${IMAGE_TAG}" \
211+ tail -f /dev/null
212+fi
213+ 
214+echo ""
215+echo "Container started. To enter:"
216+echo " docker exec -it ${CONTAINER_NAME} bash"
217+echo ""
218+if [ "${INSTALL_CANN}" -eq 1 ]; then
219+ echo "Verify NPU visible:"
220+ echo " docker exec ${CONTAINER_NAME} npu-smi info"
221+ echo ""
222+fi
223+echo "Then run (inside container):"
224+echo " cd /home/op-plugin"
225+echo " bash ci/build.sh --python=${PY_VERSION}"