---
title: 算子工程编译拓展
description: "使用msOpGen工具创建算子工程时，相关编译脚本被固化在本地，若需使用算子工程提供的新特性（比如支持MC2算子等），需重新运行msOpGen工具生成工程。为了解决开发者因功能更新而频繁重建工程的问题，将算子工程的cmake脚本打包到CANN软件包中。开发者可通过find_package的形式来查找对应的cmake modules包，从而使用算子工程对外提供的cmake函数接口。"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/programug/Ascendcopdevg/atlas_ascendc_10_00035.html
sourcePath: /source/zh/canncommercial/900/programug/Ascendcopdevg/atlas_ascendc_10_00035.html
indexId: ab5b44212b3a37c36f5a6941b02b6ea4ef78a85600f935b3ef4136cd05e0435781
---
# 算子工程编译拓展

使用msOpGen工具创建算子工程时，相关编译脚本被固化在本地，若需使用算子工程提供的新特性（比如支持MC2算子等），需重新运行msOpGen工具生成工程。为了解决开发者因功能更新而频繁重建工程的问题，将算子工程的cmake脚本打包到CANN软件包中。开发者可通过find_package的形式来查找对应的cmake modules包，从而使用算子工程对外提供的cmake函数接口。

该开发方式下，开发者参考如下工程目录，自行组织算子工程。目录结构与通过msOpGen生成的目录结构类似, 但无需再创建cmake与scripts目录，这些目录被打包至CANN软件包中。以AddCustom算子为例，目录结构如下：

```
AddCustom
├── CMakeLists.txt
// 算子工程顶层CMakeLists.txt
├── CMakePresets.json           // 编译配置项，cmake内置功能，若使能则需3.19及以上cmake版本
├── framework                   // AI框架适配时，算子插件实现文件目录
├── op_host                     // Host侧实现文件
│   ├── add_custom.cpp         // 算子原型注册、Shape推导、Tiling实现等内容文件
│   ├── add_custom_tiling.h    // 算子Tiling定义文件
│   └── CMakeLists.txt
// Host侧CMakeLists文件
├── op_kernel                   // Kernel侧实现文件
│   ├── Add
│   │   ├── add_custom.cpp    // 算子代码实现文件
└   └── CMakeLists.txt
// Kernel侧CMakeLists文件
```

#### CMakeLists.txt编写方法

- 算子工程顶层CMakeLists.txt

  1. 使用find_package找到对应的编译库。
  2. 使用npu_op_package设置算子工程的编译产物形态，支持RUN/SHARED/STATIC, 分别对应算子run包形式、算子动态库形式与算子静态库形式，同时，该接口还可配置package（即编译产物）的内容和package的安装位置。
  3. 添加需要进行编译的子目录。

```
cmake_minimum_required(VERSION 3.16.0)            # 指定所需的最低cmake版本号
project(opp)
# 1、使用find_package找到对应的编译库。
# ${ASCEND_CANN_PACKAGE_PATH}为对应的CANN软件包路径，开发者可直接使用
find_package(ASC REQUIRED HINTS ${ASCEND_CANN_PACKAGE_PATH}/compiler/tikcpp/ascendc_kernel_cmake)
# 2、使用npu_op_package设置算子工程的编译产物形态。
set(package_name ${vendor_name})
npu_op_package(${package_name}                     # package name
# RUN模式下会使用该name命名算子部署后的目录，静态库模式下输出产物为lib${package_name}.a
TYPE RUN                                       # 指定编译产物形态，[RUN|STATIC|SHARED]
CONFIG
ENABLE_SOURCE_PACKAGE True                 # 是否将源码打包到run包中
ENABLE_BINARY_PACKAGE True                 # 是否编译Kernel二进制, SHARED/STATIC模式下必须指定为True, 默认值为True
INSTALL_PATH ${CMAKE_BINARY_DIR}/          # package的安装位置
)
#3、添加需要进行编译的子目录。
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/op_host)
add_subdirectory(op_host)                      # 添加子目录op_host进行编译
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/op_kernel)
add_subdirectory(op_kernel)                    # 添加子目录op_kernel进行编译
endif()
```


- Host侧CMakeLists.txt

  1. 使用npu_op_code_gen生成aclnn单算子调用代码、入图所需的原型定义代码等。
  2. 单算子调用场景，使用npu_op_library编译aclnn单算子调用库。
  3. 算子入图场景，使用npu_op_library编译算子入图所需的算子原型库。
  4. 使用npu_op_library编译Tiling相关库。
  5. 使用npu_op_package_add添加上述Host侧库至对应package中。

```
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} ops_srcs)
#1、使用npu_op_code_gen生成aclnn单算子调用代码、入图所需的原型定义代码等。
npu_op_code_gen(
SRC ${ops_srcs}                                                           # Host侧实现文件集合
PACKAGE ${package_name}                                                   # 与npu_op_package的package_name对应
COMPILE_OPTIONS -g                                                        # 编译选项
OUT_DIR ${ASCEND_AUTOGEN_PATH}                                            # 指定生成文件的保存路径
JOIN_OP_DEF False    # 可选参数，默认为False。设置为False，仅编译CMakePreset.json中设置的AI处理器型号对应的算子；设置成True，则编译CMakePreset.json和算子原型注册中共有的AI处理器型号对应的算子。
)
#2、单算子调用场景，使用npu_op_library编译aclnn单算子调用库。
file(GLOB autogen_aclnn_src ${ASCEND_AUTOGEN_PATH}/aclnn_*.cpp)                # 将通过npu_op_code_gen生成的aclnn相关源文件添加至源文件列表中
set_source_files_properties(${autogen_aclnn_src} PROPERTIES GENERATED TRUE)    # 设置对应的文件属性为编译过程中生成的文件
npu_op_library(cust_opapi ACLNN                                                # 指定library名称与类型，以及参与编译的源文件
${autogen_aclnn_src}
)
target_compile_options(cust_opapi PRIVATE                                      # 为对应library添加编译选项，与通用的cmake语法一致
-fvisibility=hidden
)
#3、算子入图场景，使用npu_op_library编译算子入图所需的算子原型库。
file(GLOB proto_src ${ASCEND_AUTOGEN_PATH}/op_proto.cc)                        # 将通过npu_op_code_gen生成的原型定义相关源文件添加至源文件列表中
set_source_files_properties(${proto_src} PROPERTIES GENERATED TRUE)            # 设置对应的文件属性为编译过程中生成的文件
npu_op_library(cust_op_proto GRAPH                                             # 指定library名称与类型，以及参与编译的源文件
${ops_srcs}
${proto_src}
)
target_compile_options(cust_op_proto PRIVATE                                   # 为对应library添加编译选项，与通用的cmake语法一致
-fvisibility=hidden
)
#4、使用npu_op_library编译Tiling相关库。
file(GLOB fallback_src ${ASCEND_AUTOGEN_PATH}/fallback_*.cpp)                  # 将通过npu_op_code_gen生成的Tiling相关源文件添加至源文件列表中
# 若算子配置了EnableFallBack会生成该文件
set_source_files_properties(${fallback_src} PROPERTIES GENERATED TRUE)         # 设置对应的文件属性为编译过程中生成的文件
npu_op_library(cust_optiling  TILING                                           # 指定library名称与类型，以及参与编译的源文件
${ops_srcs}
${fallback_src}
)
target_compile_options(cust_optiling PRIVATE                                   # 为对应library添加编译选项，与通用的cmake语法一致
-fvisibility=hidden
)
#5、使用npu_op_package_add添加上述Host侧库到对应package中。
npu_op_package_add(${package_name}                                             # 与npu_op_package的package_name对应
LIBRARY                                                                   # 添加Host侧相关library，library名称与前述步骤的library名称对应
cust_optiling
cust_opapi
cust_op_proto
)
```


- Kernel侧CMakeLists.txt

  1. 使用npu_op_kernel_options添加算子编译选项。支持的编译选项可参考    编译选项
。
  2. 使用npu_op_kernel_sources指定算子特定目录与编译源文件。

    - 若算子的源码文件没有平铺在SRC_BASE目录（通过npu_op_kernel_library设置）下，可以通过KERNEL_DIR指定特定目录。
    - 若算子的Kernel实现cpp文件需要自定义命名，需同时指定OP_TYPE（算子类型）和KERNEL_FILE（Kernel实现cpp文件名），以配置两者之间的对应关系。不配置时，Kernel实现cpp文件名和OpType之间需满足      转换规则
。
  3. 使用npu_op_kernel_library编译Kernel库。
  4. 使用npu_op_package_add添加上述Kernel侧库到对应package中。

```
#1、使用npu_op_kernel_options添加算子编译选项。
npu_op_kernel_options(ascendc_kernels ALL OPTIONS --save-temp-files -g)# 为算子添加编译选项
#2、使用npu_op_kernel_sources指定算子特定目录与编译源文件。
npu_op_kernel_sources(ascendc_kernels                                  # 对应的Kernel库名称，与npu_op_kernel_library保持一致
OP_TYPE AddCustom                                                  # 若算子的Kernel实现cpp文件需要自定义命名，需配置算子类型
KERNEL_DIR ./Add                                                   # 将KERNEL_DIR目录与SRC_BASE目录进行拼接，作为Kernel实现cpp文件所在的目录
COMPUTE_UNIT Ascendxxxyy                                           # 设置KERNEL_FILE在Ascendxxxyy型号生效
KERNEL_FILE add_custom.cpp                                         # 若算子的Kernel实现cpp文件需要自定义命名，需配置Kernel实现cpp文件名
)
#3、使用npu_op_kernel_library编译Kernel库。
npu_op_kernel_library(ascendc_kernels                                  # Kernel库名称
SRC_BASE ${CMAKE_SOURCE_DIR}/op_kernel/                            # 指定kernel侧源码的根目录
TILING_LIBRARY cust_optiling                                       # 指定依赖的Tiling库
)
#4、添加kernel侧library到package
npu_op_package_add(${package_name}                                     # 与npu_op_package的package_name对应
LIBRARY ascendc_kernels                                            # 添加Kernel侧相关library，library名称与前述步骤的library名称对应
)
```


#### 编译环境选项说明

下表列出了供用户配置和使用的编译环境选项：

- 暂不支持设置Release、Debug版本相关选项。
- 暂不支持交叉编译相关选项。


**表1 编译环境选项**

| 类型 | 环境选项 | 默认值 | 说明 |
| --- | --- | --- | --- |
| STRING | vendor\_name | customize | 标识自定义算子所属厂商的名称。建议开发者自行指定所属厂商名称，避免和其他厂商提供的算子包冲突。 |
| STRING | ASCEND\_COMPUTE\_UNIT | \- | AI处理器型号。编译对应型号的package。 |
| PATH | ASCEND\_AUTOGEN\_PATH | <CMAKE\_BINARY\_DIR>/autogen | 通过npu\_op\_code\_gen生成的aclnn单算调用、入图所需算子原型库等源文件存放路径。 |
| BOOL | ENABLE\_SOURCE\_PACKAGE | TRUE | 是否开启源码编译。 如果使用npu\_op\_package配置了源码和二进制编译相关配置，npu\_op\_package配置的优先级更高。 |
| BOOL | ENABLE\_BINARY\_PACKAGE | TRUE | 是否开启二进制编译。 package的类型配置为SHARED或STATIC时，必须指定为TRUE。 如果使用npu\_op\_package配置了源码和二进制编译相关配置，npu\_op\_package配置的优先级更高。 |
| PATH | ASCEND\_CANN\_PACKAGE\_PATH | \- | CANN软件包路径，默认情况下用户无需配置。开发者可以在编写cmake文件时直接使用。 路径示例如下：/usr/local/Ascend/cann。 |


上述编译环境选项可通过两种方式进行配置：

- 支持直接通过set命令进行设置。

```
# CMakeLists.txt直接使用
set(vendor_name "customize")
set(ASCEND_COMPUTE_UNIT "ascendxxxyy")
```


- 通过CMakePresets.json进行设置，若通过该方式设置，则需要安装3.19及以上的cmake。

```
{
"version": 1,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default Config",
"description": "Default build using Unix Makefiles generator",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build_out",
"cacheVariables": {
"ASCEND_COMPUTE_UNIT": {
"type": "STRING",
"value": "ascendxxxyy"
},
"vendor_name": {
"type": "STRING",
"value": "customize"
}
}
}
]
}
```


  然后使用如下命令进行构建，根据--preset指定的preset进行编译。

```
// Shell环境中cmake构建编译
cmake -S . -B build_out --preset=default // 在当前目录(.)中寻找CMakePresets.json
```


#### 编译命令说明

package的类型配置为RUN时，可参考如下编译命令进行编译，使用cmake的pack能力生成run包。

```
# 工程根目录下执行
mkdir -p build_out
rm -rf build_out/*
cmake -S . -B build_out --preset=default
cmake --build build_out --target binary -j${nproc}
cmake --build build_out --target
package
-j${nproc}
```

package的类型配置为SHARED或STATIC时，可参考如下编译命令进行编译：

```
# 工程根目录下执行
mkdir -p build_out
rm -rf build_out/*
cmake -S . -B build_out --preset=default
cmake --build build_out --target binary -j${nproc}
cmake --build build_out --target
install
-j${nproc}
```


#### cmake函数说明

提供如下cmake函数供开发者使用：

| 类型 | 接口 | 功能 |
| --- | --- | --- |
| package | npu\_op\_package | 创建一个package。 |
| package | npu\_op\_package\_add | 将目标或文件添加到package中。 |
| library | npu\_op\_library | 创建Host侧库。 |
| library | npu\_op\_kernel\_library | 创建Kernel侧库。 |
| library | npu\_op\_kernel\_options | 添加Kernel目标编译选项。 |
| library | npu\_op\_kernel\_sources | 描述Kernel目标的源码信息。 |
| library | npu\_op\_device\_tiling\_library | 创建Device侧Tiling库。 |
| 其他 | npu\_op\_code\_gen | 执行代码生成过程，生成aclnn单算子调用代码和入图所需的原型定义代码。 |


1. npu_op_package
  创建一个package。

```
npu_op_package(<package_name> TYPE <type> [CONFIG] [ENABLE_SOURCE_PKG <value>] [ENABLE_BINARY_PACKAGE <value>] [INSTALL_PATH <path>])
```


  参数说明如下：
  - <package_name>：必选，package的名称。
  - TYPE <type>：必选，package的类型，取值为RUN、SHARED、STATIC。分别对应算子run包形式、算子动态库形式与算子静态库形式。
  - [CONFIG]：可选，用于配置package的内容和安装位置。

    - [ENABLE_SOURCE_PKG <value>]：可选，是否将源码打包到package中，默认为True。
    - [ENABLE_BINARY_PACKAGE <value>] ：可选，是否将二进制文件打包到package中，默认为True。
    - [INSTALL_PATH <path>]：可选，指定包的安装路径，默认为CMAKE_BINARY_DIR。
    - [ENABLE_CPACK <value>] ：可选，是否打包，默认为True。对于用户需要定制打包的场景，可以设置为False，配置为False的情况下直接在<path>路径下生成编译产物，不会打包为run包。


2. npu_op_package_add
将目标或文件添加到package中。

```
# 添加目标
npu_op_package_add(<package_name> LIBRARY <target_name1> [<target_name2>...] )
# 添加文件，仅给run包模式使用
npu_op_package_add(<package_name> FILES <file_name1> [<file_name2>...] [TYPE <target_type>] [PACKAGE_PATH <pkg_path>])
```

参数说明如下：

  - <package_name>：必选，package的名称。
  - LIBRARY：必选，指定需要添加到package中的目标名称。

    - <target_name1> [<target_name2>...]：必选，目标名称列表。
  - FILES：必选，指定需要添加到package中的文件名称。

    - <file_name1> [<file_name2>...]：必选，文件名称列表。
  - [TYPE <target_type>]：可选，指定文件类型，将文件安装到对应的目录中，取值为ACLNN、GRAPH。配置为ACLNN，会将文件打包至run包目录下aclnn单算子调用头文件所在目录，配置为GRAPH，会将文件打包至run包目录下入图原型定义头文件目录下。
  - [PACKAGE_PATH <pkg_path>]：可选，指定文件在包中的相对路径位置。TYPE和PACKAGE_PATH参数互斥，即只能选择其中一个进行配置。
3. npu_op_library
创建Host侧库。

```
npu_op_library(<library_name> TYPE <library_type> <files>)
```

参数说明如下：

  - <library_name>：必选，Host侧库的名称。
  - TYPE <library_type>：必选，Host库的类型，可选值为TILING、ACLNN、GRAPH、TF_PLUGIN。

    - TILING，Tiling相关库。
    - ACLNN，aclnn单算子调用库。
    - GRAPH，算子入图所需的算子原型库。
    - TF_PLUGIN，TensorFlow框架适配相关库。
  - <files>：必选，设置参与编译的源文件。
4. npu_op_kernel_library
创建Kernel侧库。

```
npu_op_kernel_library(<target_name> SRC_BASE <path> TILING_LIBRARY <tiling_target>)
```

参数说明如下：

  - <target_name>：必选，目标的名称。
  - SRC_BASE <path>：必选，指定Kernel源码的base目录，要求配置绝对路径。比如示例中的op_kernel目录的绝对路径。
  - TILING_LIBRARY <tiling_target>：必选，指定依赖的Tiling目标。
5. npu_op_kernel_options
添加Kernel目标编译选项。
```
npu_op_kernel_options(<target_name> <op_type> [COMPUTE_UNIT <soc_version>] OPTIONS …)
```


参数说明如下：

  - <target_name>：必选，目标的名称。
  - <op_type>：必选，定义配置生效的范围，取值为ALL、OP_TYPE。ALL表示对所有算子生效，OP_TYPE表示对特定算子生效。
  - [COMPUTE_UNIT <soc_version>]：可选，用于设置算子在具体AI处理器型号上的编译选项，不填写该选项时默认对所有型号生效。
    <soc_version>具体配置如下： 针对如下产品：在安装AI处理器的服务器执行npu-smi info命令进行查询，获取Name信息。实际配置值为AscendName，例如Name取值为xxxyy，实际配置值为Ascendxxxyy。 Atlas A2 训练系列产品 / Atlas A2 推理系列产品 Atlas 200I/500 A2 推理产品 Atlas 推理系列产品 Atlas 训练系列产品 针对 Atlas A3 训练系列产品 / Atlas A3 推理系列产品 ，在安装AI处理器的服务器执行npu-smi info -t board -i id -c chip_id命令进行查询，获取Chip Name和NPU Name信息，实际配置值为Chip Name_NPU Name。例如Chip Name取值为Ascendxxx，NPU Name取值为1234，实际配置值为Ascendxxx_1234。其中： id：设备id，通过npu-smi info -l命令查出的NPU ID即为设备id。 chip_id：芯片id，通过npu-smi info -m命令查出的Chip ID即为芯片id。 针对Atlas 350 加速卡，在安装AI处理器的服务器执行npu-smi info -t board -i id命令进行查询，获取Chip Name和NPU Name信息，实际配置值为Chip Name_NPU Name。例如Chip Name取值为Ascendxxx，NPU Name取值为1234，实际配置值为Ascendxxx_1234。 其中，id为设备id，通过npu-smi info -l命令查出的NPU ID即为设备id。

  - OPTION...： 必选，传递给编译器的编译选项。
6. npu_op_kernel_sources
描述Kernel目标的源码信息，包括设置算子的Kernel实现文件和源码路径等。

```
npu_op_kernel_sources(<target_name> [OP_TYPE <op_type>] [KERNEL_DIR <path>] [COMPUTE_UNIT <soc_version>] [KERNEL_FILE <file>])
```

参数说明如下：

  - <target_name>：必选，目标的名称。
  - [OP_TYPE <op_type>]：可选，算子类型，必须与KERNEL_FILE同时存在。
  - [KERNEL_DIR <path>]：可选，指定Kernel源码相对于SRC_BASE的相对路径。
    若算子的源码文件没有平铺在SRC_BASE目录（通过npu_op_kernel_library设置）下，可以通过KERNEL_DIR指定特定目录。

  - [COMPUTE_UNIT <soc_version>] ：可选，设置KERNEL_FILE在<soc_version>型号生效。默认KERNEL_FILE对所有型号生效。
  - [KERNEL_FILE <file>]：可选，指定算子入口的Kernel实现文件名。
    若算子的Kernel实现cpp文件需要自定义命名，需同时指定OP_TYPE（算子类型）和KERNEL_FILE（Kernel实现cpp文件名），以配置两者之间的对应关系。不配置时，Kernel实现cpp文件名和OpType之间需满足转换规则。

7. npu_op_device_tiling_library
创建Device侧Tiling库。使用该选项时，package的类型仅支持配置为RUN（run包模式）。

```
npu_op_device_tiling_library(<target_name> <type> <files>)
```

参数说明如下：

  - <target_name>：必选，目标的名称。
  - <type>：必选，指定Tiling产物的类型。支持取值为SHARED、STATIC。
  - <files>：必选，指定Tiling源码文件。
8. npu_op_code_gen
执行代码生成过程，生成aclnn单算子调用代码和入图所需的原型定义代码。

```
npu_op_code_gen(SRC <src_files> OUT_DIR <output_dir> PACKAGE <pkg_name> [COMPILE_OPTIONS ...])
```

参数说明如下：

  - SRC <src_files>：必选，参与代码生成的源文件范围。
  - OUT_DIR <output_dir>：必选，生成代码的输出路径。
  - PACKAGE <pkg_name>：必选，指定生成代码的package名称。
  - [COMPILE_OPTIONS ...]：可选，自定义编译过程中的编译选项。
