#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
HOST_MACHINE="$(uname -m)"
case "$HOST_MACHINE" in
x86_64|amd64)
CANN_ARCH_DIR="x86_64-linux"
;;
aarch64|arm64)
CANN_ARCH_DIR="aarch64-linux"
;;
*)
echo "不支持的主机 CPU 架构: '$HOST_MACHINE',可选值: x86_64, aarch64" >&2
exit 1
;;
esac
SOC="ascend910b"
OP_NAME=""
while [[ $# -gt 0 ]]; do
case "$1" in
--soc)
if [ $# -lt 2 ] || [[ "$2" == -* ]]; then
echo "错误: --soc 需要一个参数,可选值: ascend910b, ascend910_93, ascend950" >&2
exit 1
fi
SOC="$2"
shift 2
;;
--soc=*)
SOC="${1#*=}"
shift
;;
-*)
echo "未知选项: $1" >&2
echo "用法: bash ops_build.sh [--soc ascend910b|ascend910_93|ascend950] [<op>]" >&2
exit 1
;;
*)
OP_NAME="$1"
shift
;;
esac
done
case "$SOC" in
ascend910b) NPU_ARCH="dav-2201" ;;
ascend910_93) NPU_ARCH="dav-2201" ;;
ascend950) NPU_ARCH="dav-3510" ;;
*)
echo "不支持的 SOC: '$SOC',可选值: ascend910b, ascend910_93, ascend950" >&2
exit 1
;;
esac
echo "[1/4] 加载 CANN 环境..."
if [ -z "${ASCEND_HOME_PATH:-}" ]; then
echo "错误: 环境变量 ASCEND_HOME_PATH 未设置,请先 source CANN 的 set_env.sh 或导出该变量" >&2
exit 1
fi
if [ ! -f "$ASCEND_HOME_PATH/set_env.sh" ]; then
echo "错误: '$ASCEND_HOME_PATH/set_env.sh' 不存在,请检查 CANN 安装路径" >&2
exit 1
fi
source "$ASCEND_HOME_PATH/set_env.sh"
echo "[2/4] 编译算子 (HOST=${HOST_MACHINE}, CANN_ARCH_DIR=${CANN_ARCH_DIR}, SOC=${SOC}, NPU_ARCH=${NPU_ARCH})..."
build_op() {
local op_name="$1"
local op_dir="$SCRIPT_DIR/$op_name"
echo " 编译 $op_name ..."
rm -rf "$op_dir/build" && mkdir "$op_dir/build"
cmake -S "$op_dir" -B "$op_dir/build" \
-DCMAKE_BUILD_TYPE=Release \
-DNPU_ARCH="${NPU_ARCH}" \
-DASCEND_ARCH_DIR="${CANN_ARCH_DIR}" > /dev/null
cmake --build "$op_dir/build" -j"$(nproc)"
}
if [ -n "$OP_NAME" ]; then
build_op "$OP_NAME"
else
for op in */; do
op="${op%/}"
[ -f "$op/CMakeLists.txt" ] && build_op "$op"
done
fi
echo "[3/4] 汇集 Python 包到 staging/..."
rm -rf staging && mkdir -p staging/amct_ops
cp "$SCRIPT_DIR/ops_init.py" staging/amct_ops/__init__.py
collect_op() {
local op_name="$1"
local op_dir="$SCRIPT_DIR/$op_name"
local python_src="$op_dir/python"
[ -d "$python_src" ] || return
for pkg_dir in "$python_src"/*/; do
[ -d "$pkg_dir" ] || continue
local pkg_name
pkg_name="$(basename "$pkg_dir")"
[[ "$pkg_name" == _* || "$pkg_name" == .* ]] && continue
local dst="staging/amct_ops/$pkg_name"
mkdir -p "$dst"
find "$pkg_dir" -maxdepth 1 -name "*.py" -exec cp {} "$dst/" \;
[ -d "$op_dir/build" ] && find "$op_dir/build" -maxdepth 1 -name "*.so" -exec cp {} "$dst/" \;
echo " $op_name → staging/amct_ops/$pkg_name/ ($(ls "$dst"/*.so 2>/dev/null | wc -l) .so)"
done
}
if [ -n "$OP_NAME" ]; then
collect_op "$OP_NAME"
for op in */; do
op="${op%/}"
[ "$op" = "$OP_NAME" ] && continue
[ -d "$op/python" ] && collect_op "$op"
done
else
for op in */; do
op="${op%/}"
[ -d "$op/python" ] && collect_op "$op"
done
fi
echo "[4/4] 构建 wheel..."
rm -rf dist amct_ops.egg-info build
mkdir -p dist
pip wheel . -w dist/ --no-deps --no-build-isolation -q
echo ""
echo "构建完成:"
ls -lh dist/amct_ops-*.whl
echo ""
echo "内容:"
python3 -m zipfile -l dist/amct_ops-*.whl | grep -v "dist-info"
echo ""
echo "安装方式: pip install dist/amct_ops-*.whl"