# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# CANN Open Software License Agreement Version 2.0 (the "License").
# Please refer to the License for details. You may not use this file except in compliance with the License.
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
# See LICENSE in the root of the software repository for the full text of the License.
# -----------------------------------------------------------------------------------------------------------
include(ExternalProject)
if(DEFINED ENV{ATVC_PATH})
set(ATVC_PATH $ENV{ATVC_PATH})
else()
set(ATVC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../include")
endif()
function(get_system_info SYSTEM_INFO)
if (UNIX)
execute_process(COMMAND grep -i ^id= /etc/os-release OUTPUT_VARIABLE TEMP)
string(REGEX REPLACE "\n|id=|ID=|\"" "" SYSTEM_NAME ${TEMP})
set(${SYSTEM_INFO} ${SYSTEM_NAME}_${CMAKE_SYSTEM_PROCESSOR} PARENT_SCOPE)
elseif (WIN32)
message(STATUS "System is Windows. Only for pre-build.")
else ()
message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} not support.")
endif ()
endfunction()
function(opbuild)
message(STATUS "Opbuild generating sources")
cmake_parse_arguments(OPBUILD "" "OUT_DIR;PROJECT_NAME;ACCESS_PREFIX;ENABLE_SOURCE" "OPS_SRC" ${ARGN})
execute_process(COMMAND ${CMAKE_COMPILE} -g -fPIC -shared -std=c++17 ${OPBUILD_OPS_SRC} -D_GLIBCXX_USE_CXX11_ABI=0
-I ${ASCEND_CANN_PACKAGE_PATH}/include -I ${CMAKE_CURRENT_SOURCE_DIR}/../op_kernel
-L ${ASCEND_CANN_PACKAGE_PATH}/lib64 -lexe_graph -lregister -ltiling_api -I ${ATVC_PATH}
-o ${OPBUILD_OUT_DIR}/libascend_all_ops.so
RESULT_VARIABLE EXEC_RESULT
OUTPUT_VARIABLE EXEC_INFO
ERROR_VARIABLE EXEC_ERROR
)
if (${EXEC_RESULT})
message("build ops lib info: ${EXEC_INFO}")
message("build ops lib error: ${EXEC_ERROR}")
message(FATAL_ERROR "opbuild run failed!")
endif()
set(proj_env "")
set(prefix_env "")
if (NOT "${OPBUILD_PROJECT_NAME}x" STREQUAL "x")
set(proj_env "OPS_PROJECT_NAME=${OPBUILD_PROJECT_NAME}")
endif()
if (NOT "${OPBUILD_ACCESS_PREFIX}x" STREQUAL "x")
set(prefix_env "OPS_DIRECT_ACCESS_PREFIX=${OPBUILD_ACCESS_PREFIX}")
endif()
set(ENV{ENABLE_SOURCE_PACAKGE} ${OPBUILD_ENABLE_SOURCE})
if(${ASCEND_PACK_SHARED_LIBRARY})
if (NOT vendor_name)
message(FATAL_ERROR "ERROR: vendor_name is invalid!")
return()
endif()
set(ENV{ASCEND_VENDOR_NAME} ${vendor_name})
set(ENV{OPS_PRODUCT_NAME} ${ASCEND_COMPUTE_UNIT})
set(ENV{SYSTEM_PROCESSOR} ${CMAKE_SYSTEM_PROCESSOR})
endif()
execute_process(COMMAND ${proj_env} ${prefix_env} ${ASCEND_CANN_PACKAGE_PATH}/toolkit/tools/opbuild/op_build
${OPBUILD_OUT_DIR}/libascend_all_ops.so ${OPBUILD_OUT_DIR}
RESULT_VARIABLE EXEC_RESULT
OUTPUT_VARIABLE EXEC_INFO
ERROR_VARIABLE EXEC_ERROR
)
unset(ENV{ENABLE_SOURCE_PACAKGE})
if(${ASCEND_PACK_SHARED_LIBRARY})
unset(ENV{ASCEND_VENDOR_NAME})
unset(ENV{OPS_PRODUCT_NAME})
unset(ENV{SYSTEM_PROCESSOR})
endif()
if (${EXEC_RESULT})
message("opbuild ops info: ${EXEC_INFO}")
message("opbuild ops error: ${EXEC_ERROR}")
endif()
message(STATUS "Opbuild generating sources - done")
endfunction()
function(add_ops_info_target)
cmake_parse_arguments(OPINFO "" "TARGET;OPS_INFO;OUTPUT;INSTALL_DIR" "" ${ARGN})
get_filename_component(opinfo_file_path "${OPINFO_OUTPUT}" DIRECTORY)
add_custom_command(OUTPUT ${OPINFO_OUTPUT}
COMMAND mkdir -p ${opinfo_file_path}
COMMAND ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/parse_ini_to_json.py
${OPINFO_OPS_INFO} ${OPINFO_OUTPUT}
)
add_custom_target(${OPINFO_TARGET} ALL
DEPENDS ${OPINFO_OUTPUT}
)
if(NOT ${ASCEND_PACK_SHARED_LIBRARY})
install(FILES ${OPINFO_OUTPUT}
DESTINATION ${OPINFO_INSTALL_DIR}
)
endif()
endfunction()
function(add_ops_compile_options OP_TYPE)
cmake_parse_arguments(OP_COMPILE "" "OP_TYPE" "COMPUTE_UNIT;OPTIONS" ${ARGN})
execute_process(COMMAND ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/ascendc_gen_options.py
${ASCEND_AUTOGEN_PATH}/${CUSTOM_COMPILE_OPTIONS} ${OP_TYPE} ${OP_COMPILE_COMPUTE_UNIT}
${OP_COMPILE_OPTIONS}
RESULT_VARIABLE EXEC_RESULT
OUTPUT_VARIABLE EXEC_INFO
ERROR_VARIABLE EXEC_ERROR)
if (${EXEC_RESULT})
message("add ops compile options info: ${EXEC_INFO}")
message("add ops compile options error: ${EXEC_ERROR}")
message(FATAL_ERROR "add ops compile options failed!")
endif()
endfunction()
function(add_npu_support_target)
cmake_parse_arguments(NPUSUP "" "TARGET;OPS_INFO_DIR;OUT_DIR;INSTALL_DIR" "" ${ARGN})
get_filename_component(npu_sup_file_path "${NPUSUP_OUT_DIR}" DIRECTORY)
add_custom_command(OUTPUT ${NPUSUP_OUT_DIR}/npu_supported_ops.json
COMMAND mkdir -p ${NPUSUP_OUT_DIR}
COMMAND ${CMAKE_SOURCE_DIR}/cmake/util/gen_ops_filter.sh
${NPUSUP_OPS_INFO_DIR}
${NPUSUP_OUT_DIR}
)
add_custom_target(npu_supported_ops ALL
DEPENDS ${NPUSUP_OUT_DIR}/npu_supported_ops.json
)
if(NOT ${ASCEND_PACK_SHARED_LIBRARY})
install(FILES ${NPUSUP_OUT_DIR}/npu_supported_ops.json
DESTINATION ${NPUSUP_INSTALL_DIR}
)
endif()
endfunction()
function(add_simple_kernel_compile)
set(options "")
set(single_value_args "OPS_INFO;OUT_DIR;TILING_LIB;OP_TYPE;SRC;COMPUTE_UNIT;JSON_FILE;DYNAMIC_PATH")
set(multi_value_args "OPTIONS;CONFIGS")
cmake_parse_arguments(BINCMP "${options}" "${single_value_args}" "${multi_value_args}" ${ARGN})
if (NOT DEFINED BINCMP_OUT_DIR)
set(BINCMP_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/binary)
endif()
if (NOT DEFINED BINCMP_TILING_LIB)
set(BINCMP_TILING_LIB $<TARGET_FILE:cust_optiling>)
endif()
if (${ASCEND_PACK_SHARED_LIBRARY})
if (NOT TARGET op_kernel_pack)
add_custom_target(op_kernel_pack
COMMAND ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/ascendc_pack_kernel.py
--input-path=${BINCMP_OUT_DIR}
--output-path=${BINCMP_OUT_DIR}/library
--enable-library=${ASCEND_PACK_SHARED_LIBRARY}
--platform=${CMAKE_SYSTEM_PROCESSOR})
add_library(ascend_kernels INTERFACE)
target_link_libraries(ascend_kernels INTERFACE kernels)
target_link_directories(ascend_kernels INTERFACE ${BINCMP_OUT_DIR}/library)
target_include_directories(ascend_kernels INTERFACE ${BINCMP_OUT_DIR}/library)
add_dependencies(ascend_kernels op_kernel_pack)
add_dependencies(op_kernel_pack ${BINCMP_OP_TYPE}_${BINCMP_COMPUTE_UNIT})
endif()
endif()
# add Environment Variable Configurations of ccache
set(_ASCENDC_ENV_VAR)
if(${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES "ccache$")
list(APPEND _ASCENDC_ENV_VAR export ASCENDC_CCACHE_EXECUTABLE=${CMAKE_CXX_COMPILER_LAUNCHER} &&)
endif()
if (NOT DEFINED BINCMP_OPS_INFO)
set(BINCMP_OPS_INFO ${ASCEND_AUTOGEN_PATH}/aic-${BINCMP_COMPUTE_UNIT}-ops-info.ini)
endif()
if (NOT ${ENABLE_CROSS_COMPILE})
add_custom_target(${BINCMP_OP_TYPE}_${BINCMP_COMPUTE_UNIT}
COMMAND ${_ASCENDC_ENV_VAR} ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/ascendc_compile_kernel.py
--op-name=${BINCMP_OP_TYPE}
--src-file=${BINCMP_SRC}
--compute-unit=${BINCMP_COMPUTE_UNIT}
--compile-options=\"${BINCMP_OPTIONS}\"
--debug-config=\"${BINCMP_CONFIGS}\"
--config-ini=${BINCMP_OPS_INFO}
--tiling-lib=${BINCMP_TILING_LIB}
--output-path=${BINCMP_OUT_DIR}
--dynamic-dir=${BINCMP_DYNAMIC_PATH}
--enable-binary=\"${ENABLE_BINARY_PACKAGE}\"
--json-file=${BINCMP_JSON_FILE}
--build-tool=$(MAKE))
add_dependencies(${BINCMP_OP_TYPE}_${BINCMP_COMPUTE_UNIT} cust_optiling)
else()
if (${ENABLE_BINARY_PACKAGE} AND NOT DEFINED HOST_NATIVE_TILING_LIB)
message(FATAL_ERROR "Native host libs was not set for cross compile!")
endif()
add_custom_target(${BINCMP_OP_TYPE}_${BINCMP_COMPUTE_UNIT}
COMMAND ${_ASCENDC_ENV_VAR} ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/ascendc_compile_kernel.py
--op-name=${BINCMP_OP_TYPE}
--src-file=${BINCMP_SRC}
--compute-unit=${BINCMP_COMPUTE_UNIT}
--compile-options=\"${BINCMP_OPTIONS}\"
--debug-config=\"${BINCMP_CONFIGS}\"
--config-ini=${BINCMP_OPS_INFO}
--tiling-lib=${HOST_NATIVE_TILING_LIB}
--output-path=${BINCMP_OUT_DIR}
--dynamic-dir=${BINCMP_DYNAMIC_PATH}
--enable-binary=\"${ENABLE_BINARY_PACKAGE}\"
--json-file=${BINCMP_JSON_FILE}
--build-tool=$(MAKE))
endif()
add_dependencies(ascendc_bin_${BINCMP_COMPUTE_UNIT}_gen_ops_config ${BINCMP_OP_TYPE}_${BINCMP_COMPUTE_UNIT})
add_dependencies(${BINCMP_OP_TYPE}_${BINCMP_COMPUTE_UNIT} ops_info_gen_${BINCMP_COMPUTE_UNIT})
endfunction()
function(ascendc_device_library)
message(STATUS "Ascendc device library generating")
cmake_parse_arguments(DEVICE "" "TARGET;OPTION" "SRC" ${ARGN})
execute_process(
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/tiling_sink
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/tiling_sink/CMakeLists.txt
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "cmake_minimum_required(VERSION 3.16.0)\nproject(cust_tiling_sink)\ninclude(${CMAKE_SOURCE_DIR}/cmake/device_task.cmake)\n"
OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/tiling_sink/CMakeLists.txt
RESULT_VARIABLE result
)
string(REPLACE ";" " " DEVICE_SRC "${DEVICE_SRC}")
ExternalProject_Add(tiling_sink_task
SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/tiling_sink
CONFIGURE_COMMAND ${CMAKE_COMMAND}
-DASCEND_CANN_PACKAGE_PATH=${ASCEND_CANN_PACKAGE_PATH}
-DTARGET=${DEVICE_TARGET}
-DOPTION=${DEVICE_OPTION}
-DSRC=${DEVICE_SRC}
-DVENDOR_NAME=${vendor_name}
<SOURCE_DIR>
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
INSTALL_COMMAND ""
BUILD_ALWAYS TRUE
)
ExternalProject_Get_Property(tiling_sink_task BINARY_DIR)
set(TILINGSINK_LIB_PATH "")
if ("${DEVICE_OPTION}" STREQUAL "SHARED")
set(TILINGSINK_LIB_PATH "${BINARY_DIR}/libcust_opmaster.so")
else()
set(TILINGSINK_LIB_PATH "${BINARY_DIR}/libcust_opmaster.a")
endif()
install(FILES ${TILINGSINK_LIB_PATH}
DESTINATION packages/vendors/${vendor_name}/op_impl/ai_core/tbe/op_master_device/lib
)
endfunction()
function(add_opregistry_target)
string(REPLACE ";" "-" COMPUTE_UNIT "${ASCEND_COMPUTE_UNIT}")
add_custom_target(op_registry_pack
COMMAND ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/ascendc_pack_opregistry.py
--input-path=${CMAKE_SOURCE_DIR}/build_out/
--base-path=${CMAKE_SOURCE_DIR}/build_out/tmp/vendors/
--output-path=${CMAKE_SOURCE_DIR}/build_out/library/
--vendor-name=${vendor_name}
--compute-unit=${COMPUTE_UNIT}
--framework-type=${ASCEND_FRAMEWORK_TYPE}
--platform=${CMAKE_SYSTEM_PROCESSOR})
add_library(ascend_opregistry INTERFACE)
target_link_libraries(ascend_opregistry INTERFACE opregistry)
target_link_directories(ascend_opregistry INTERFACE ${CMAKE_SOURCE_DIR}/build_out/library)
target_include_directories(ascend_opregistry INTERFACE ${CMAKE_SOURCE_DIR}/build_out/library)
add_dependencies(ascend_opregistry op_registry_pack)
if(EXISTS "${CMAKE_SOURCE_DIR}/framework/caffe_plugin")
add_dependencies(op_registry_pack cust_caffe_parsers)
elseif(EXISTS "${CMAKE_SOURCE_DIR}/framework/tf_plugin")
add_dependencies(op_registry_pack cust_tf_parsers)
elseif(EXISTS "${CMAKE_SOURCE_DIR}/framework/onnx_plugin")
add_dependencies(op_registry_pack cust_onnx_parsers)
endif()
endfunction()
function(add_kernels_install)
# install kernel file
if (${ENABLE_SOURCE_PACKAGE})
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/binary/dynamic/
DESTINATION packages/vendors/${vendor_name}/op_impl/ai_core/tbe/${vendor_name}_impl/dynamic/
)
endif()
# install *.o files and *.json files
if (${ENABLE_BINARY_PACKAGE})
set(INSTALL_DIR packages/vendors/${vendor_name}/op_impl/ai_core/tbe/)
foreach(compute_unit ${ASCEND_COMPUTE_UNIT})
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/binary/${compute_unit}/
DESTINATION ${INSTALL_DIR}/kernel/${compute_unit}/
)
endforeach()
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/binary/config/
DESTINATION ${INSTALL_DIR}/kernel/config/
)
endif()
endfunction()
function(add_kernels_compile)
set(DYNAMIC_PATH "")
if (${ENABLE_SOURCE_PACKAGE})
set(DYNAMIC_PATH ${CMAKE_CURRENT_BINARY_DIR}/binary/dynamic)
execute_process(COMMAND sh -c "mkdir -p ${DYNAMIC_PATH} &&
cp -rf ${CMAKE_SOURCE_DIR}/op_kernel/* ${DYNAMIC_PATH}/ &&
rm ${DYNAMIC_PATH}/CMakeLists.txt"
RESULT_VARIABLE EXEC_RESULT
ERROR_VARIABLE EXEC_ERROR
)
if (${EXEC_RESULT})
message(FATAL_ERROR, "copy_source_files failed, gen error:${EXEC_ERROR}" )
endif()
endif()
foreach(compute_unit ${ASCEND_COMPUTE_UNIT})
# generate aic-${compute_unit}-ops-info.json
add_ops_info_target(TARGET ops_info_gen_${compute_unit}
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tbe/op_info_cfg/ai_core/${compute_unit}/aic-${compute_unit}-ops-info.json
OPS_INFO ${ASCEND_AUTOGEN_PATH}/aic-${compute_unit}-ops-info.ini
INSTALL_DIR packages/vendors/${vendor_name}/op_impl/ai_core/tbe/config/${compute_unit}
)
# define a target:binary to prevent kernel file from being rebuilt during the preinstall process
if (NOT TARGET binary)
add_custom_target(binary)
endif()
if (${ENABLE_BINARY_PACKAGE} OR ${ENABLE_SOURCE_PACKAGE})
if (${ENABLE_BINARY_PACKAGE})
# gen binary_info_config.json and <file_name>.json
add_custom_target(ascendc_bin_${compute_unit}_gen_ops_config
COMMAND ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/insert_simplified_keys.py
-p ${CMAKE_CURRENT_BINARY_DIR}/binary/${compute_unit}
COMMAND ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/ascendc_ops_config.py
-p ${CMAKE_CURRENT_BINARY_DIR}/binary/${compute_unit}
-s ${compute_unit}
COMMAND ${CMAKE_COMMAND} -E make_directory
${CMAKE_CURRENT_BINARY_DIR}/binary/config/${compute_unit}
COMMAND mv ${CMAKE_CURRENT_BINARY_DIR}/binary/${compute_unit}/*.json
${CMAKE_CURRENT_BINARY_DIR}/binary/config/${compute_unit}
)
else()
if (NOT TARGET ascendc_bin_${compute_unit}_gen_ops_config)
add_custom_target(ascendc_bin_${compute_unit}_gen_ops_config)
endif()
endif()
add_dependencies(binary ascendc_bin_${compute_unit}_gen_ops_config)
# get op_type-op_name from aic-${compute_unit}-ops-info.ini
execute_process(COMMAND ${ASCEND_PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/util/ascendc_get_op_name.py
--ini-file=${ASCEND_AUTOGEN_PATH}/aic-${compute_unit}-ops-info.ini
OUTPUT_VARIABLE OP_TYPE_NAME
RESULT_VARIABLE EXEC_RESULT
ERROR_VARIABLE EXEC_ERROR
)
if (${EXEC_RESULT})
message(FATAL_ERROR, "get op name failed, gen error: ${EXEC_ERROR}")
endif()
# compile op one by one with ascendc_compile_kernel.py
string(REPLACE "\n" ";" TYPE_NAME_LIST "${OP_TYPE_NAME}")
foreach(TYPE_NAME IN LISTS TYPE_NAME_LIST)
if (NOT "${TYPE_NAME}" STREQUAL "")
string(REPLACE "-" ";" bin_sep ${TYPE_NAME})
list(GET bin_sep 0 op_type)
list(GET bin_sep 1 op_file)
add_simple_kernel_compile(OP_TYPE ${op_type}
SRC ${CMAKE_SOURCE_DIR}/op_kernel/${op_file}.cpp
COMPUTE_UNIT ${compute_unit}
JSON_FILE ${CMAKE_CURRENT_BINARY_DIR}/tbe/op_info_cfg/ai_core/${compute_unit}/aic-${compute_unit}-ops-info.json
DYNAMIC_PATH ${DYNAMIC_PATH})
endif()
endforeach()
endif()
endforeach()
# generate npu_supported_ops.json
add_npu_support_target(TARGET npu_supported_ops
OPS_INFO_DIR ${ASCEND_AUTOGEN_PATH}
OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/tbe/op_info_cfg/ai_core
INSTALL_DIR packages/vendors/${vendor_name}/framework/${ASCEND_FRAMEWORK_TYPE}
)
if(ENABLE_TEST AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/testcases)
add_subdirectory(testcases)
endif()
if(NOT ASCEND_PACK_SHARED_LIBRARY)
add_kernels_install()
else()
add_opregistry_target()
endif()
endfunction()