---
tags: [CANN]
doc_type: knowledge-note
abstract: "组织子目录与公共库，并检查完整工程的依赖和构建配置。"
返回目录: "[[计算机系/昇腾与CANN/大模型与算子专题学习导航|大模型与算子专题学习导航]]"
专题目录: "[[计算机系/昇腾与CANN/CMake与Ascend C编译入门|CMake与Ascend C编译入门]]"
上一篇: "[[计算机系/昇腾与CANN/02 Ascend C源码组织与编译运行|02 Ascend C源码组织与编译运行]]"
前置操作: "[[计算机系/昇腾与CANN/02 Ascend C源码组织与编译运行|02 Ascend C源码组织与编译运行]]"
---

# 03 多级CMake工程与构建检查

组织子目录与公共库，并检查完整工程的依赖和构建配置。

## 8. 多级 CMake：按子目录组织目标

所谓“多级串联”，通常是顶层 `CMakeLists.txt` 使用 `add_subdirectory` 加载子目录的 `CMakeLists.txt`。它们共同组成一个工程的构建关系。

### 8.1 目录结构

```text
kernel_samples/
├── CMakeLists.txt
├── common/
│   ├── CMakeLists.txt
│   ├── helper.cpp
│   └── include/
│       └── helper.h
└── samples/
    ├── CMakeLists.txt
    └── add_custom.asc
```

`helper` 表示可以独立编译的普通 C++ 辅助库，`samples` 定义使用它的可执行程序。

### 8.2 顶层配置

```cmake
cmake_minimum_required(VERSION 3.16)
find_package(ASC REQUIRED)
project(kernel_samples LANGUAGES ASC CXX)

add_subdirectory(common)
add_subdirectory(samples)
```

顶层统一启用语言并组织子目录，子目录不需要机械重复 `project` 和 `find_package`。

### 8.3 `common/CMakeLists.txt`

```cmake
add_library(helper STATIC
    helper.cpp
)

target_include_directories(helper PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/include"
)
```

`helper` 是静态库目标。这里的 `CMAKE_CURRENT_SOURCE_DIR` 指 `common` 目录。

### 8.4 `samples/CMakeLists.txt`

```cmake
add_executable(demo
    add_custom.asc
)

target_compile_options(demo PRIVATE
    $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=dav-2201>
)

target_link_libraries(demo PRIVATE helper)
```

这里声明 `demo` 使用 `helper`，构建工具就能根据目标依赖安排构建顺序。**最终编译顺序由依赖关系决定，不能只按两个 `add_subdirectory` 的书写顺序理解。**

在默认的 Linux 单配置布局下，这个子目录目标通常输出为 `build/samples/demo`。这与顶层直接定义 `demo` 时的 `build/demo` 有所区别。

### 8.5 常用目录变量

| 变量 | 含义 |
| --- | --- |
| `CMAKE_SOURCE_DIR` | 最顶层源码目录 |
| `CMAKE_BINARY_DIR` | 最顶层构建目录 |
| `CMAKE_CURRENT_SOURCE_DIR` | 当前处理的源码目录 |
| `CMAKE_CURRENT_BINARY_DIR` | 当前源码目录对应的构建目录 |

`add_subdirectory` 用于加入具有目标和目录结构的子工程；`include` 更常用于加载可复用的 `.cmake` 配置或函数模块，两者用途不同。

## 9. 阅读这段配置时的检查顺序

1. **语言**：`CXX` 是 C++，`ASC` 是 Ascend C，是否还需要 `C`？
2. **包与工具链**：ASC 包能否被找到，编译工具是否就绪？
3. **目标**：`demo` 是可执行目标，哪些源文件属于它？
4. **入口与依赖**：是否有程序入口、必要声明和需要链接的库？
5. **选项范围**：参数作用于哪个目标、哪种语言，是否需要向使用者传播？
6. **架构**：编译架构是否与目标设备匹配？
7. **输出**：程序生成在构建目录的哪个位置，是否设置了输出目录？

这份配置负责把算子代码组织成可构建的程序。核函数的数学逻辑、数据分片、搬运与同步仍由 [Ascend C 算子基础整理](Ascend%20C算子基础整理.md)中的代码实现。

## 10. 从最小配置扩展到完整工程

最小配置建立了“加载 ASC 支持、启用语言、定义目标、指定编译架构”的框架。完整应用还需要程序入口、源文件和实际使用的依赖；仅有核函数片段时，增加 `add_executable` 不能自动补齐这些内容。

工程扩大时，可以按需增加：

- 头文件搜索路径：`target_include_directories`。
- 库依赖：`target_link_libraries`。
- 宏定义：`target_compile_definitions`。
- 子目录与公共模块：`add_subdirectory` 和 `include`。
- 构建配置：Debug、Release 等。

对于 Makefile、常见单配置 Ninja 等生成器，可在配置阶段选择构建类型：

```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build --target demo
```

对于多配置生成器，通常在构建阶段选择：

```bash
cmake --build build --config Debug --target demo
```

Debug 与 Release 对应哪些调试信息或优化参数，由语言、工具链及项目配置共同决定，不能默认所有 ASC 编译步骤都与普通 C++ 使用完全相同的选项。
