# -----------------------------------------------------------------------------------------------------------
# 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.
# -----------------------------------------------------------------------------------------------------------
# GTest 生成覆盖率
#[[
Parameters:
one_value_keywords:
TARGET : [Required] 指定所依赖的目标(POST_BUILD)
multi_value_keywords:
FILTER_DIRECTORIES : [Optional] 覆盖率结果过滤目录
]]
function(PTO_Fwk_GTest_GenerateCoverage)
cmake_parse_arguments(
ARG
""
"TARGET"
"FILTER_DIRECTORIES"
""
${ARGN}
)
if (ENABLE_TESTS_EXECUTE AND ENABLE_GCOV)
# 获取 gcc 默认头文件搜索路径
execute_process(
COMMAND ${CMAKE_C_COMPILER} --print-sysroot
RESULT_VARIABLE _RST
OUTPUT_VARIABLE _SUFFIX
ERROR_QUIET
)
if (_RST)
get_filename_component(SYS_ROOT "/usr/include" REALPATH)
else ()
get_filename_component(SYS_ROOT "${_SUFFIX}/usr/include" REALPATH)
endif ()
# 参数组织
find_program(LCOV lcov REQUIRED)
get_filename_component(GenCoveragePy ${PTO_FWK_SRC_ROOT}/cmake/scripts/gen_coverage.py REALPATH)
get_filename_component(GenCoverageDataDir "${PTO_FWK_BIN_ROOT}" REALPATH)
set(_Args "-s=${PTO_FWK_SRC_ROOT}" "-d=${GenCoverageDataDir}")
set(Filter_Dirs
${PTO_FWK_SRC_ROOT}/framework/tests
$<TARGET_PROPERTY:GTest::gtest,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:json,INTERFACE_INCLUDE_DIRECTORIES>
${SYS_ROOT}
${Python3_INCLUDE_DIRS}
${pybind11_INCLUDE_DIR}
${ARG_FILTER_DIRECTORIES}
)
if (ENABLE_TORCH_VERIFIER)
list(APPEND Filter_Dirs ${PY3_MOD_TORCH_ROOT_PATH}/include)
endif ()
if (BUILD_WITH_CANN)
list(APPEND Filter_Dirs ${ASCEND_CANN_PACKAGE_PATH}/include)
list(APPEND Filter_Dirs ${ASCEND_CANN_PACKAGE_PATH}/pkg_inc)
endif ()
foreach (_dir ${Filter_Dirs})
list(APPEND _Args "-f=${_dir}")
endforeach ()
list(REMOVE_DUPLICATES _Args)
add_custom_command(
TARGET ${ARG_TARGET} POST_BUILD
COMMAND ${Python3_EXECUTABLE} ${GenCoveragePy} ARGS ${_Args}
VERBATIM
COMMENT "Generate coverage for ${ARG_TARGET}"
)
endif ()
endfunction()
# GTest 获取可执行程序在执行前需要的命令行配置和环境变量配置
#[[
Parameters:
one_value_keywords:
TARGET : [Required] 用于指定具体 GTest 可执行目标
multi_value_keywords:
PY_CMD_SETUP : [Required] 输出 Python 场景命令行配置
PY_ENV_LINES : [Required] 输出 Python 场景环境变量(按照 "K=V" 格式组织)
BASH_CMD_SETUP : [Required] 输出 bash 场景命令行配置(内部包含命令行配置+环境变量配置)
LD_LIBRARIES_EXT : [Optional] 需要在执行时将所在路径配置到环境变量 LD_LIBRARY_PATH 中的 Libraries
CMD_SETUP_EXT : [Optional] 附加命令行配置, 要求调用者设置 export 及多命令行配置间的 && 连接
ENV_LINES_EXT : [Optional] 附加环境变量配置(按照 "K=V" 格式组织)
]]
function(PTO_Fwk_GTest_RunExe_GetPreExecSetup PY_CMD_SETUP PY_ENV_LINES BASH_CMD_SETUP)
cmake_parse_arguments(
ARG
""
"TARGET"
"LD_LIBRARIES_EXT;CMD_SETUP_EXT;ENV_LINES_EXT"
""
${ARGN}
)
# 命令行
set(CmdSetup)
# 处理变量 CMD_SETUP_EXT
if (NOT "${ARG_CMD_SETUP_EXT}x" STREQUAL "x")
list(APPEND CmdSetup ${ARG_CMD_SETUP_EXT})
endif ()
# 处理变量内部处理(XSan 相关处理)
if (ENABLE_ASAN OR ENABLE_UBSAN)
if (NOT "${CmdSetup}x" STREQUAL "x")
list(APPEND CmdSetup &&)
endif ()
list(APPEND CmdSetup ulimit -s 32768)
endif ()
# 环境变量
set(EnvLines)
# 处理变量 LD_LIBRARIES_EXT 及环境变量 LD_LIBRARY_PATH 及 CMAKE_LIBRARY_OUTPUT_DIRECTORY
# 1. 当前 UTest/STest 已把动态库生成路径设置到 CMAKE_LIBRARY_OUTPUT_DIRECTORY 路径下, 此处需增加该路径配置;
# 2. 保留 LD_LIBRARY_PATH_EXT 处理逻辑, 已供后续其他场景使用;
set(LD_LIBRARY_PATH_EXT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
foreach (LIBRARY ${ARG_LD_LIBRARIES_EXT})
add_dependencies(${ARG_TARGET} ${LIBRARY})
list(APPEND LD_LIBRARY_PATH_EXT "$<TARGET_FILE_DIR:${LIBRARY}>")
endforeach ()
string(REPLACE ";" ":" LD_LIBRARY_PATH_EXT "${LD_LIBRARY_PATH_EXT}")
set(LD_LIBRARY_PATH "LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}")
if (NOT "${LD_LIBRARY_PATH_EXT}x" STREQUAL "x")
set(LD_LIBRARY_PATH "LD_LIBRARY_PATH=${LD_LIBRARY_PATH_EXT}:$ENV{LD_LIBRARY_PATH}")
endif ()
list(APPEND EnvLines ${LD_LIBRARY_PATH})
# 处理环境变量 PATH
# 处理变量 ENV_SETUP_EXT
list(REMOVE_ITEM ARG_ENV_LINES_EXT export)
list(REMOVE_ITEM ARG_ENV_LINES_EXT &)
list(REMOVE_ITEM ARG_ENV_LINES_EXT &&)
if (NOT "${ARG_ENV_LINES_EXT}x" STREQUAL "x")
list(APPEND EnvLines ${ARG_ENV_LINES_EXT})
endif ()
# 处理 ASAN / UBSAN 场景
if (ENABLE_ASAN OR ENABLE_UBSAN)
if (NOT "${XSAN_LD_PRELOAD}x" STREQUAL "x")
list(APPEND EnvLines ${XSAN_LD_PRELOAD})
endif ()
endif ()
# 输出处理
set(PyCmdSetup ${CmdSetup})
if (NOT "${PyCmdSetup}x" STREQUAL "x")
list(APPEND PyCmdSetup &&)
endif ()
set(${PY_CMD_SETUP} ${PyCmdSetup} PARENT_SCOPE)
# 输出处理
set(XSan_Options)
if (ENABLE_ASAN OR ENABLE_UBSAN)
set(XSan_Options ${ASAN_OPTIONS} ${UBSAN_OPTIONS})
endif ()
set(PyEnvLines ${EnvLines} ${XSan_Options})
set(${PY_ENV_LINES} ${PyEnvLines} PARENT_SCOPE)
# 输出处理
set(BashSetup)
if (NOT "${EnvLines}x" STREQUAL "x")
foreach (_line ${EnvLines})
if (NOT "${BashSetup}x" STREQUAL "x")
list(APPEND BashSetup &&)
endif ()
list(APPEND BashSetup export ${_line})
endforeach ()
endif ()
if (NOT "${CmdSetup}x" STREQUAL "x")
if (NOT "${BashSetup}x" STREQUAL "x")
list(APPEND BashSetup &&)
endif ()
list(APPEND BashSetup ${CmdSetup})
endif ()
# XSan 特殊处理(XSan_Options)
# 1. 当其存在时, 其需要在 BashSetup 尾部, 其前需要 && 与前述命令行连接, 其后不需要补充 && 连接符
# 2. 当不存在时, BashSetup 尾部需要补充 && 连接符;
if (NOT "${BashSetup}x" STREQUAL "x")
list(APPEND BashSetup &&)
endif ()
if (NOT "${XSan_Options}x" STREQUAL "x")
list(APPEND BashSetup ${XSan_Options})
endif ()
set(${BASH_CMD_SETUP} ${BashSetup} PARENT_SCOPE)
endfunction()
# GTest 添加可执行程序
#[[
Parameters:
one_value_keywords:
TARGET : [Required] 用于指定具体 GTest 可执行目标, 用例会在该目标编译完成后(POST_BUILD)启动执行
multi_value_keywords:
SOURCES : [Optional] 额外的编译源码
PRIVATE_INCLUDE_DIRECTORIES : [Optional] Private 头文件查找路径
PRIVATE_LINK_LIBRARIES : [Optional] Private 链接库
]]
function(PTO_Fwk_GTest_AddExe)
cmake_parse_arguments(
ARG
""
"TARGET"
"SOURCES;PRIVATE_INCLUDE_DIRECTORIES;PRIVATE_LINK_LIBRARIES"
""
${ARGN}
)
add_executable(${ARG_TARGET})
target_sources(${ARG_TARGET}
PRIVATE
${ARG_SOURCES}
${PTO_FWK_SRC_ROOT}/framework/tests/main.cpp
)
target_include_directories(${ARG_TARGET}
PRIVATE
${ARG_PRIVATE_INCLUDE_DIRECTORIES}
)
target_compile_definitions(${ARG_TARGET}
PRIVATE
$<$<BOOL:${BUILD_WITH_CANN}>:BUILD_WITH_CANN>
$<$<BOOL:${ENABLE_UTEST}>:ENABLE_UTEST>
$<$<BOOL:${ENABLE_STEST}>:ENABLE_STEST>
)
target_link_libraries(${ARG_TARGET}
PRIVATE
GTest::gtest
-Wl,--no-as-needed
-Wl,--whole-archive
${ARG_PRIVATE_LINK_LIBRARIES}
-Wl,--as-needed
-Wl,--no-whole-archive
-rdynamic
)
# 模拟配置文件 Install 流程, 为便于调试, 使用创建软连接方式模拟安装
get_filename_component(InstallConfigsDir "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/configs" REALPATH)
add_custom_command(
TARGET ${ARG_TARGET} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory ${InstallConfigsDir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${InstallConfigsDir}
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/framework/src/interface/configs/*.json" "${InstallConfigsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/framework/src/passes/pass_config/tile_fwk_platform_info.json" "${InstallConfigsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/framework/src/platform/parser/platforminfo.ini" "${InstallConfigsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/framework/src/platform/parser/simulation_platform/platform_config/*.ini" "${InstallConfigsDir}/"
COMMENT "Soft link of configs(*.json) has been created at ${InstallConfigsDir}"
)
# 模拟脚本文件 Install 流程, 为便于调试, 使用创建软连接方式模拟安装
get_filename_component(InstallScriptsDir "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/scripts" REALPATH)
add_custom_command(
TARGET ${ARG_TARGET} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory ${InstallScriptsDir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${InstallScriptsDir}
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/tools/profiling/draw_swim_lane.py" "${InstallScriptsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/framework/src/cost_model/simulation/scripts/draw_pipe_swim_lane.py" "${InstallScriptsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/framework/src/cost_model/simulation/scripts/draw_comm_swim_lane_png.py" "${InstallScriptsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/framework/src/cost_model/simulation/scripts/print_swim_lane.py" "${InstallScriptsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/tools/profiling/function_json_convert.py" "${InstallScriptsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/tools/profiling/parse_pipe_time_trace.py" "${InstallScriptsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/tools/scripts/machine_perf_trace.py" "${InstallScriptsDir}/"
COMMAND ln -sf "${PTO_FWK_SRC_ROOT}/tools/scripts/extract_pass_log.py" "${InstallScriptsDir}/"
COMMENT "Soft link of scripts has been created at ${InstallScriptsDir}"
)
# 模拟头文件 Install 流程, 为便于调试, 使用创建软连接方式模拟安装
get_filename_component(InstallIncludeDir "${PTO_FWK_BIN_OUTPUT_ROOT}/include" REALPATH)
add_custom_command(
TARGET ${ARG_TARGET} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory ${InstallIncludeDir}/
COMMAND ${CMAKE_COMMAND} -E make_directory ${InstallIncludeDir}/
COMMAND ln -sf ${PTO_FWK_SRC_ROOT}/framework/include/tilefwk ${InstallIncludeDir}
COMMENT "Soft link of include directory has been created at ${InstallIncludeDir}"
)
get_filename_component(InstallLibIncludeDir "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/include" REALPATH)
add_custom_command(
TARGET ${ARG_TARGET} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory ${InstallLibIncludeDir}/
COMMAND ${CMAKE_COMMAND} -E make_directory ${InstallLibIncludeDir}/
COMMAND ln -sf ${PTO_FWK_SRC_ROOT}/framework/src/interface/tileop ${InstallLibIncludeDir}
COMMAND ln -sf ${PTO_FWK_SRC_ROOT}/framework/src/interface/machine/device/tilefwk ${InstallLibIncludeDir}
COMMENT "Soft link of library include directory has been created at ${InstallLibIncludeDir}"
)
endfunction()
# 用于获取 GTestFilter(str)
#[[
Parameters:
one_value_keywords:
CLASSIFY : [Required] Classify 配置文件
TESTS_TYPE : [Required] 测试类型, 支持 [utest, stest]
TESTS_GROUP : [Optional] 测试分组
CHANGED_FILE : [Optional] 修改文件
]]
function(PTO_Fwk_GTest_GetGTestFilterStr GTEST_FILTER_STR)
cmake_parse_arguments(
ARG
""
"CLASSIFY;TESTS_TYPE;TESTS_GROUP;CHANGED_FILE"
""
""
${ARGN}
)
get_filename_component(_Py "${PTO_FWK_SRC_ROOT}/cmake/scripts/analysis_changed_files.py" REALPATH)
set(_Args "-r=${ARG_CLASSIFY}" "-t=${ARG_TESTS_TYPE}")
if (ARG_TESTS_GROUP AND NOT "${ARG_TESTS_GROUP}" STREQUAL "ON")
string(REPLACE ":" "," TestsGroupStr "${ARG_TESTS_GROUP}")
list(APPEND _Args "-g=${TestsGroupStr}")
endif ()
if (ARG_CHANGED_FILE AND NOT "${ARG_CHANGED_FILE}" STREQUAL "ON")
list(APPEND _Args "-c=${ARG_CHANGED_FILE}")
endif ()
execute_process(
COMMAND ${Python3_EXECUTABLE} ${_Py} ${_Args}
OUTPUT_VARIABLE OutputVariable
)
string(REPLACE "," ":" OutputVariable "${OutputVariable}")
set(${GTEST_FILTER_STR} ${OutputVariable} PARENT_SCOPE)
endfunction()
# GTest 按模块添加路径
#[[
Parameters:
one_value_keywords:
MARK : [Required] 标识测试类型
DIR : [Required] 待添加的模块名(与子路径同名)
multi_value_keywords:
MODULE_LIST : [Optional] 配置的模块名列表
]]
function(PTO_Fwk_GTest_AddModuleDir)
cmake_parse_arguments(
ARG
""
"MARK;DIR"
"MODULE_LIST"
""
${ARGN}
)
if ((NOT ARG_MODULE_LIST) OR "${ARG_MODULE_LIST}x" STREQUAL "ONx")
set(_TestModuleList "ALL")
else ()
string(REPLACE "," ";" _TestModuleList "${ARG_MODULE_LIST}")
string(REPLACE ":" ";" _TestModuleList "${_TestModuleList}")
endif ()
if (("${_TestModuleList}" STREQUAL "ALL") OR ("${ARG_DIR}" IN_LIST _TestModuleList))
add_subdirectory(${ARG_DIR})
message(STATUS "${ARG_MARK} Add module(${ARG_DIR})")
endif()
endfunction()