跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 07 章 快速上手:安装与第一个 kernel

/code/07-quickstart/

06-env-check/check_env.py4040 字节
"""第七章 · 安装前的环境体检。

在真机上装 tilelang 之前,先跑一遍这个脚本,把「环境要求」对着官方
``docs/get_started/Installation.md`` 里那几条逐项验一遍。它只报告事实,
不做自动安装、不改任何文件。

运行:
    python check_env.py                    # 只体检 CUDA / 通用环境
    python check_env.py --ascend           # 额外体检昇腾环境

验证级别:**在本机运行过(纯 Python,只读环境)**。脚本本身不需要 GPU;
它检测的是「如果本机没有 GPU,会如实说没有」。
"""

from __future__ import annotations

import argparse
import ctypes
import os
import platform
import shutil
import subprocess
import sys


def report(name: str, state: bool | None, detail: str, required: bool = False) -> None:
    mark = "ok  " if state else ("FAIL" if state is False else "?   ")
    suffix = "  (必需)" if required else ""
    print(f"  [{mark}] {name:<30} {detail}{suffix}")


def check_python() -> None:
    v = sys.version_info
    report("Python >= 3.10", (v.major, v.minor) >= (3, 10), platform.python_version(), required=True)


def check_glibc() -> None:
    try:
        libc = ctypes.CDLL("libc.so.6")
        libc.gnu_get_libc_version.restype = ctypes.c_char_p
        ver = libc.gnu_get_libc_version().decode()
        major, minor = (int(x) for x in ver.split(".")[:2])
        report("glibc >= 2.28", (major, minor) >= (2, 28), ver, required=True)
    except Exception:
        report("glibc >= 2.28", None, "非 glibc 环境(macOS / musl 等),跳过")


def check_cuda() -> None:
    nvcc = shutil.which("nvcc")
    if nvcc is None:
        report("nvcc(host CUDA 工具链)", False, "PATH 里没有 nvcc;可用 pip 提供的 CUDA(>=13)")
        return
    try:
        out = subprocess.run([nvcc, "--version"], capture_output=True, text=True, timeout=20).stdout
        line = next((l for l in out.splitlines() if "release" in l), "").strip()
        report("nvcc 可用", True, f"{nvcc}  {line}")
    except Exception as exc:  # pragma: no cover
        report("nvcc 可用", None, f"找到 {nvcc} 但无法执行:{exc}")


def check_torch() -> None:
    try:
        import torch
    except Exception:
        report("import torch", False, "未安装 torch(wheel 安装会把它作为依赖装上)")
        return
    report("import torch", True, torch.__version__)
    try:
        ok = torch.cuda.is_available()
        report("torch.cuda.is_available()", ok, "有 NVIDIA GPU" if ok else "没有可见的 NVIDIA GPU")
    except Exception as exc:
        report("torch.cuda.is_available()", None, str(exc))


def check_tilelang() -> None:
    try:
        import tilelang
    except Exception as exc:
        report("import tilelang", False, f"{type(exc).__name__}: {exc}")
        return
    report("import tilelang", True, getattr(tilelang, "__version__", "?"))
    try:
        from tilelang import env

        report("TILELANG_CACHE_DIR", True, str(env.TILELANG_CACHE_DIR))
    except Exception:
        pass


def check_ascend() -> None:
    print("\n== 昇腾环境 ==")
    home = os.environ.get("ASCEND_HOME_PATH")
    report("ASCEND_HOME_PATH", bool(home), home or "未设置(build_wheel_ascend.sh 需要它)")
    bisheng = shutil.which("bisheng")
    report("bisheng(编译器)", bisheng is not None, bisheng or "PATH / BISHENG_HOME/bin 里没有 bisheng")
    lld = shutil.which("ld.lld")
    report("ld.lld(CCE 版)", lld is not None, lld or "PATH 里没有 ld.lld")
    try:
        import torch
        import torch_npu  # type: ignore[import-not-found]  # noqa: F401

        ok = torch.npu.is_available()
        report("torch.npu.is_available()", ok, "有昇腾 NPU" if ok else "没有可见的昇腾 NPU")
    except Exception as exc:
        report("import torch_npu", False, f"{type(exc).__name__}: {exc}")


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--ascend", action="store_true", help="额外体检昇腾环境")
    args = parser.parse_args()

    print(f"平台:{platform.platform()} / {platform.machine()}\n")
    print("== 通用环境(对照 docs/get_started/Installation.md:7-9) ==")
    check_python()
    check_glibc()
    print("\n== CUDA 环境 ==")
    check_cuda()
    print("\n== Python 依赖 ==")
    check_torch()
    check_tilelang()
    if args.ascend:
        check_ascend()
    print("\n提示:本脚本只报告事实。安装命令见本章 3 节,安装失败见本章 8 节。")
    return 0


if __name__ == "__main__":
    sys.exit(main())

← 浏览本章全部代码