Files
arcs/arcs-sdk/cmake/extensions.cmake
2026-08-13 16:50:52 +08:00

416 lines
14 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
add_library(listenai_interface INTERFACE "")
# 简介: 定义一个名称为`_name`的静态库
# 参数:
# + _name 指定该静态库的名称
macro(listenai_library_named _name)
add_library(${_name} STATIC "")
set(LISTENAI_CURRENT_LIBRARY ${_name})
listenai_append_cmake_library(${_name})
target_link_libraries(${_name} PUBLIC listenai_interface)
endmacro()
macro(listenai_psram_library_named _name)
listenai_library_named(psram_${_name})
endmacro()
# 简介: 为当前的目标添加源文件
# 提示: 必须在使用`listenai_library_named`之后使用
# 参数:
# + source 源文件
# + ${ARGN} 可不參數
#
# 使用示例:
# ```
# listenai_library_sources(test.c test1.c test2.c test3.c)
# ```
function(listenai_library_sources source)
target_sources(${LISTENAI_CURRENT_LIBRARY} PRIVATE ${source} ${ARGN})
endfunction()
# 简介: 当配置有效时,为当前的目标添加源文件
# 提示: 必须在使用`listenai_library_named`之后使用
# 参数:
# + feature_toggle 配置选项
# + ${ARGN} 可不參數
#
# 使用示例:
# 当`CONFIG_TEST`有效时,将添加源文件
# ```
# listenai_library_sources_ifdef(CONFIG_TEST test.c test1.c test2.c test3.c)
# ```
#
function(listenai_library_sources_ifdef feature_toggle)
if(${${feature_toggle}})
listenai_library_sources(${ARGN})
endif()
endfunction()
# 简介: 为当前的目标提添加编译选项
# 提示: 必须在使用`listenai_library_named`之后使用
# 参数:
# + scope 作用范围, 可选择:PRIVATE, PUBLIC
# + option 编译选项
# + ${ARGN} 可不參數
function(listenai_library_compile_options scope option)
target_compile_options(${LISTENAI_CURRENT_LIBRARY} ${scope} ${option} ${ARGN})
endfunction()
# 简介: 当配置项有效时, 为当前的目标提添加编译选项
# 提示: 必须在使用`listenai_library_named`之后使用
# 参数:
# + feature_toggle 配置项
# + scope 作用范围, 可选择:PRIVATE, PUBLIC
# + option 编译选项
# + ${ARGN} 可不參數
function(listenai_library_compile_options_ifdef feature_toggle scope option)
if(${${feature_toggle}})
target_compile_options(${LISTENAI_CURRENT_LIBRARY} ${scope} ${option} ${ARGN})
endif()
endfunction()
# 简介: 将指定的目标添加到`LISTENAI_LIBS`属性中
# 参数:
# + library 待添加的目标
function(listenai_append_cmake_library library)
set_property(GLOBAL APPEND PROPERTY LISTENAI_LIBS ${library})
endfunction()
# 简介: 当配置有效时, 添加子目录
# 参数:
# + feature_toggle 配置项
# + dir 子目录
function(listenai_add_subdirectory_ifdef feature_toggle dir)
if(${${feature_toggle}})
add_subdirectory(${dir})
endif()
endfunction()
# 简介: 当配置有效时, 为指定的目标添加源文件
# 参数:
# + feature_toggle 配置项
# + target 指定的目标
# + scope 作用范围,PRIVATE PUBLIC INTERFACE
# + item 源文件
# + ${ARGN} 可不參數
function(listenai_target_sources_ifdef feature_toggle target scope item)
if(${${feature_toggle}})
target_sources(${target} ${scope} ${item} ${ARGN})
endif()
endfunction()
# 简介: 当配置有效时, 为指定的目标添添加宏定义
# 参数:
# + feature_toggle 配置项
# + target 指定的目标
# + scope 作用范围 PRIVATE, PUBLIC, INTERFACE
# + item 宏定义
# + ${ARGV} 可变参数
function(listenai_target_compile_definitions_ifdef feature_toggle target scope item)
if(${${feature_toggle}})
target_compile_definitions(${target} ${scope} ${item} ${ARGN})
endif()
endfunction()
# 简介: 当配置有效时, 为指定的目标添加头文件路径
# 参数:
# + feature_toggle 配置项
# + target 指定的目标
# + scope 作用范围 PRIVATE, PUBLIC, INTERFACE
# + item 待被链接的目标
# + ${ARGV} 可变参数
function(listenai_target_include_directories_ifdef feature_toggle target scope item)
if(${${feature_toggle}})
target_include_directories(${target} ${scope} ${item} ${ARGN})
endif()
endfunction()
# 简介: 当配置有效时, 为指定的目标连接其他目标
# 参数:
# + feature_toggle 配置项
# + target 指定的目标
# + item 待被链接的目标
# + ${ARGV} 可变参数
function(listenai_target_link_libraries_ifdef feature_toggle target item)
if(${${feature_toggle}})
target_link_libraries(${target} ${item} ${ARGN})
endif()
endfunction()
# 简介: 当配置有效时, 添加全局的编译选项
# 参数:
# + feature_toggle 配置项
# + option 编译选项
# + ${ARGV} 可变参数
function(listenai_add_compile_option_ifdef feature_toggle option)
if(${${feature_toggle}})
add_compile_options(${option})
endif()
endfunction()
# 简介: 当配置有效时, 为指定的目标添加编译选项
# 参数:
# + feature_toggle 配置项
# + target 指定的目标
# + scope 作用范围
# + option 编译选项
# + ${ARGV} 可变参数
function(listenai_target_compile_option_ifdef feature_toggle target scope option)
if(${feature_toggle})
target_compile_options(${target} ${scope} ${option} ${ARGV})
endif()
endfunction()
# 简介: 为listenai_interface添加编译选项
# 参数:
# + ${ARGV} 可变参数
function(listenai_compile_options)
target_compile_options(listenai_interface INTERFACE ${ARGV})
endfunction()
# 简介: 为listenai_interface添加宏定义
# 参数:
# + ${ARGV} 可变参数
function(listenai_compile_definitions)
target_compile_definitions(listenai_interface INTERFACE ${ARGV})
endfunction()
# 简介: 当配置有效时, 为listenai_interface添加宏定义
# 参数:
# + feature_toggle 配置项
# + ${ARGV} 可变参数
function(listenai_compile_definitions_ifdef feature_toggle)
if(${${feature_toggle}})
listenai_compile_definitions(${ARGN})
endif()
endfunction()
# 简介: 将目标链接到listenai_interface中
# 参数:
# + item 被连接的目标
function(listenai_link_libraries item)
target_link_libraries(listenai_interface INTERFACE ${item} ${ARGV})
foreach(arg ${ARGV})
set_property(GLOBAL APPEND PROPERTY LISTENAI_LIBS ${arg})
endforeach()
endfunction()
# 简介: 将头文件加入listenai_interface中
# 参数:
# + target_name 目标
function(listenai_include_directories)
foreach(arg ${ARGV})
if(IS_ABSOLUTE ${arg})
set(path ${arg})
else()
set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg})
endif()
target_include_directories(listenai_interface INTERFACE ${path})
endforeach()
endfunction()
# 简介: 为目标生成bin文件
# 参数:
# + target_name 目标
macro(listenai_generate_bin target_name)
add_custom_command(
TARGET ${target_name} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "-- Genarating file: ${target_name}.bin"
COMMAND ${CMAKE_OBJCOPY} -S -O binary ${target_name} ${target_name}.bin
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endmacro()
# 简介: 为目标生成hex文件
# 参数:
# + target_name 目标
macro(listenai_generate_hex target_name)
add_custom_command(
TARGET ${target_name} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "-- Genarating file: ${target_name}.hex"
COMMAND ${CMAKE_OBJCOPY} -S -O ihex
${target_name}
${target_name}.hex
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endmacro()
# 简介: 为目标生成调试信息包括反汇编、ELF头、符号表等
# 参数:
# + target_name 目标
macro(listenai_generate_debug_files target_name)
add_custom_command(
TARGET ${target_name} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "-- Genarating file: ${target_name}.lst"
COMMAND ${CMAKE_OBJDUMP} -d -S ${target_name} > ${target_name}.lst
COMMAND ${CMAKE_READELF} -a ${target_name} > ${target_name}.relf
COMMAND ${CMAKE_NM} -CSsnl -f sysv ${target_name} > ${target_name}.symb
COMMAND ${CMAKE_SIZE} -B ${target_name}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endmacro()
# 简介: 将所有通过listenai cmake扩展定义的目标连接到指定的目标中
# 参数:
# + target_name 将要链接到的目标
macro(listenai_link_all_modules target_name)
get_property(LISTENAI_LIBS_PROPERTY GLOBAL PROPERTY LISTENAI_LIBS)
list(REMOVE_DUPLICATES LISTENAI_LIBS_PROPERTY)
# 获取目标已手动链接的库,避免重复链接
get_target_property(_existing_libs ${target_name} LINK_LIBRARIES)
if(_existing_libs)
list(REMOVE_ITEM LISTENAI_LIBS_PROPERTY ${_existing_libs})
endif()
if (LISTENAI_LIBS_PROPERTY)
# 硬编码排除libm.a以避免符号冲突
# 2025.02版本工具链lib.m存在两个frexpl实现经芯来原厂沟通两个实现都可用
set(EXCLUDE_LIB_NAME "m")
set(WHOLE_ARCHIVE_LIBS)
set(NORMAL_LIBS)
# 分离需要全量链接的库和普通库
foreach(lib ${LISTENAI_LIBS_PROPERTY})
set(is_excluded FALSE)
# 检查库名是否匹配排除的库
if(lib MATCHES "lib${EXCLUDE_LIB_NAME}\\.(a|so)$" OR lib STREQUAL "${EXCLUDE_LIB_NAME}")
set(is_excluded TRUE)
endif()
if(is_excluded)
list(APPEND NORMAL_LIBS ${lib})
else()
list(APPEND WHOLE_ARCHIVE_LIBS ${lib})
endif()
endforeach()
set(LINK_START_CMD)
set(LINK_END_CMD)
if (DEFINED CONFIG_LINK_OPTION_LISTENAI_LIBRARY_GROUP)
list(APPEND LINK_START_CMD "-Wl,--start-group")
list(APPEND LINK_END_CMD "-Wl,--end-group")
endif()
# 根据whole-archive配置选择链接方式
if (DEFINED CONFIG_LINK_OPTION_LISTENAI_LIBRARY_WHOLE_ARCHIVE)
# 开启了whole-archive分别链接全量库和普通库
if (WHOLE_ARCHIVE_LIBS)
target_link_libraries(${target_name} PRIVATE
${LINK_START_CMD}
"-Wl,--whole-archive"
${WHOLE_ARCHIVE_LIBS}
"-Wl,--no-whole-archive"
${LINK_END_CMD})
endif()
if(NORMAL_LIBS)
target_link_libraries(${target_name} PRIVATE ${NORMAL_LIBS})
endif()
else()
# 没有开启whole-archive使用原来的逻辑
target_link_libraries(${target_name} PRIVATE ${LINK_START_CMD} ${LISTENAI_LIBS_PROPERTY} ${LINK_END_CMD})
endif()
endif()
endmacro()
# 添加可执行文件
# 此宏会自动为可执行文件添加bin,hex,lst文件输出
# 此宏会自动扫描LISTENAI_MODULES_DIR_LIST 列表中的目录, 并添加模块到构建系统中
macro(listenai_add_executable name)
set(LISTENAI_EXECUTABLE_NAME ${name})
add_executable(${name})
target_sources(${name} PRIVATE ${LISTENAI_CMAKE_PATH}/empty.c)
listenai_generate_bin(${name})
listenai_generate_hex(${name})
if(CONFIG_COMPILE_OPTION_GENERATE_DEBUG_FILES)
listenai_generate_debug_files(${name})
endif()
if(LISTENAI_ADD_BIN_HEADR)
listenai_generate_boot_header(${name})
endif()
# 立即扫描并添加模块,但延迟链接操作
# 这样可以确保所有 add_subdirectory 执行完后再链接,不受调用顺序影响
get_property(LISTENAI_MODULES_PROPERTY GLOBAL PROPERTY LISTENAI_MODULES)
foreach(module IN LISTS LISTENAI_MODULES_PROPERTY)
message(STATUS "Found module: ${module} ")
add_subdirectory(${module} ${CMAKE_BINARY_DIR}/modules/${module})
endforeach()
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
# 延迟链接到配置阶段末尾,确保用户的 add_subdirectory 也执行完成
cmake_language(DEFER CALL listenai_link_all_modules ${name})
else()
# CMake 版本过低,无法使用 DEFER 机制
message(FATAL_ERROR "CMake 3.19 or higher is required, but current version is ${CMAKE_VERSION}")
endif()
set(LISTENAI_CURRENT_LIBRARY "_inner_app")
set(LISTENAI_EXECUTABLE_COMPLETED TRUE)
endmacro()
# 为可执行文件添加listenai boot header
macro(listenai_generate_boot_header target_name)
add_custom_target(
mkhdr ALL
COMMAND ${CMAKE_COMMAND} -E echo "-- Genarating ListenAI Boot Header for ${target_name}.bin"
COMMAND ${LISTENAI_TOOLS_MKHDR} ${target_name}.bin
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
add_dependencies(mkhdr ${target_name})
endmacro()
macro(listenai_set_linker_script linker_script)
get_property(LISTENAI_LINK_SCRIPTS_PROPERTY GLOBAL PROPERTY LISTENAI_LINK_SCRIPTS)
get_property(INCLUDE_DIRS TARGET listenai_interface PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
get_property(LISTENAI_IF_DEFINITIONS TARGET listenai_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS)
set(INCLUDE_FLAGS "")
foreach(dir ${INCLUDE_DIRS})
list(APPEND INCLUDE_FLAGS "-I${dir}")
endforeach()
set(LISTENAI_IF_DEFINITIONS_FLAGS "")
foreach(flag ${LISTENAI_IF_DEFINITIONS})
list(APPEND LISTENAI_IF_DEFINITIONS_FLAGS "-D${flag}")
endforeach()
if(LISTENAI_LINK_SCRIPTS_PROPERTY)
add_custom_target(linker_script_prepare
COMMAND cat ${linker_script} ${LISTENAI_LINK_SCRIPTS_PROPERTY} > ${CMAKE_BINARY_DIR}/linker.ld.pre
DEPENDS ${linker_script} ${LISTENAI_LINK_SCRIPTS_PROPERTY}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
else()
add_custom_target(linker_script_prepare
COMMAND cp ${linker_script} ${CMAKE_BINARY_DIR}/linker.ld.pre
DEPENDS ${linker_script}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
add_custom_target(generate_linker_script
COMMAND ${CMAKE_C_COMPILER}
-E
-P
-x assembler-with-cpp
${INCLUDE_FLAGS}
${LISTENAI_IF_DEFINITIONS_FLAGS}
-include autoconf.h
${CMAKE_BINARY_DIR}/linker.ld.pre
-o ${CMAKE_BINARY_DIR}/linker.ld
DEPENDS linker_script_prepare
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
add_dependencies(${LISTENAI_EXECUTABLE_NAME} generate_linker_script)
target_link_options(${LISTENAI_EXECUTABLE_NAME} PRIVATE "-T${CMAKE_BINARY_DIR}/linker.ld")
endmacro()
macro(listenai_append_linker_script linker_script)
set_property(GLOBAL APPEND PROPERTY LISTENAI_LINK_SCRIPTS ${linker_script})
endmacro()