最开始的尝试可以参考之前的文章: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