ESP32-IDF编译时出现undefined reference to function()

在编译ESP32项目时出现了奇怪的错误,在Link CXX executable test.elf时失败,并报错undefined reference to 'lv_demo_music'。是编译报错。这里记录解决方法。

image-20230514195146129

原因分析

上面的报错意思很简单,其实就是虽然声明了这个函数(有头文件),没有报错undeclare,但是由于**没有编译这个函数(没编译.c文件)**,导致编译器在链接的时候找不到。

这其实是CMake文件没有写好编译范围,导致没有将目标文件编译的原因

解决方法

解决方法也很简单,参考官方文档的构建系统。该文档中说明,可以使用SRCS SRC_DIRS指定要编译的文件,文件夹。

添加编译单个文件:

1
2
idf_component_register(SRCS library/a.c library/b.c platform/platform.c
...)

添加编译包含多个文件的文件夹:

1
2
idf_component_register(SRC_DIRS library platform
...)

后台会使用通配符在指定的目录中查找源文件。但是请注意,在使用这种方法的时候,如果组件中添加了一个新的源文件,CMake 并不知道重新运行配置,最终该文件也没有被加入构建中。这在使用命令行单步编译时需要注意。

问题解决

我是在移植lvgl时出现的BUG,由于ESP公司是LVGl的合作伙伴,lvgl对ESP-IDF做了专门的适配,其直接克隆的仓库就可以做为一个组件使用。在项目CMakeList.txt中,可以看到这一行:

1
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/esp.cmake)c

引用了env_support目录下的cmake文件,打开该文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c)# ${LVGL_ROOT_DIR}/demos/*.c)

idf_build_get_property(LV_MICROPYTHON LV_MICROPYTHON)

if(LV_MICROPYTHON)
idf_component_register(
SRCS
${SOURCES}
INCLUDE_DIRS
${LVGL_ROOT_DIR}
${LVGL_ROOT_DIR}/src
${LVGL_ROOT_DIR}/../
REQUIRES
main)

target_compile_definitions(${COMPONENT_LIB}
INTERFACE "-DLV_CONF_INCLUDE_SIMPLE")

if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM)
target_compile_definitions(${COMPONENT_LIB}
INTERFACE "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
endif()
else()
idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ${LVGL_ROOT_DIR}
${LVGL_ROOT_DIR}/src ${LVGL_ROOT_DIR}/../)

target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_INCLUDE_SIMPLE")

if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM)
target_compile_definitions(${COMPONENT_LIB}
PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
endif()
endif()

可以看到,两次idf_component_register()使用的源文件为${SOURCES},而该变量定义在:

1
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c)

可以看到,只编译了src文件夹,我们使用的函数在demos文件夹下,因此可以直接修改为

1
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c ${LVGL_ROOT_DIR}/demos/*.c)

重新编译,问题解决。