最开始的尝试可以参考之前的文章:https://www.shenqhy.com/porting-rt-the-automatic-initialization-function-of-the-thread-to-the-esp32.html
因为ESP IDF构建系统是将app_main也作为组件,编译成静态库后,再与IDF中的main链接出elf,所以__attribute__((used))不起作用,
链接成静态库的时候,直接被丢掉了。
以下是实现的.h和.c文件
/* einit.h */ #ifndef __EINIT_H__ #define __EINIT_H__ #ifdef __cplusplus #define cpp_declare extern "C" #else #define cpp_declare #endif typedef int(*einit_fn_t)(void); typedef struct einit_desc { const char* name; einit_fn_t func; }einit_desc; #define EINIT_EXP(fn, lv) \ cpp_declare const __attribute__((used)) __attribute__((section(".einit." #lv))) \ einit_desc __einit_##fn = { \ .name = #fn, \ .func = fn, \ } #ifdef __cplusplus extern "C" { #endif extern void einit_run(); #ifdef __cpluscplus } #endif #endif /* __EINIT_H__ */
/* einit.c */ #include "einit.h" static int start() { return 0; } EINIT_EXP(start, 0); static int stop() { return 0; } EINIT_EXP(start, z); void einit_run() { const einit_desc* desc; for (desc = &__einit_start; desc <= &__einit_stop; desc++) { desc->func(); } }
## CMakeLists.txt idf_component_register( SRCS einit.c INCLUDE_DIRS "." LDFRAGMENTS "./einit.lf" )
einit.lf
[sections:einit_sections] entries: .einit+ [scheme:einit_scheme] entries: einit_sections -> flash_rodata [mapping:einit] archive: * entries: * (einit_scheme); einit_sections -> flash_rodata ALIGN(4) KEEP() SORT(name) SURROUND(einit)
最关键的:
如果是IDF4, 在main/CMakeLists.txt中底部添加:
idf_build_set_property(LINK_OPTIONS "-Wl,--whole-archive ${CMAKE_CURRENT_BINARY_DIR}/lib${COMPONENT_NAME}.a -Wl,--no-whole-archive -Wl,--allow-multiple-definition" APPEND)
如果是IDF5, 在main/CMakeLists.txt中idf_component_register的括号内部末尾,添加WHOLE_ARCHIVE
例:
idf_component_register(SRCS "main.c" INCLUDE_DIRS "." REQUIRES nvs_flash WHOLE_ARCHIVE)
最后,在app_main中执行einit_run,便可以在其它文件中,使用EINIT_EXP定义自动初始化func