chore: migrate project into clean repository

This commit is contained in:
yuuux
2026-08-13 16:50:52 +08:00
commit d1d25a09e7
27405 changed files with 9422808 additions and 0 deletions

78
arcs-sdk/cmake/Kconfig Normal file
View File

@@ -0,0 +1,78 @@
menu "Common Compile and Link Options"
config DEBUG
bool "debug"
default y
choice
prompt "optimize level"
default COMPILE_OPTION_OPTIMIZE_LEVEL_OS
config COMPILE_OPTION_OPTIMIZE_LEVEL_O0
bool "O0"
config COMPILE_OPTION_OPTIMIZE_LEVEL_O1
bool "O1"
config COMPILE_OPTION_OPTIMIZE_LEVEL_O2
bool "O2"
config COMPILE_OPTION_OPTIMIZE_LEVEL_O3
bool "O3"
config COMPILE_OPTION_OPTIMIZE_LEVEL_OS
bool "OS"
endchoice
config LINK_OPTION_LISTENAI_LIBRARY_WHOLE_ARCHIVE
bool "whole arch link"
default y
help
Enable whole archive link option for listenai libraries (libm.a is automatically excluded)
config LINK_OPTION_LISTENAI_LIBRARY_GROUP
bool "group link"
default n
help
Enable group link option for listenai libraries
config LINK_OPTION_GC_SECTIONS
bool "gc sections"
default y
config COMPILE_OPTION_GENERATE_DEBUG_FILES
bool "generate debug files"
default y
help
Enable generate debug files like lst, relf, symbol table, etc
config COMPILE_OPTION_WARNING_AS_ERROR
bool "warning as error"
default n
config COMPILE_OPTION_WARNING_ALL
bool "warning all"
default n
config COMPILE_OPTION_WARNING_DISABLE
bool "warning disable"
default n
config FPU
bool "fpu"
default n
config PRINT_MEMORY_USAGE
bool "print memory usage"
default y
choice
prompt "link options specs"
default LINK_OPTION_NONE_SPECS
config LINK_OPTION_NOSYS_SPECS
bool "link options nosys specs"
config LINK_OPTION_NANO_SPECS
bool "link options nano specs"
config LINK_OPTION_NONE_SPECS
bool "link options none specs"
endchoice
endmenu

View File

@@ -0,0 +1,10 @@
set(CORE_FLAGS -mtune=nuclei-300-series -msave-restore)
if (CONFIG_FPU)
set(FPU_FLAGS -march=rv32imafc_zba_zbb_zbc_zbs -mabi=ilp32f)
else()
set(FPU_FLAGS -march=rv32imac_zba_zbb_zbc_zbs -mabi=ilp32)
endif()
add_compile_options(${CORE_FLAGS} ${FPU_FLAGS})
add_link_options(${CORE_FLAGS} ${FPU_FLAGS})

View File

@@ -0,0 +1,44 @@
if (NOT DEFINED NUCLEI_TOOLCHAIN_PATH)
if(DEFINED ENV{NUCLEI_TOOLCHAIN_PATH})
set(NUCLEI_TOOLCHAIN_PATH $ENV{NUCLEI_TOOLCHAIN_PATH})
else()
if (NOT DEFINED LISTENAI_TOOLS_PATH)
message(FATAL_ERROR "NUCLEI_TOOLCHAIN_PATH is not defined")
else()
set(NUCLEI_TOOLCHAIN_PATH ${LISTENAI_TOOLS_PATH}/nuclei-toolchain)
endif()
endif()
endif()
string(REPLACE "\\" "/" NUCLEI_TOOLCHAIN_PATH "${NUCLEI_TOOLCHAIN_PATH}")
set(TOOLCHAIN_PATH ${NUCLEI_TOOLCHAIN_PATH})
set(TOOLCHAIN_PREFIX riscv64-unknown-elf-)
set(TOOLCHAIN_SUFFIX )
if (WIN32)
set(TOOLCHAIN_SUFFIX .exe)
endif()
set(CROSS_COMPILE ${TOOLCHAIN_PATH}/bin/${TOOLCHAIN_PREFIX})
# Use ccache to speed up compilation if it is installed
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc${TOOLCHAIN_SUFFIX})
set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}g++${TOOLCHAIN_SUFFIX})
set(CMAKE_LINKER ${CROSS_COMPILE}ld${TOOLCHAIN_SUFFIX})
set(CMAKE_OBJCOPY ${CROSS_COMPILE}objcopy${TOOLCHAIN_SUFFIX})
set(CMAKE_OBJDUMP ${CROSS_COMPILE}objdump${TOOLCHAIN_SUFFIX})
set(CMAKE_READELF ${CROSS_COMPILE}readelf${TOOLCHAIN_SUFFIX})
set(CMAKE_SIZE ${CROSS_COMPILE}size${TOOLCHAIN_SUFFIX})
set(CMAKE_NM ${CROSS_COMPILE}nm${TOOLCHAIN_SUFFIX})
if (NOT EXISTS ${CMAKE_C_COMPILER})
message(FATAL_ERROR "Compile not found: ${CMAKE_C_COMPILER}")
endif()
message(STATUS "Found toolchain path: ${NUCLEI_TOOLCHAIN_PATH}")

View File

@@ -0,0 +1,67 @@
if (CONFIG_DEBUG)
add_compile_options(-g)
endif()
if (CONFIG_COMPILE_OPTION_OPTIMIZE_LEVEL_O0)
add_compile_options(-O0)
endif()
if (CONFIG_COMPILE_OPTION_OPTIMIZE_LEVEL_O1)
add_compile_options(-O1)
endif()
if (CONFIG_COMPILE_OPTION_OPTIMIZE_LEVEL_O2)
add_compile_options(-O2)
endif()
if (CONFIG_COMPILE_OPTION_OPTIMIZE_LEVEL_O3)
add_compile_options(-O3)
endif()
if (CONFIG_COMPILE_OPTION_OPTIMIZE_LEVEL_OS)
add_compile_options(-Os)
endif()
if (CONFIG_COMPILE_OPTION_WARNING_AS_ERROR)
add_compile_options(-Werror)
endif()
if (CONFIG_COMPILE_OPTION_WARNING_ALL)
add_compile_options(-Wall)
endif()
if (CONFIG_COMPILE_OPTION_WARNING_DISABLE)
add_compile_options(-w)
endif()
option(ENABLE_DEBUG_PATH "Enable debug path info" ON)
add_compile_options(-MMD)
add_compile_options(-Wno-comment)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-int-conversion>)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-implicit-function-declaration>)
add_compile_options(-fno-common)
add_compile_options(-fno-builtin-printf -fno-builtin-puts)
add_compile_options(-fno-omit-frame-pointer -fno-optimize-sibling-calls)
add_compile_options(-ffunction-sections -fdata-sections -ffast-math)
add_compile_options(-fdiagnostics-color=always)
# add_compile_options(-mcmodel=medlow)
if (ENABLE_DEBUG_PATH)
message(STATUS "ENABLE_DEBUG_PATH is ON")
else()
message(STATUS "ENABLE_DEBUG_PATH is OFF")
# 使用-ffile-prefix-map来减少调试信息中的路径长度从而固定SRAM占用
get_filename_component(ROOT_PROJECT_DIR ${CMAKE_CURRENT_LIST_DIR}/../.. ABSOLUTE)
add_compile_options("-ffile-prefix-map=${ROOT_PROJECT_DIR}=.")
# 移除符号表中的build目录前缀
get_filename_component(BUILD_DIR ${CMAKE_BINARY_DIR} ABSOLUTE)
add_compile_options("-ffile-prefix-map=${BUILD_DIR}=")
# 同时也处理工具链目录的路径
if(DEFINED ENV{NUCLEI_TOOLCHAIN_PATH})
add_compile_options("-ffile-prefix-map=$ENV{NUCLEI_TOOLCHAIN_PATH}=/toolchain")
endif()
endif()

View File

@@ -0,0 +1,19 @@
if (CONFIG_LINK_OPTION_GC_SECTIONS)
add_link_options(-Wl,--gc-sections)
endif()
if (CONFIG_PRINT_MEMORY_USAGE)
add_link_options(-Wl,--print-memory-usage)
endif()
if (CONFIG_LINK_OPTION_NOSYS_SPECS)
add_link_options(--specs=nosys.specs)
endif()
if (CONFIG_LINK_OPTION_NANO_SPECS)
add_link_options(--specs=nano.specs)
endif()
add_link_options(-Wl,--no-warn-rwx-segments)
add_link_options(-nostartfiles)
add_link_options(-static)

View File

@@ -0,0 +1,271 @@
# ListenAI Cmake扩展说明文档
### listenai_library_named
简介: 定义一个名称为`_name`的静态库
参数:
+ _name 指定该静态库的名称
### listenai_library_sources
简介: 为当前的目标添加源文件
提示: 必须在使用`listenai_library_named`之后使用
参数:
+ source 源文件
+ ${ARGN} 可不參數
使用示例:
```
listenai_library_sources(test.c test1.c test2.c test3.c)
```
### listenai_library_sources_ifdef
简介: 当配置有效时,为当前的目标添加源文件
提示: 必须在使用`listenai_library_named`之后使用
参数:
+ feature_toggle 配置选项
+ ${ARGN} 可不參數
使用示例:
当`CONFIG_TEST`有效时,将添加源文件
```
listenai_library_sources_ifdef(CONFIG_TEST test.c test1.c test2.c test3.c)
```
### listenai_library_compile_options
简介: 为当前的目标提添加编译选项
提示: 必须在使用`listenai_library_named`之后使用
参数:
+ scope 作用范围, 可选择:PRIVATE, PUBLIC
+ option 编译选项
+ ${ARGN} 可不參數
### listenai_library_compile_options_ifdef
简介: 当配置项有效时, 为当前的目标提添加编译选项
提示: 必须在使用`listenai_library_named`之后使用
参数:
+ feature_toggle 配置项
+ scope 作用范围, 可选择:PRIVATE, PUBLIC
+ option 编译选项
+ ${ARGN} 可不參數
### listenai_append_cmake_library
简介: 将指定的目标添加到`LISTENAI_LIBS`属性中
参数:
+ library 待添加的目标
### listenai_add_subdirectory_ifdef
简介: 当配置有效时, 添加子目录
参数:
+ feature_toggle 配置项
+ dir 子目录
### listenai_target_sources_ifdef
简介: 当配置有效时, 为指定的目标添加源文件
参数:
+ feature_toggle 配置项
+ target 指定的目标
+ scope 作用范围,PRIVATE PUBLIC INTERFACE
+ item 源文件
+ ${ARGN} 可不參數
### listenai_target_compile_definitions_ifdef
简介: 当配置有效时, 为指定的目标添添加宏定义
参数:
+ feature_toggle 配置项
+ target 指定的目标
+ scope 作用范围 PRIVATE, PUBLIC, INTERFACE
+ item 宏定义
+ ${ARGV} 可变参数
### listenai_target_include_directories_ifdef
简介: 当配置有效时, 为指定的目标添加头文件路径
参数:
+ feature_toggle 配置项
+ target 指定的目标
+ scope 作用范围 PRIVATE, PUBLIC, INTERFACE
+ item 待被链接的目标
+ ${ARGV} 可变参数
### listenai_target_link_libraries_ifdef
简介: 当配置有效时, 为指定的目标连接其他目标
参数:
+ feature_toggle 配置项
+ target 指定的目标
+ item 待被链接的目标
+ ${ARGV} 可变参数
### listenai_add_compile_option_ifdef
简介: 当配置有效时, 添加全局的编译选项
参数:
+ feature_toggle 配置项
+ option 编译选项
+ ${ARGV} 可变参数
### listenai_target_compile_option_ifdef
简介: 当配置有效时, 为指定的目标添加编译选项
参数:
+ feature_toggle 配置项
+ target 指定的目标
+ scope 作用范围
+ option 编译选项
+ ${ARGV} 可变参数
### listenai_compile_options
简介: 为listenai_interface添加编译选项
参数:
+ ${ARGV} 可变参数
### listenai_compile_definitions
简介: 为listenai_interface添加宏定义
参数:
+ ${ARGV} 可变参数
### listenai_compile_definitions_ifdef
简介: 当配置有效时, 为listenai_interface添加宏定义
参数:
+ feature_toggle 配置项
+ ${ARGV} 可变参数
### listenai_link_libraries
简介: 将目标链接到listenai_interface中
参数:
+ item 被连接的目标
### listenai_include_directories
简介: 将头文件加入listenai_interface中
参数:
+ target_name 目标
### listenai_generate_bin
简介: 为目标生成bin文件
参数:
+ target_name 目标
### listenai_generate_hex
简介: 为目标生成hex文件
参数:
+ target_name 目标
### listenai_generate_lst
简介: 为目标生成lst文件
参数:
+ target_name 目标
### listenai_link_all_modules
简介: 将所有通过listenai cmake扩展定义的目标连接到指定的目标中
参数:
+ target_name 将要链接到的目标
注意: 此函数通常不需要手动调用,会在 `listenai_add_executable` 中自动延迟调用
### listenai_add_executable
添加可执行文件
此宏会自动为可执行文件添加bin,hex,lst文件输出
此宏会自动扫描LISTENAI_MODULES_DIR_LIST 列表中的目录, 并添加模块到构建系统中
**重要特性:**
- 使用延迟链接机制(需要 CMake 3.19+
- 用户可以在 `listenai_add_executable` 之前或之后调用 `add_subdirectory` 添加库
- 所有库会被自动包含在 `--whole-archive` 链接选项中,确保未被引用的符号不被丢弃
**CMake 版本要求:**
- 最低版本: CMake 3.19
- 低于此版本会报 FATAL_ERROR
### listenai_executable_set_link_file
为可执行文件设置链接脚本
### listenai_generate_boot_header
为可执行文件添加listenai boot header

0
arcs-sdk/cmake/empty.c Normal file
View File

View File

@@ -0,0 +1,415 @@
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()

View File

@@ -0,0 +1,26 @@
# SPDX-License-Identifier: Apache-2.0
# ARCS SDK 版本头文件生成脚本
# 此脚本由主 CMakeLists.txt 通过 execute_process 调用
# 尝试获取 git 提交哈希
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS ${ARCS_SDK_BASE}/.git)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --abbrev=12 --always
WORKING_DIRECTORY ${ARCS_SDK_BASE}
OUTPUT_VARIABLE BUILD_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
endif()
# 如果未获取到 git 信息,设置为默认值
if(NOT BUILD_VERSION)
set(BUILD_VERSION "unknown")
endif()
# 从模板生成头文件
configure_file(${ARCS_SDK_BASE}/sdk_version.h.in ${OUT_FILE} @ONLY)
message(STATUS "生成版本头文件: ${OUT_FILE}")
message(STATUS " BUILD_VERSION: ${BUILD_VERSION}")

56
arcs-sdk/cmake/hex.cmake Normal file
View File

@@ -0,0 +1,56 @@
# SPDX-License-Identifier: Apache-2.0
# from https://gist.github.com/korzo89/71a6de0f388f7cf8b349101b0134060c
function(from_hex HEX DEC)
string(SUBSTRING "${HEX}" 2 -1 HEX)
string(TOUPPER "${HEX}" HEX)
set(_res 0)
string(LENGTH "${HEX}" _strlen)
while(_strlen GREATER 0)
math(EXPR _res "${_res} * 16")
string(SUBSTRING "${HEX}" 0 1 NIBBLE)
string(SUBSTRING "${HEX}" 1 -1 HEX)
if(NIBBLE STREQUAL "A")
math(EXPR _res "${_res} + 10")
elseif(NIBBLE STREQUAL "B")
math(EXPR _res "${_res} + 11")
elseif(NIBBLE STREQUAL "C")
math(EXPR _res "${_res} + 12")
elseif(NIBBLE STREQUAL "D")
math(EXPR _res "${_res} + 13")
elseif(NIBBLE STREQUAL "E")
math(EXPR _res "${_res} + 14")
elseif(NIBBLE STREQUAL "F")
math(EXPR _res "${_res} + 15")
else()
math(EXPR _res "${_res} + ${NIBBLE}")
endif()
string(LENGTH "${HEX}" _strlen)
endwhile()
set(${DEC} ${_res} PARENT_SCOPE)
endfunction()
function(to_hex DEC HEX)
while(DEC GREATER 0)
math(EXPR _val "${DEC} % 16")
math(EXPR DEC "${DEC} / 16")
if(_val EQUAL 10)
set(_val "A")
elseif(_val EQUAL 11)
set(_val "B")
elseif(_val EQUAL 12)
set(_val "C")
elseif(_val EQUAL 13)
set(_val "D")
elseif(_val EQUAL 14)
set(_val "E")
elseif(_val EQUAL 15)
set(_val "F")
endif()
set(_res "${_val}${_res}")
endwhile()
set(${HEX} "0x${_res}" PARENT_SCOPE)
endfunction()

View File

@@ -0,0 +1,252 @@
macro(import_kconfig prefix kconfig_fragment)
cmake_parse_arguments(IMPORT_KCONFIG "" "TARGET" "" ${ARGN})
file(
STRINGS
${kconfig_fragment}
DOT_CONFIG_LIST
REGEX "^${prefix}"
ENCODING "UTF-8"
)
foreach (CONFIG ${DOT_CONFIG_LIST})
# maybe prefix is empty string
if(CONFIG MATCHES "^#")
continue()
endif()
# CONFIG could look like: CONFIG_NET_BUF=y
# Match the first part, the variable name
string(REGEX MATCH "[^=]+" CONF_VARIABLE_NAME ${CONFIG})
# Match the second part, variable value
string(REGEX MATCH "=(.+$)" CONF_VARIABLE_VALUE ${CONFIG})
# The variable name match we just did included the '=' symbol. To just get the
# part on the RHS we use match group 1
set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1})
if("${CONF_VARIABLE_VALUE}" MATCHES "^\"(.*)\"$") # Is surrounded by quotes
set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1})
endif()
set(${CONF_VARIABLE_NAME} ${CONF_VARIABLE_VALUE})
endforeach()
endmacro()
if (NOT DEFINED APPLICATION_SOURCE_DIR)
set(APPLICATION_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
"Application Source Directory"
)
endif()
option(LISTENAI_SDK_KCONFIG_PARSE "kconfig parse" ON)
set(LISTENAI_MODULES_KCONFIG_FILE ${CMAKE_BINARY_DIR}/module.Kconfig)
if (EXISTS ${LISTENAI_MODULES_KCONFIG_FILE})
file(REMOVE ${LISTENAI_MODULES_KCONFIG_FILE})
endif()
get_property(LISTENAI_MODULES_PROPERTY GLOBAL PROPERTY LISTENAI_MODULES)
set(ENV{LISTENAI_MODULES} ${CMAKE_BINARY_DIR}/module.Kconfig)
file(APPEND ${LISTENAI_MODULES_KCONFIG_FILE} "menu \"modules\"\n")
file(APPEND ${LISTENAI_MODULES_KCONFIG_FILE} "osource \"${LISTENAI_CMAKE_PATH}/Kconfig\"\n")
foreach(module IN LISTS LISTENAI_MODULES_PROPERTY)
list(FIND LISTENAI_KCONFIG_CUSTOM_PARSE_DIR_LIST ${module} idx)
if (idx EQUAL -1)
if (EXISTS ${module}/Kconfig)
file(APPEND ${LISTENAI_MODULES_KCONFIG_FILE} "osource \"${module}/Kconfig\"\n")
endif()
endif()
endforeach()
file(APPEND ${LISTENAI_MODULES_KCONFIG_FILE} "endmenu\n")
macro(listenai_kconfig_parse kconfig_root dot_config autoconf_h kconfig_list conf_merge prefix)
message(STATUS "Parse kconfig: ${${kconfig_root}}, prefix: ${${prefix}}")
set(ENV{CONFIG_} ${${prefix}})
execute_process(
COMMAND
${LISTENAI_TOOLS_KCONFIG}
-k ${${kconfig_root}}
-c ${${dot_config}}
-H ${${autoconf_h}}
-l ${${kconfig_list}}
-m ${${conf_merge}}
WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR}
RESULT_VARIABLE result
)
if (NOT result EQUAL 0)
message(FATAL_ERROR "Kconfig parse failed, error code: ${result}")
endif()
import_kconfig("${${prefix}}" ${${dot_config}})
add_compile_options(-imacros${${autoconf_h}})
endmacro()
if (LISTENAI_SDK_KCONFIG_PARSE)
if (NOT EXISTS ${APPLICATION_SOURCE_DIR}/Kconfig)
set(KCONFIG_ROOT ${LISTENAI_SDK_BASE}/Kconfig)
else()
set(KCONFIG_ROOT ${APPLICATION_SOURCE_DIR}/Kconfig)
endif()
if (NOT DEFINED DOT_CONFIG)
set(DOT_CONFIG ${CMAKE_BINARY_DIR}/.config)
endif()
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/generated/include)
if (NOT DEFINED AUTOCONF_H)
set(AUTOCONF_H ${CMAKE_BINARY_DIR}/generated/include/autoconf.h)
endif()
if (NOT DEFINED KCONFIG_MERGE_LIST)
set(KCONFIG_MERGE_LIST "")
endif()
# 首先处理命令行CONFIG_*参数生成extra_kconfig_options.conf
unset(EXTRA_KCONFIG_OPTIONS)
get_cmake_property(cache_variable_names CACHE_VARIABLES)
foreach (name ${cache_variable_names})
if("${name}" MATCHES "^CONFIG_")
# When a cache variable starts with 'CONFIG_', it is assumed to be
# a Kconfig symbol assignment from the CMake command line.
set(EXTRA_KCONFIG_OPTIONS
"${EXTRA_KCONFIG_OPTIONS}\n${name}=${${name}}"
)
endif()
endforeach()
if(EXTRA_KCONFIG_OPTIONS)
set(EXTRA_KCONFIG_OPTIONS_FILE ${CMAKE_BINARY_DIR}/misc/generated/extra_kconfig_options.conf)
# 确保目录存在
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/misc/generated)
file(WRITE
${EXTRA_KCONFIG_OPTIONS_FILE}
${EXTRA_KCONFIG_OPTIONS}
)
endif()
if (NOT DEFINED KCONFIG_LIST)
set(KCONFIG_LIST ${CMAKE_BINARY_DIR}/kconfig.list)
endif()
if (EXISTS ${DOT_CONFIG})
list(APPEND KCONFIG_MERGE_LIST ${DOT_CONFIG})
endif()
if (NOT DEFINED CONFIG_DEFAULT)
set(CONFIG_DEFAULT ${APPLICATION_SOURCE_DIR}/prj.conf)
endif()
if (NOT IS_ABSOLUTE ${CONFIG_DEFAULT})
set(CONFIG_DEFAULT ${APPLICATION_SOURCE_DIR}/${CONFIG_DEFAULT})
endif()
if (EXISTS ${CONFIG_DEFAULT})
list(APPEND KCONFIG_MERGE_LIST ${CONFIG_DEFAULT})
endif()
if (EXISTS ${APPLICATION_SOURCE_DIR}/.config)
list(APPEND KCONFIG_MERGE_LIST ${APPLICATION_SOURCE_DIR}/.config)
endif()
if (EXISTS ${BOARD_DIR}/overlay.conf)
list(APPEND KCONFIG_MERGE_LIST ${BOARD_DIR}/overlay.conf)
message(STATUS "Added board overlay config: ${BOARD_DIR}/overlay.conf")
endif()
if (DEFINED CONFIG_FILES)
foreach(config_file IN LISTS CONFIG_FILES)
if (IS_ABSOLUTE ${config_file})
list(APPEND KCONFIG_MERGE_LIST ${config_file})
else()
list(APPEND KCONFIG_MERGE_LIST ${APPLICATION_SOURCE_DIR}/${config_file})
endif()
endforeach()
endif()
# 添加命令行CONFIG_*参数文件到合并列表的最后(最高优先级)
if(EXTRA_KCONFIG_OPTIONS_FILE AND EXISTS ${EXTRA_KCONFIG_OPTIONS_FILE})
list(APPEND KCONFIG_MERGE_LIST ${EXTRA_KCONFIG_OPTIONS_FILE})
message(STATUS "Added command-line CONFIG options file: ${EXTRA_KCONFIG_OPTIONS_FILE}")
endif()
string(JOIN " " KCONFIG_MERGE_LIST_STRING "${KCONFIG_MERGE_LIST}")
message(STATUS "Kconfig merge list: ${KCONFIG_MERGE_LIST_STRING}")
if (NOT DEFINED LISTENAI_KCONFIG_PREFIX)
set(LISTENAI_KCONFIG_PREFIX "CONFIG_")
endif()
# parse main kconfig
listenai_kconfig_parse(
KCONFIG_ROOT
DOT_CONFIG
AUTOCONF_H
KCONFIG_LIST
KCONFIG_MERGE_LIST_STRING
LISTENAI_KCONFIG_PREFIX
)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/kconfig/custom)
message(STATUS "Custom kconfig parse list: ${LISTENAI_KCONFIG_CUSTOM_PARSE_DIR_LIST}")
list(LENGTH LISTENAI_KCONFIG_CUSTOM_PARSE_PREFIX_LIST prefix_list_len)
foreach(item IN LISTS LISTENAI_KCONFIG_CUSTOM_PARSE_DIR_LIST)
get_filename_component(ITEM_DIRECTORY_NAME ${item} NAME)
string(TOLOWER ${ITEM_DIRECTORY_NAME} ITEM_DIRECTORY_NAME)
set(ITEM_KCONFIG_ROOT ${item}/Kconfig)
set(ITEM_DOTCONFIG ${CMAKE_BINARY_DIR}/kconfig/custom/${ITEM_DIRECTORY_NAME}.config)
set(ITEM_AUTOCONF_H ${CMAKE_BINARY_DIR}/generated/include/${ITEM_DIRECTORY_NAME}_autoconf.h)
set(ITEM_KCONFIG_LIST ${CMAKE_BINARY_DIR}/kconfig/custom/${ITEM_DIRECTORY_NAME}_kconfig.list)
list(FIND LISTENAI_KCONFIG_CUSTOM_PARSE_DIR_LIST ${item} idx)
if (${prefix_list_len} GREATER 0)
if (${idx} LESS ${prefix_list_len})
list(GET LISTENAI_KCONFIG_CUSTOM_PARSE_PREFIX_LIST ${idx} ITEM_KCONFIG_PREFIX)
else()
math(EXPR idx "${prefix_list_len} - 1")
list(GET LISTENAI_KCONFIG_CUSTOM_PARSE_PREFIX_LIST ${idx} ITEM_KCONFIG_PREFIX)
endif()
else()
set(ITEM_KCONFIG_PREFIX "CONFIG_")
endif()
if (${ITEM_KCONFIG_PREFIX} STREQUAL "\"\"")
set(ITEM_KCONFIG_PREFIX "")
endif()
listenai_kconfig_parse(
ITEM_KCONFIG_ROOT
ITEM_DOTCONFIG
ITEM_AUTOCONF_H
ITEM_KCONFIG_LIST
KCONFIG_MERGE_LIST_STRING
ITEM_KCONFIG_PREFIX
)
endforeach()
endif()
add_custom_target(menuconfig
COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_BINARY_DIR}/.config.old
COMMAND ${CMAKE_COMMAND} -E env
LISTENAI_MODULES=${CMAKE_BINARY_DIR}/module.Kconfig
KCONFIG_CONFIG=${CMAKE_BINARY_DIR}/.config
${LISTENAI_TOOLS_MENUCONFIG}
WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR}
COMMENT "running menuconfig"
USES_TERMINAL
)
# 命令行CONFIG_*参数处理已移动到kconfig_setup函数内部确保在合并列表构建时可用

View File

@@ -0,0 +1,145 @@
set(LISTENAI_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR})
if (NOT DEFINED LISTENAI_TOOLS_PATH)
if (NOT DEFINED ENV{LISTENAI_TOOLS_PATH})
message(FATAL_ERROR "LISTENAI_TOOLS_PATH is not defined")
else()
set(LISTENAI_TOOLS_PATH $ENV{LISTENAI_TOOLS_PATH})
endif()
endif()
if (NOT DEFINED ARCS_SDK_BASE)
if (NOT DEFINED ENV{ARCS_BASE})
message(FATAL_ERROR "ARCS_BASE is not defined")
else()
set(ARCS_SDK_BASE $ENV{ARCS_BASE})
endif()
endif()
string(REPLACE "\\" "/" LISTENAI_TOOLS_PATH "${LISTENAI_TOOLS_PATH}")
set(LISTENAI_TOOLS_MKHDR ${LISTENAI_TOOLS_PATH}/mkhdr/mkhdr)
set(LISTENAI_TOOLS_KCONFIG ${LISTENAI_TOOLS_PATH}/kconfig/kconfig)
set(LISTENAI_TOOLS_MENUCONFIG ${LISTENAI_TOOLS_PATH}/menuconfig/menuconfig)
option(LISTENAI_ADD_BIN_HEADR "kconfig no generate header of bin " ON)
string(REPLACE "\\" "/" LISTENAI_CMAKE_PATH "${LISTENAI_CMAKE_PATH}")
if (NOT DEFINED LISTENAI_MODULES_DIR_LIST)
message(STATUS "LISTENAI_MODULES_DIR_LIST is not defined")
set(LISTENAI_MODULES_DIR_LIST "")
endif()
if(NOT LISTENAI_MODULES_DIR_LIST MATCHES "${ARCS_SDK_BASE}")
list(APPEND LISTENAI_MODULES_DIR_LIST "${ARCS_SDK_BASE}")
endif()
message(STATUS "LISTENAI_MODULES_DIR_LIST: ${LISTENAI_MODULES_DIR_LIST}")
function(check_tool tool_var tool_name)
if (NOT DEFINED ${tool_var})
message(FATAL_ERROR "${tool_name} is not defined")
endif()
if (NOT EXISTS ${${tool_var}})
message(FATAL_ERROR "Tool ${${tool_var}} does not exist")
endif()
string(REPLACE "\\" "/" ${tool_var} "${${tool_var}}")
message(STATUS "Found ${tool_name}: ${${tool_var}}")
endfunction()
check_tool(LISTENAI_TOOLS_KCONFIG "ListenAI Kconfig tool")
check_tool(LISTENAI_TOOLS_MKHDR "ListenAI mkhdr tool")
include(${LISTENAI_CMAKE_PATH}/hex.cmake)
# 包含版本管理(在 kconfig 之前,因为 kconfig 可能依赖版本信息)
include(${LISTENAI_CMAKE_PATH}/version.cmake)
message(STATUS "Listenai module dir list: ${LISTENAI_MODULES_DIR_LIST}")
# 从指定的目录中查询模块,并将模块的路径存放到属性LISTENAI_MODULES中
function(listenai_find_modules dir)
set(cmake_lists_path "${dir}/CMakeLists.txt")
get_filename_component(DIRECTORY_NAME ${dir} NAME)
if(EXISTS "${cmake_lists_path}")
get_filename_component(module_abs_path "${dir}" ABSOLUTE)
set_property(GLOBAL APPEND PROPERTY LISTENAI_MODULES ${module_abs_path})
message(STATUS "Found module: ${module_abs_path}")
return()
endif()
file(GLOB CHILD_DIRS LIST_DIRECTORIES TRUE "${dir}/*")
foreach(child_dir ${CHILD_DIRS})
if(IS_DIRECTORY ${child_dir})
listenai_find_modules(${child_dir})
endif()
endforeach()
endfunction()
foreach(dir ${LISTENAI_MODULES_DIR_LIST})
listenai_find_modules(${dir})
endforeach()
# 板型搜索逻辑(在 Kconfig 解析之前)
# 设置 BOARD_KCONFIG_PATH 环境变量,供 boards/Kconfig 动态加载板型配置
set(BOARD_DIR "")
if(DEFINED BOARD)
# 优先级1: 自定义板型路径
if(DEFINED BOARD_SEARCH_PATH)
if(EXISTS "${BOARD_SEARCH_PATH}/${BOARD}")
set(BOARD_DIR "${BOARD_SEARCH_PATH}/${BOARD}")
endif()
endif()
# 优先级2: SDK 内置板型
if(NOT BOARD_DIR)
if(EXISTS "${ARCS_SDK_BASE}/boards/${BOARD}")
set(BOARD_DIR "${ARCS_SDK_BASE}/boards/${BOARD}")
endif()
endif()
endif()
# 设置板型 Kconfig 路径环境变量
# 如果找到板型,设置为板型的 Kconfig 文件路径
# 如果未找到,设置为不存在的路径,让 osource 静默跳过(避免 Kconfig 解析错误)
if(BOARD_DIR AND EXISTS "${BOARD_DIR}/Kconfig")
set(ENV{BOARD_KCONFIG_PATH} "${BOARD_DIR}/Kconfig")
else()
# 设置为一个明确不存在的文件路径,让 osource 静默跳过
set(ENV{BOARD_KCONFIG_PATH} "${ARCS_SDK_BASE}/boards/.kconfig.not.found")
endif()
include(${LISTENAI_CMAKE_PATH}/kconfig.cmake)
include(${LISTENAI_CMAKE_PATH}/extensions.cmake)
if (NOT DEFINED CHIP)
set(CHIP arcs)
endif()
include(${LISTENAI_CMAKE_PATH}/${CHIP}-chip.cmake)
include(${LISTENAI_CMAKE_PATH}/${CHIP}-toolchain.cmake)
include(${LISTENAI_CMAKE_PATH}/common_compile_options.cmake)
include(${LISTENAI_CMAKE_PATH}/common_link_options.cmake)
listenai_include_directories(${CMAKE_BINARY_DIR}/generated/include)
listenai_library_named(_inner_app)
listenai_library_sources(${LISTENAI_CMAKE_PATH}/empty.c)
# 生成 SDK 版本头文件
execute_process(
COMMAND ${CMAKE_COMMAND}
-DARCS_SDK_BASE=${ARCS_SDK_BASE}
-DOUT_FILE=${CMAKE_BINARY_DIR}/generated/include/sdk_version.h
-DSDK_VERSION_MAJOR=${SDK_VERSION_MAJOR}
-DSDK_VERSION_MINOR=${SDK_VERSION_MINOR}
-DSDK_PATCHLEVEL=${SDK_PATCHLEVEL}
-DSDK_VERSION_STRING=${SDK_VERSION_STRING}
-DSDK_VERSION_CODE=${SDK_VERSION_CODE}
-DSDK_VERSION_NUMBER=${SDK_VERSION_NUMBER}
-DSDKVERSION=${SDKVERSION}
-P ${ARCS_SDK_BASE}/cmake/gen_version_h.cmake
WORKING_DIRECTORY ${ARCS_SDK_BASE}
)

View File

@@ -0,0 +1,48 @@
import re
import argparse
def line_startswith_keys(line, keys):
for k in keys:
if line.startswith(k):
pattern = rf'{k}\((\w+)'
match = re.search(pattern, line)
return match.group(1) if match else None
return None
def comments_section_get_by_keys(file_path, keys):
current_comment = []
extensions_dic = {}
with open(file_path, 'r', encoding='UTF-8') as f:
for line in f:
line = line.strip()
if line.startswith('#'):
current_comment.append(line)
else:
name = line_startswith_keys(line, keys)
if name is not None:
extensions_dic[name] = current_comment.copy()
current_comment.clear()
return extensions_dic
def save_comments_to_file(filepath,comments_dic):
with open(filepath, 'w', encoding='utf-8') as f:
f.write(f'# ListenAI Cmake扩展说明文档\n')
for k,v in comments_dic.items():
f.write(f'### {k}\n')
for line in v:
line = line.replace('#','').strip()
f.write(f'{line}\n\n')
def main():
parser = argparse.ArgumentParser(description='Extract comments from CMake files.')
parser.add_argument('input_file', type=str, help='Path to the input CMake file')
parser.add_argument('output_file', type=str, help='Path to the output Markdown file')
args = parser.parse_args()
cmake_keys= ['macro', 'function']
dic = comments_section_get_by_keys(args.input_file, cmake_keys)
save_comments_to_file(args.output_file, dic)
if __name__=='__main__':
main()

View File

@@ -0,0 +1,73 @@
# SPDX-License-Identifier: Apache-2.0
# ARCS SDK 版本管理
# 参考: VERSION_SYSTEM_REFERENCE_CN.md
# 包含十六进制转换工具
include(${ARCS_SDK_BASE}/cmake/hex.cmake)
# 读取 VERSION 文件
file(READ ${ARCS_SDK_BASE}/VERSION ver)
# 使用正则表达式解析每个版本组件
string(REGEX MATCH "VERSION_MAJOR = ([0-9]*)" _ ${ver})
set(PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1})
string(REGEX MATCH "VERSION_MINOR = ([0-9]*)" _ ${ver})
set(PROJECT_VERSION_MINOR ${CMAKE_MATCH_1})
string(REGEX MATCH "PATCHLEVEL = ([0-9]*)" _ ${ver})
set(PROJECT_VERSION_PATCH ${CMAKE_MATCH_1})
string(REGEX MATCH "VERSION_TWEAK = ([0-9]*)" _ ${ver})
set(PROJECT_VERSION_TWEAK ${CMAKE_MATCH_1})
string(REGEX MATCH "EXTRAVERSION = ([a-z0-9]*)" _ ${ver})
set(PROJECT_VERSION_EXTRA ${CMAKE_MATCH_1})
# 设置导出变量(用于 C 头文件)
set(SDK_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(SDK_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(SDK_PATCHLEVEL ${PROJECT_VERSION_PATCH})
# 构建版本字符串(不包含 TWEAK
set(PROJECT_VERSION_WITHOUT_TWEAK ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
# 构建完整版本TWEAK 非零时包含)
if(PROJECT_VERSION_TWEAK AND NOT PROJECT_VERSION_TWEAK EQUAL 0)
set(PROJECT_VERSION ${PROJECT_VERSION_WITHOUT_TWEAK}.${PROJECT_VERSION_TWEAK})
else()
set(PROJECT_VERSION ${PROJECT_VERSION_WITHOUT_TWEAK})
endif()
# 构建版本字符串(用于显示)
# 规则:优先显示 EXTRA其次显示 TWEAK最后显示基础版本
if(PROJECT_VERSION_EXTRA AND NOT PROJECT_VERSION_EXTRA STREQUAL "0")
# 有 EXTRA 后缀:显示 MAJOR.MINOR.PATCH-EXTRA不显示 TWEAK
set(PROJECT_VERSION_STR "${PROJECT_VERSION_WITHOUT_TWEAK}-${PROJECT_VERSION_EXTRA}")
set(SDK_VERSION_STRING "\"${PROJECT_VERSION_WITHOUT_TWEAK}-${PROJECT_VERSION_EXTRA}\"")
elseif(PROJECT_VERSION_TWEAK AND NOT PROJECT_VERSION_TWEAK EQUAL 0)
# 有 TWEAK显示 MAJOR.MINOR.PATCH.TWEAK
set(PROJECT_VERSION_STR "${PROJECT_VERSION}")
set(SDK_VERSION_STRING "\"${PROJECT_VERSION}\"")
else()
# 正式版本:显示 MAJOR.MINOR.PATCH
set(PROJECT_VERSION_STR "${PROJECT_VERSION_WITHOUT_TWEAK}")
set(SDK_VERSION_STRING "\"${PROJECT_VERSION_WITHOUT_TWEAK}\"")
endif()
# 计算数值版本(用于版本比较)
# SDK_VERSION_NUMBER: 24位编码 0xMMNNPP (MAJOR.MINOR.PATCH)
math(EXPR SDK_VERSION_NUMBER_INT "(${PROJECT_VERSION_MAJOR} << 16) + (${PROJECT_VERSION_MINOR} << 8) + (${PROJECT_VERSION_PATCH})")
to_hex(${SDK_VERSION_NUMBER_INT} SDK_VERSION_NUMBER)
# SDKVERSION: 32位编码 0xMMNNPPTT (MAJOR.MINOR.PATCH.TWEAK)
math(EXPR SDKVERSION_INT "(${PROJECT_VERSION_MAJOR} << 24) + (${PROJECT_VERSION_MINOR} << 16) + (${PROJECT_VERSION_PATCH} << 8) + (${PROJECT_VERSION_TWEAK})")
to_hex(${SDKVERSION_INT} SDKVERSION)
# SDK_VERSION_CODE: 与 SDK_VERSION_NUMBER_INT 相同(用于兼容)
set(SDK_VERSION_CODE ${SDK_VERSION_NUMBER_INT})
# 打印版本信息(可以通过 NO_PRINT_VERSION 禁用)
if(NOT NO_PRINT_VERSION)
message(STATUS "arcs_sdk: ${PROJECT_VERSION_STR} (${ARCS_SDK_BASE})")
endif()