#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
ERROR_COUNT=0
WARNING_COUNT=0
PASS_COUNT=0
REQUIRED_GCC_MIN="7.3.0"
REQUIRED_PYTHON_MIN="3.9.0"
REQUIRED_CMAKE_MIN="3.16.0"
REQUIRED_CMAKE_RECOMMEND="3.20.0"
log_pass() {
PASS_COUNT=$((PASS_COUNT + 1))
echo -e " ${GREEN}[PASS]${NC} $1"
}
log_warn() {
WARNING_COUNT=$((WARNING_COUNT + 1))
echo -e " ${YELLOW}[WARNING]${NC} $1"
}
log_error() {
ERROR_COUNT=$((ERROR_COUNT + 1))
echo -e " ${RED}[ERROR]${NC} $1"
}
log_info() {
echo -e " ${BLUE}[INFO]${NC} $1"
}
version_ge() {
[ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$2" ]
}
check_command() {
command -v "$1" &>/dev/null
}
pkg_install_hint() {
local apt_pkg="$1"
local yum_pkg="$2"
case "$DISTRO" in
ubuntu|debian)
log_info "安装: sudo apt-get install $apt_pkg"
;;
centos|rhel|fedora|euleros|openeuler)
log_info "安装: sudo $PKG_MGR install $yum_pkg"
;;
*)
log_info "安装 (Ubuntu/Debian): sudo apt-get install $apt_pkg"
log_info "安装 (CentOS/EulerOS): sudo yum install $yum_pkg"
;;
esac
}
extract_version() {
local input="$1"
local ver
ver=$(echo "$input" | grep -oP '\d+\.\d+(\.\d+)*' | head -n1 || true)
if [ -z "$ver" ]; then
ver=$(echo "$input" | grep -oP '\d+' | head -n1 || true)
if [ -n "$ver" ]; then
ver="${ver}.0.0"
else
echo "0.0.0"
return
fi
fi
if [[ "$ver" =~ ^[0-9]+\.[0-9]+$ ]]; then
ver="${ver}.0"
fi
echo "$ver"
}
print_header() {
echo ""
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE} $1${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}
echo ""
echo "=================================================================="
echo " metadef 编译环境依赖检查"
echo " 仓库: 项目源码仓库(metadef 模块)"
echo " 依据: docs/build.md"
echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo " 系统: $(uname -s) $(uname -m)"
echo "=================================================================="
print_header "1. 操作系统 [可选]"
OS_NAME=$(uname -s)
OS_ARCH=$(uname -m)
if [ "$OS_NAME" = "Linux" ]; then
log_info "操作系统: Linux"
else
log_info "其他操作系统: $OS_NAME"
fi
if [ "$OS_ARCH" = "x86_64" ] || [ "$OS_ARCH" = "aarch64" ]; then
log_info "CPU 架构: $OS_ARCH"
else
log_info "其他CPU架构: $OS_ARCH (build.md 验证过 x86_64/aarch64)"
fi
if [ -f /etc/os-release ]; then
DISTRO=$(grep "^ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
DISTRO_VER=$(grep "^VERSION_ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
log_info "发行版: $DISTRO $DISTRO_VER"
fi
case "$DISTRO" in
ubuntu|debian)
PKG_MGR="apt-get"
;;
centos|rhel|fedora)
PKG_MGR="yum"
;;
euleros|openeuler)
if check_command dnf; then
PKG_MGR="dnf"
else
PKG_MGR="yum"
fi
;;
*)
PKG_MGR="yum"
log_info "未识别的发行版, 安装提示将同时给出 apt/yum 两种方案"
;;
esac
if [ -n "$DISTRO" ]; then
log_info "包管理器: $PKG_MGR"
fi
print_header "2. GCC/G++ [build.md: >= $REQUIRED_GCC_MIN]"
if check_command gcc; then
GCC_RAW=$(gcc -dumpversion)
GCC_VER=$(extract_version "$GCC_RAW")
log_info "gcc -dumpversion: $GCC_RAW → $GCC_VER"
if version_ge "$GCC_VER" "$REQUIRED_GCC_MIN"; then
log_pass "GCC $GCC_VER (>= $REQUIRED_GCC_MIN)"
else
log_error "GCC 版本过低: $GCC_VER (build.md 要求 >= $REQUIRED_GCC_MIN)"
pkg_install_hint "build-essential" "gcc gcc-c++"
case "$DISTRO" in
centos|rhel) log_info " (CentOS 7 可用 SCL: sudo yum install devtoolset-7-gcc devtoolset-7-gcc-c++)" ;;
esac
fi
else
log_error "未安装 GCC (build.md 要求 >= $REQUIRED_GCC_MIN)"
pkg_install_hint "build-essential" "gcc gcc-c++"
fi
if check_command g++; then
GPP_RAW=$(g++ -dumpversion)
GPP_VER=$(extract_version "$GPP_RAW")
log_pass "G++ $GPP_VER"
else
log_error "未安装 G++"
pkg_install_hint "g++" "gcc-c++"
fi
print_header "3. Python3 [build.md: >= $REQUIRED_PYTHON_MIN]"
PYTHON_CMD=""
if check_command python3; then
PYTHON_CMD="python3"
PYTHON_RAW=$($PYTHON_CMD --version 2>&1)
PYTHON_VER=$(extract_version "$PYTHON_RAW")
elif check_command python; then
PYTHON_CMD="python"
PYTHON_RAW=$($PYTHON_CMD --version 2>&1)
PYTHON_VER=$(extract_version "$PYTHON_RAW")
fi
if [ -n "$PYTHON_CMD" ]; then
log_info "$PYTHON_CMD --version: $PYTHON_RAW → $PYTHON_VER"
if version_ge "$PYTHON_VER" "$REQUIRED_PYTHON_MIN"; then
log_pass "Python $PYTHON_VER (>= $REQUIRED_PYTHON_MIN)"
else
log_error "Python 版本过低: $PYTHON_VER (build.md 要求 >= $REQUIRED_PYTHON_MIN)"
log_info "请安装 Python 3.9 或更高版本"
fi
PYTHON_INCLUDE=$($PYTHON_CMD -c "import sysconfig; print(sysconfig.get_path('include'))" 2>/dev/null || true)
if [ -n "$PYTHON_INCLUDE" ] && [ -f "$PYTHON_INCLUDE/Python.h" ]; then
log_pass "Python 开发头文件: $PYTHON_INCLUDE/Python.h"
else
log_error "缺少 Python.h"
pkg_install_hint "python3-dev" "python3-devel"
fi
else
log_error "未安装 Python3 (build.md 要求 >= $REQUIRED_PYTHON_MIN)"
pkg_install_hint "python3 python3-dev" "python3 python3-devel"
fi
print_header "4. CMake [build.md: >= $REQUIRED_CMAKE_MIN, 建议 $REQUIRED_CMAKE_RECOMMEND]"
if check_command cmake; then
CMAKE_RAW=$(cmake --version | head -n1)
CMAKE_VER=$(extract_version "$CMAKE_RAW")
log_info "cmake --version: $CMAKE_RAW → $CMAKE_VER"
if version_ge "$CMAKE_VER" "$REQUIRED_CMAKE_RECOMMEND"; then
log_pass "CMake $CMAKE_VER (>= 建议版本 $REQUIRED_CMAKE_RECOMMEND)"
elif version_ge "$CMAKE_VER" "$REQUIRED_CMAKE_MIN"; then
log_pass "CMake $CMAKE_VER (>= $REQUIRED_CMAKE_MIN)"
log_warn "build.md 建议使用 CMake $REQUIRED_CMAKE_RECOMMEND, 当前 $CMAKE_VER"
else
log_error "CMake 版本过低: $CMAKE_VER (build.md 要求 >= $REQUIRED_CMAKE_MIN)"
log_info "升级 (pip): pip install cmake --upgrade"
log_info "升级 (源码): CMake 官方下载页面获取最新版本"
fi
else
log_error "未安装 CMake (build.md 要求 >= $REQUIRED_CMAKE_MIN)"
pkg_install_hint "cmake" "cmake"
log_info "安装 (pip): pip install cmake"
fi
print_header "5. ccache [build.md: 必需]"
if check_command ccache; then
CCACHE_RAW=$(ccache --version | head -n1)
CCACHE_VER=$(extract_version "$CCACHE_RAW")
log_info "ccache --version: $CCACHE_RAW → $CCACHE_VER"
log_pass "ccache $CCACHE_VER"
else
log_error "未安装 ccache (build.md 要求安装)"
pkg_install_hint "ccache" "ccache"
fi
print_header "6. lcov [build.md: 非必需 (cov, 用于代码覆盖率)]"
if check_command lcov; then
LCOV_RAW=$(lcov --version 2>&1 | head -n1)
LCOV_VER=$(extract_version "$LCOV_RAW")
log_info "lcov --version: $LCOV_RAW → $LCOV_VER"
log_pass "lcov $LCOV_VER"
else
log_warn "未安装 lcov (非必需, 仅用于代码覆盖率统计, 不影响编译)"
pkg_install_hint "lcov" "lcov"
fi
if check_command genhtml; then
log_pass "genhtml 已安装 (lcov 附带)"
else
log_warn "genhtml 未找到 (通常随 lcov 一起安装)"
fi
print_header "7. libasan [build.md: 必需 (asan)]"
ASAN_FOUND=false
for path in /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 \
/usr/lib/x86_64-linux-gnu /usr/lib/aarch64-linux-gnu \
/usr/lib/gcc/x86_64-linux-gnu/*/ /usr/lib/gcc/aarch64-linux-gnu/*/; do
if ls "$path"/libasan.so* &>/dev/null 2>&1; then
ASAN_FOUND=true
ASAN_PATH="$path"
break
fi
done
if $ASAN_FOUND; then
log_pass "libasan 已安装 ($ASAN_PATH)"
else
log_error "未安装 libasan (build.md 要求安装, 用于地址消毒器)"
log_info "build.md 原文: 'asan以gcc 7.5.0版本为例,其他版本请安装对应版本asan'"
if check_command gcc; then
GCC_MAJOR=$(gcc -dumpversion | cut -d'.' -f1)
else
GCC_MAJOR=""
fi
case "$DISTRO" in
ubuntu|debian)
case "$GCC_MAJOR" in
7) apt_asan="libasan4" ;;
8|9) apt_asan="libasan5" ;;
10|11) apt_asan="libasan6" ;;
12|13) apt_asan="libasan8" ;;
*) apt_asan="libasan" ;;
esac
log_info ">>> 当前 GCC ${GCC_MAJOR:-未知}, 建议: sudo apt-get install $apt_asan"
;;
centos|rhel|fedora|euleros|openeuler)
log_info ">>> 当前 GCC ${GCC_MAJOR:-未知}, 建议: sudo $PKG_MGR install libasan"
;;
*)
log_info "安装 (Ubuntu/Debian): sudo apt-get install libasan4 (随 GCC 版本: 4/5/6/8)"
log_info "安装 (CentOS/EulerOS): sudo yum install libasan"
;;
esac
fi
print_header "8. graph-easy [build.md: 可选]"
if check_command graph-easy; then
log_pass "graph-easy 已安装"
else
log_info "graph-easy 未安装 (build.md 标记为可选, 不影响编译)"
pkg_install_hint "libgraph-easy-perl" "perl-Graph-Easy"
fi
print_header "9. CANN Toolkit [build.md: 步骤二, 必需]"
ASCEND_HOME=""
if [ -n "$ASCEND_HOME_PATH" ]; then
ASCEND_HOME="$ASCEND_HOME_PATH"
elif [ -d "/usr/local/Ascend/ascend-toolkit/latest" ]; then
ASCEND_HOME="/usr/local/Ascend/ascend-toolkit/latest"
elif [ -d "$HOME/Ascend/ascend-toolkit/latest" ]; then
ASCEND_HOME="$HOME/Ascend/ascend-toolkit/latest"
elif [ -d "/usr/local/Ascend/latest" ]; then
ASCEND_HOME="/usr/local/Ascend/latest"
fi
if [ -n "$ASCEND_HOME" ] && [ -d "$ASCEND_HOME" ]; then
log_pass "CANN Toolkit 路径: $ASCEND_HOME"
if [ -f "$ASCEND_HOME/version.cfg" ]; then
CANN_VER=$(head -n1 "$ASCEND_HOME/version.cfg")
log_info "CANN 版本: $CANN_VER"
fi
SET_ENV_FOUND=false
for env_script in \
"/usr/local/Ascend/cann/set_env.sh" \
"$HOME/Ascend/cann/set_env.sh" \
"$ASCEND_HOME/bin/setenv.bash" \
"$ASCEND_HOME/../set_env.sh"; do
if [ -f "$env_script" ]; then
SET_ENV_FOUND=true
log_pass "set_env.sh 存在: $env_script"
break
fi
done
if ! $SET_ENV_FOUND; then
log_warn "未找到 set_env.sh"
log_info "build.md: source /usr/local/Ascend/cann/set_env.sh"
fi
if [ -n "$ASCEND_TOOLKIT_HOME" ]; then
log_pass "ASCEND_TOOLKIT_HOME 已设置: $ASCEND_TOOLKIT_HOME"
else
log_warn "ASCEND_TOOLKIT_HOME 未设置 (请先 source set_env.sh)"
log_info "build.md: source /usr/local/Ascend/cann/set_env.sh"
fi
if echo "$LD_LIBRARY_PATH" | grep -q "Ascend" 2>/dev/null; then
log_pass "LD_LIBRARY_PATH 包含 Ascend 路径"
else
log_warn "LD_LIBRARY_PATH 未包含 Ascend 路径 (请先 source set_env.sh)"
fi
else
log_error "未检测到 CANN Toolkit"
log_info "build.md 步骤二: 安装社区版 CANN Toolkit 包"
log_info "下载: https://ascend.devcloud.huaweicloud.com/artifactory/cann-run-mirror/software/master/"
log_info "安装: ./Ascend-cann-toolkit_xxx_linux-xxx.run --full"
log_info "然后: source /usr/local/Ascend/cann/set_env.sh"
fi
print_header "10. 基础构建工具"
if check_command make; then
MAKE_RAW=$(make --version | head -n1)
MAKE_VER=$(extract_version "$MAKE_RAW")
log_pass "make $MAKE_VER"
else
log_error "未安装 make"
pkg_install_hint "make" "make"
fi
if check_command git; then
GIT_RAW=$(git --version)
GIT_VER=$(extract_version "$GIT_RAW")
log_pass "git $GIT_VER"
else
log_error "未安装 git (build.md 步骤三需要 git clone)"
pkg_install_hint "git" "git"
fi
if [ -n "$PYTHON_CMD" ]; then
if $PYTHON_CMD -m pip --version &>/dev/null; then
PIP_RAW=$($PYTHON_CMD -m pip --version)
PIP_VER=$(extract_version "$PIP_RAW")
log_pass "pip $PIP_VER"
else
log_warn "pip 未安装"
log_info "安装: $PYTHON_CMD -m ensurepip --upgrade"
fi
fi
if check_command patch; then
PATCH_RAW=$(patch --version 2>&1 | head -n1)
PATCH_VER=$(extract_version "$PATCH_RAW")
log_pass "patch $PATCH_VER"
else
log_error "未安装 patch (应用补丁文件需要)"
pkg_install_hint "patch" "patch"
fi
print_header "11. 系统资源 [可选]"
DISK_AVAIL=$(df -BG . 2>/dev/null | tail -1 | awk '{print $4}' | tr -d 'G' || echo "0")
if [ "$DISK_AVAIL" -gt 10 ] 2>/dev/null; then
log_info "可用磁盘: ${DISK_AVAIL}GB"
elif [ "$DISK_AVAIL" -gt 5 ] 2>/dev/null; then
log_info "磁盘偏少: ${DISK_AVAIL}GB (建议 >10GB)"
else
log_info "磁盘不足: ${DISK_AVAIL}GB"
fi
if [ -f /proc/meminfo ]; then
MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
MEM_GB=$((MEM_KB / 1024 / 1024))
if [ "$MEM_GB" -ge 8 ]; then
log_info "内存: ${MEM_GB}GB"
elif [ "$MEM_GB" -ge 4 ]; then
log_info "内存偏少: ${MEM_GB}GB (推荐 >=8GB)"
else
log_info "内存不足: ${MEM_GB}GB"
fi
fi
CPU_CORES=$(nproc 2>/dev/null || echo "unknown")
log_info "CPU 核心数: $CPU_CORES"
APT_ASAN_PKG="libasan4"
if check_command gcc; then
GCC_MAJOR_FOR_ASAN=$(gcc -dumpversion | cut -d'.' -f1)
case "$GCC_MAJOR_FOR_ASAN" in
7) APT_ASAN_PKG="libasan4" ;;
8|9) APT_ASAN_PKG="libasan5" ;;
10|11) APT_ASAN_PKG="libasan6" ;;
12|13) APT_ASAN_PKG="libasan8" ;;
*) APT_ASAN_PKG="libasan" ;;
esac
fi
echo ""
echo "=================================================================="
echo " metadef 环境检查完成"
echo " 依据: https://gitcode.com/cann/metadef/blob/master/docs/build.md"
echo "=================================================================="
echo ""
[ $ERROR_COUNT -gt 0 ] && echo -e " ${RED}✗ ERRORS: $ERROR_COUNT${NC} (必须修复才能编译)"
[ $WARNING_COUNT -gt 0 ] && echo -e " ${YELLOW}⚠ WARNINGS: $WARNING_COUNT${NC} (建议修复)"
echo -e " ${GREEN}✓ PASSED: $PASS_COUNT${NC}"
echo ""
if [ $ERROR_COUNT -gt 0 ]; then
echo -e " ${RED}结论: 环境不满足 metadef 编译要求,请修复上述 ERROR 项。${NC}"
echo ""
case "$DISTRO" in
ubuntu|debian)
echo " build.md 安装命令 (Ubuntu/Debian, libasan 按 GCC 版本适配):"
echo " sudo apt-get install cmake ccache lcov $APT_ASAN_PKG libgraph-easy-perl patch"
echo ""
echo " 完整依赖一键安装:"
echo " sudo apt-get update && sudo apt-get install -y \\"
echo " build-essential cmake ccache lcov $APT_ASAN_PKG \\"
echo " python3 python3-dev python3-pip \\"
echo " git make patch"
;;
centos|rhel|fedora|euleros|openeuler)
echo " 完整依赖一键安装 (CentOS/EulerOS/openEuler):"
echo " sudo $PKG_MGR install -y \\"
echo " gcc gcc-c++ make cmake ccache lcov libasan \\"
echo " python3 python3-devel python3-pip git patch"
;;
*)
echo " build.md 安装命令 (Ubuntu/Debian, libasan 按 GCC 版本适配):"
echo " sudo apt-get install cmake ccache lcov $APT_ASAN_PKG libgraph-easy-perl patch"
echo ""
echo " 完整依赖一键安装 (CentOS/EulerOS/openEuler):"
echo " sudo yum install -y gcc gcc-c++ make cmake ccache lcov libasan \\"
echo " python3 python3-devel python3-pip git patch"
;;
esac
echo ""
echo " CANN Toolkit 安装:"
echo " 下载: https://ascend.devcloud.huaweicloud.com/artifactory/cann-run-mirror/software/master/"
echo " 安装: ./Ascend-cann-toolkit_xxx_linux-xxx.run --full"
echo " 环境: source /usr/local/Ascend/cann/set_env.sh"
echo ""
echo " 详细说明: docs/build.md"
echo ""
exit 1
elif [ $WARNING_COUNT -gt 0 ]; then
echo -e " ${YELLOW}结论: 环境基本可用,建议关注上述 WARNING 项。${NC}"
exit 0
else
echo -e " ${GREEN}结论: 环境检查全部通过!可以编译 metadef。${NC}"
echo -e " ${GREEN}编译命令: bash build.sh${NC}"
exit 0
fi