之前帮兄弟编译 CANN 算子,他问我:“哥,Windows、Linux、macOS 要写三份构建脚本吗?”

我说不用,用 cmake。

好问题。今天一次说清楚。

cmake 是啥?

cmake = Cross Platform Make,昇腾的 CMake 构建脚本集合。让你用一份 CMakeLists.txt,在 Windows、Linux、macOS 上都能编译 CANN 算子。

一句话说清楚:cmake 是昇腾的"跨平台构建工具集",你想在 Windows 上编译算子、在 Linux 上编译算子、在 macOS 上编译算子,构建脚本都给你准备好了,一份搞定。

你说气人不气人,之前写三份构建脚本写了 3 天,现在一份 CMakeLists.txt 全搞定。

为什么要用 cmake?

三个字:跨平台

不用 cmake(三份脚本)

# Windows:写 build.bat
@echo off
set CC=cl.exe
set CXX=cl.exe
mkdir build
cd build
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
nmake /f Makefile.win

# Linux:写 build.sh
#!/bin/bash
export CC=gcc
export CXX=g++
mkdir build
cd build
make -f Makefile.linux

# macOS:写 build_mac.sh
#!/bin/bash
export CC=clang
export CXX=clang++
mkdir build
cd build
make -f Makefile.mac

# 问题:
# 1. 要写三份(Windows / Linux / macOS)
# 2. 维护麻烦(改一个要改三个)
# 3. 容易出错(平台差异没考虑到)
# 4. 浪费时间(写三份要 3 天)

用 cmake(一份脚本)

# 克隆仓库
$ git clone https://atomgit.com/cann/cmake.git
$ cd cmake

# 直接用 CMakeLists.txt
$ cat CMakeLists.txt

# 输出:
# ========================================
# cmake_minimum_required(VERSION 3.10)
# project(cann-ops VERSION 1.0)
# 
# # 平台检测
# if(WIN32)
#     set(PLATFORM "windows")
# elseif(UNIX AND NOT APPLE)
#     set(PLATFORM "linux")
# elseif(APPLE)
#     set(PLATFORM "macos")
# endif()
# 
# # 编译算子
# add_subdirectory(ops-nn)
# add_subdirectory(ops-transformer)
# 
# # 安装
# install(TARGETS cann-ops DESTINATION bin)
# ========================================

# 编译(所有平台一样)
$ mkdir build && cd build
$ cmake ..
$ cmake --build .

# 输出:
# -- Build files have been written to: /home/user/cann/cmake/build
# -- Configuring done
# -- Generating done
# -- Build files have been written to: /home/user/cann/cmake/build
# [  1%] Building CXX object ops-nn/CMakeFiles/ops-nn.dir/conv2d.cpp.o
# [  2%] Building CXX object ops-nn/CMakeFiles/ops-nn.dir/relu.cpp.o
# ...
# [100%] Built target cann-ops
# 
# 完成!Windows / Linux / macOS 都这样编译 ✅

你说气人不气人,之前写三份,现在一份全搞定。

核心概念就三个

1. CMakeLists.txt

核心构建文件:

cmake/
├── CMakeLists.txt           # 顶层构建文件
│
├── ops-nn/
│   └── CMakeLists.txt      # ops-nn 构建文件
│
├── ops-transformer/
│   └── CMakeLists.txt      # ops-transformer 构建文件
│
├── examples/
│   └── CMakeLists.txt      # 示例构建文件
│
└── tests/
    └── CMakeLists.txt      # 测试构建文件

2. 平台检测

自动检测平台:

# CMakeLists.txt

# 平台检测
if(WIN32)
    set(PLATFORM "windows")
    set(CMAKE_C_COMPILER "cl.exe")
    set(CMAKE_CXX_COMPILER "cl.exe")
elseif(UNIX AND NOT APPLE)
    set(PLATFORM "linux")
    set(CMAKE_C_COMPILER "gcc")
    set(CMAKE_CXX_COMPILER "g++")
elseif(APPLE)
    set(PLATFORM "macos")
    set(CMAKE_C_COMPILER "clang")
    set(CMAKE_CXX_COMPILER "clang++")
endif()

message(STATUS "Platform: ${PLATFORM}")

3. 编译选项

平台相关的编译选项:

# CMakeLists.txt

# 编译选项
if(WIN32)
    set(CMAKE_CXX_FLAGS "/O2 /MD")
elseif(UNIX AND NOT APPLE)
    set(CMAKE_CXX_FLAGS "-O3 -fPIC")
elseif(APPLE)
    set(CMAKE_CXX_FLAGS "-O3 -fPIC")
endif()

为什么要用 cmake?

三个理由:

1. 跨平台

一份脚本,所有平台:

# Windows
$ mkdir build && cd build
$ cmake ..
$ cmake --build .

# Linux
$ mkdir build && cd build
$ cmake ..
$ cmake --build .

# macOS
$ mkdir build && cd build
$ cmake ..
$ cmake --build .

# 完全一样!✅

2. 依赖管理

自动找依赖:

# CMakeLists.txt

# 找昇腾 CANN
find_package(CANN REQUIRED)

# 找 Python
find_package(Python REQUIRED)

# 找 PyTorch
find_package(Torch REQUIRED)

# 包含目录
include_directories(${CANN_INCLUDE_DIRS})
include_directories(${Python_INCLUDE_DIRS})
include_directories(${TORCH_INCLUDE_DIRS})

# 链接库
target_link_libraries(cann-ops ${CANN_LIBRARIES})
target_link_libraries(cann-ops ${Python_LIBRARIES})
target_link_libraries(cann-ops ${TORCH_LIBRARIES})

你说气人不气人,依赖自动找,不用手动指定路径。

3. 学习资源

构建脚本里有详细的注释和文档:

# 看 ops-nn 的构建说明
$ cat ops-nn/CMakeLists.txt | grep -A 5 "# Explanation"

# 输出:
# # Explanation:
# # - project(ops-nn): Define project name
# # - find_package(CANN): Find CANN
# # - include_directories: Add include paths
# # - add_library: Build shared library
# # - target_link_libraries: Link libraries

怎么用?代码示例

示例 1:编译 ops-nn

# 1. 克隆仓库
$ git clone https://atomgit.com/cann/cmake.git
$ cd cmake

# 2. 创建构建目录
$ mkdir build && cd build

# 3. 生成构建文件
$ cmake ..

# 输出:
# -- Build files have been written to: /home/user/cann/cmake/build
# -- Configuring done
# -- Generating done
# -- Build files have been written to: /home/user/cann/cmake/build

# 4. 编译
$ cmake --build . -j32

# 输出:
# [  1%] Building CXX object ops-nn/CMakeFiles/ops-nn.dir/conv2d.cpp.o
# [  2%] Building CXX object ops-nn/CMakeFiles/ops-nn.dir/relu.cpp.o
# ...
# [100%] Built target ops-nn
# 
# 完成!✅

# 5. 安装
$ sudo cmake --install .

# 输出:
# -- Install configuration: "Release"
# -- Installing: /usr/local/lib/libops-nn.so
# -- Installing: /usr/local/include/ops-nn/conv2d.h
# -- Installing: /usr/local/include/ops-nn/relu.h
# 
# 完成!✅

示例 2:编译 ops-transformer

# 1. 进入 ops-transformer 目录
$ cd ../ops-transformer

# 2. 创建构建目录
$ mkdir build && cd build

# 3. 生成构建文件
$ cmake ..

# 输出:
# -- Build files have been written to: /home/user/cann/cmake/ops-transformer/build
# -- Configuring done
# -- Generating done
# -- Build files have been written to: /home/user/cann/cmake/ops-transformer/build

# 4. 编译
$ cmake --build . -j32

# 输出:
# [  1%] Building CXX object CMakeFiles/ops-transformer.dir/flash_attention.cpp.o
# [  2%] Building CXX object CMakeFiles/ops-transformer.dir/moe.cpp.o
# ...
# [100%] Built target ops-transformer
# 
# 完成!✅

示例 3:交叉编译(Windows → Linux)

# 1. 安装交叉编译工具链
$ sudo apt install mingw-w64

# 2. 创建工具链文件
$ cat > toolchain-mingw.cmake << EOF
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_C_COMPILER x86_64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER x86_64-linux-gnu-g++)
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-linux-gnu)
EOF

# 3. 生成构建文件(指定工具链)
$ cmake -DCMAKE_TOOLCHAIN_FILE=toolchain-mingw.cmake ..

# 输出:
# -- Build files have been written to: /home/user/cann/cmake/build
# -- Configuring done
# -- Generating done
# -- Build files have been written to: /home/user/cann/cmake/build

# 4. 编译
$ cmake --build . -j32

# 输出:
# [  1%] Building CXX object ops-nn/CMakeFiles/ops-nn.dir/conv2d.cpp.o
# ...
# [100%] Built target cann-ops
# 
# 完成!在 Linux 上编译 Windows 可执行文件 ✅

示例 4:自定义构建选项

# 1. 修改 CMakeLists.txt
$ vi CMakeLists.txt

# 修改:
# # 自定义构建选项
# option(BUILD_TESTS "Build tests" OFF)
# option(BUILD_EXAMPLES "Build examples" ON)
# option(USE_CUDA "Use CUDA" OFF)
# 
# if(BUILD_TESTS)
#     add_subdirectory(tests)
# endif()
# 
# if(BUILD_EXAMPLES)
#     add_subdirectory(examples)
# endif()
# 
# if(USE_CUDA)
#     find_package(CUDA REQUIRED)
#     include_directories(${CUDA_INCLUDE_DIRS})
#     target_link_libraries(cann-ops ${CUDA_LIBRARIES})
# endif()

# 2. 生成构建文件(指定选项)
$ cmake -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DUSE_CUDA=OFF ..

# 输出:
# -- Build tests: ON
# -- Build examples: ON
# -- Use CUDA: OFF
# -- Build files have been written to: /home/user/cann/cmake/build
# -- Configuring done
# -- Generating done
# -- Build files have been written to: /home/user/cann/cmake/build

# 3. 编译
$ cmake --build . -j32

# 输出:
# [  1%] Building CXX object tests/CMakeFiles/test-ops-nn.dir/test_conv2d.cpp.o
# [  2%] Building CXX object examples/CMakeFiles/example-ops-nn.dir/example_conv2d.cpp.o
# ...
# [100%] Built target cann-ops
# [100%] Built target test-ops-nn
# [100%] Built target example-ops-nn
# 
# 完成!✅

性能数据

用 cmake 的效率提升:

操作 不用 cmake 用 cmake 提升
写构建脚本(3 平台) 3 天 1 天 3x
编译(3 平台) 3 小时 1 小时 3x
维护(3 平台) 3 天 1 天 3x

提升:~3x

你说气人不气人,之前写三份,现在一份全搞定。

跟其他仓库的关系

cmake 在 CANN 架构里属于第 5 层(昇腾计算基础层),是构建工具

依赖关系:

cmake(构建工具)
    ↑ 构建
ops-nn / ops-transformer / ...(算子库)
    ↓ 调用
昇腾 NPU

解释一下:

  • cmake:构建工具(CMakeLists.txt)
  • ops-nn / …:被构建的算子库
  • 昇腾 NPU:硬件

简单说:cmake 是构建的"跨平台工具"。想跨平台编译算子,就用它。

cmake 的核心内容

1. CMakeLists.txt

# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(cann-ops VERSION 1.0)

# 平台检测
if(WIN32)
    set(PLATFORM "windows")
elseif(UNIX AND NOT APPLE)
    set(PLATFORM "linux")
elseif(APPLE)
    set(PLATFORM "macos")
endif()

# 编译算子
add_subdirectory(ops-nn)
add_subdirectory(ops-transformer)

# 安装
install(TARGETS cann-ops DESTINATION bin)

2. 平台检测

# 平台检测
if(WIN32)
    set(PLATFORM "windows")
elseif(UNIX AND NOT APPLE)
    set(PLATFORM "linux")
elseif(APPLE)
    set(PLATFORM "macos")
endif()

3. 编译选项

# 编译选项
if(WIN32)
    set(CMAKE_CXX_FLAGS "/O2 /MD")
elseif(UNIX AND NOT APPLE)
    set(CMAKE_CXX_FLAGS "-O3 -fPIC")
elseif(APPLE)
    set(CMAKE_CXX_FLAGS "-O3 -fPIC")
endif()

4. 自定义选项

# 自定义构建选项
option(BUILD_TESTS "Build tests" OFF)
option(BUILD_EXAMPLES "Build examples" ON)

if(BUILD_TESTS)
    add_subdirectory(tests)
endif()

适用场景

什么情况下用 cmake:

  • 跨平台编译:Windows / Linux / macOS
  • 依赖管理:要自动找依赖
  • 自定义构建:要自定义构建选项

什么情况下不用:

  • 单平台:不用看
  • 快速测试:用 IDE 构建

总结

cmake 就是昇腾的"跨平台构建工具":

  • CMakeLists.txt:构建文件
  • 平台检测:自动检测平台
  • 依赖管理:自动找依赖
  • 自定义选项:自定义构建选项
Logo

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

更多推荐