ESP32编译FreeType失败:fterror.h宏无法识别问题求助
问题背景
用默认Makefile在Windows平台编译FreeType可正常运行,但自行编写CMakeLists.txt在ESP32环境编译时,大量FreeType的.c文件出现编译错误:编译器预处理器无法识别fterror.h中定义的宏。
已确认相关.c文件正确引入fterror.h,且代码在Windows平台编译正常,但仍提示宏缺失,导致FT_ERR_PREFIX无法替换为FT_Err_,引发如下类型的错误:
[2/200] Building C object esp-idf/freetype2/CMakeFiles/__idf_freetype2.dir/base/ftbdf.c.obj FAILED: esp-idf/freetype2/CMakeFiles/__idf_freetype2.dir/base/ftbdf.c.obj ccache C:\Users\CKan\.espressif\tools\xtensa-esp32s3-elf\esp-12.2.0_20230208\xtensa-esp32s3-elf\bin\xtensa-esp32s3-elf-gcc.exe -DESP_PLATFORM -DIDF_VER=\"v5.1-dirty\" -DSOC_MMU_PAGE_SIZE=CONFIG_MMU_PAGE_SIZE -D_GNU_SOURCE -D_POSIX_READER_WRITER_LOCKS -IC:/Projects/tgesp32/build/config -IC:/Projects/tgesp32/components/freetype2/include -IC:/Projects/tgesp32/components/freetype2/include/freetype -IC:/Projects/tgesp32/components/freetype2/include/freetype/config -IC:/Projects/tgesp32/components/freetype2/include/freetype/internal -IC:/Projects/tgesp32/components/freetype2/include/freetype/internal/services -IC:/Projects/tgesp32/components/freetype2/include/dlg -IC:/Users/CKan/esp/esp-idf/components/newlib/platform_include -IC:/Users/CKan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/include -IC:/Users/CKan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/include -IC:/Users/CKan/esp/esp-idf/components/freertos/esp_additions/include/freertos -IC:/Users/CKan/esp/esp-idf/components/freertos/esp_additions/include -IC:/Users/CKan/esp/esp-idf/components/freertos/esp_additions/arch/xtensa/include -IC:/Users/CKan/esp/esp-idf/components/esp_hw_support/include -IC:/Users/CKan/esp/esp-idf/components/esp_hw_support/include/soc -IC:/Users/CKan/esp/esp-idf/components/esp_hw_support/include/soc/esp32s3 -IC:/Users/CKan/esp/esp-idf/components/esp_hw_support/port/esp32s3/. -IC:/Users/CKan/esp/esp-idf/components/esp_hw_support/port/esp32s3/private_include -IC:/Users/CKan/esp/esp-idf/components/heap/include -IC:/Users/CKan/esp/esp-idf/components/log/include -IC:/Users/CKan/esp/esp-idf/components/soc/include -IC:/Users/CKan/esp/esp-idf/components/soc/esp32s3 -IC:/Users/CKan/esp/esp-idf/components/soc/esp32s3/include -IC:/Users/CKan/esp/esp-idf/components/hal/esp32s3/include -IC:/Users/CKan/esp/esp-idf/components/hal/include -IC:/Users/CKan/esp/esp-idf/components/hal/platform_port/include -IC:/Users/CKan/esp/esp-idf/components/esp_rom/include -IC:/Users/CKan/esp/esp-idf/components/esp_rom/include/esp32s3 -IC:/Users/CKan/esp/esp-idf/components/esp_rom/esp32s3 -IC:/Users/CKan/esp/esp-idf/components/esp_common/include -IC:/Users/CKan/esp/esp-idf/components/esp_system/include -IC:/Users/CKan/esp/esp-idf/components/esp_system/port/soc -IC:/Users/CKan/esp/esp-idf/components/esp_system/port/include/private -IC:/Users/CKan/esp/esp-idf/components/xtensa/include -IC:/Users/CKan/esp/esp-idf/components/xtensa/esp32s3/include -IC:/Users/CKan/esp/esp-idf/components/lwip/include -IC:/Users/CKan/esp/esp-idf/components/lwip/include/apps -IC:/Users/CKan/esp/esp-idf/components/lwip/include/apps/sntp -IC:/Users/CKan/esp/esp-idf/components/lwip/lwip/src/include -IC:/Users/CKan/esp/esp-idf/components/lwip/port/include -IC:/Users/CKan/esp/esp-idf/components/lwip/port/freertos/include -IC:/Users/CKan./esp/esp-idf/components/lwip/port/esp32xx/include -IC:/Users/CKan./esp/esp-idf/components/lwip/port/esp32xx/include/arch -mlongcalls -fdiagnostics-color=always -ffunction-sections -fdata-sections -Wall -Werror=all -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=unused-but-set-variable -Wno-error=deprecated-declarations -Wextra -Wno-unused-parameter -Wno-sign-compare -Wno-enum-conversion -gdwarf-4 -ggdb -Og -fmacro-prefix-map=C:/Projects/tgesp32=. -fmacro-prefix-map=C:/Users/CKan./esp/esp-idf=/IDF -fstrict-volatile-bitfields -fno-jump-tables -fno-tree-switch-conversion -DconfigENABLE_FREERTOS_DEBUG_OCDAWARE=1 -std=gnu17 -Wno-old-style-declaration -MD -MT esp-idf/freetype2/CMakeFiles/__idf_freetype2.dir/base/ftbdf.c.obj -MF esp-idf\freetype2\CMakeFiles\__idf_freetype2.dir\base\ftbdf.c.obj.d -o esp-idf/freetype2/CMakeFiles/__idf_freetype2.dir/base/ftbdf.c.obj -c C:/Projects/tgesp32/components/freetype2/base/ftbdf.c In file included from C:/Projects/tgesp32/components/freetype2/include/freetype/freetype.h:25, from C:/Projects/tgesp32/components/freetype2/include/freetype/internal/ftdebug.h:30, from C:/Projects/tgesp32/components/freetype2/base/ftbdf.c:19: C:/Projects/tgesp32/components/freetype2/base/ftbdf.c: In function 'FT_Get_BDF_Charset_ID': C:/Projects/tgesp32/components/freetype2/include/freetype/internal/ftdebug.h:329:36: error: 'FT_ERR_PREFIXInvalid_Face_Handle' undeclared (first use in this function); did you mean 'FT_Err_Invalid_Face_Handle'? 329 | #define FT_THROW( e ) FT_ERR_CAT( FT_ERR_PREFIX, e ) | ^~~~~~~~~~~~~ C:/Projects/tgesp32/components/freetype2/include/freetype/fttypes.h:596:30: note: in definition of macro 'FT_ERR_XCAT' 596 | #define FT_ERR_XCAT( x, y ) x ## y | ^ C:/Projects/tgesp32/components/freetype2/include/freetype/internal/ftdebug.h:329:24: note: in expansion of macro 'FT_ERR_CAT' 329 | #define FT_THROW( e ) FT_ERR_CAT( FT_ERR_PREFIX, e ) | ^~~~~~~~~~ C:/Projects/tgesp32/components/freetype2/base/ftbdf.c:44:14: note: in expansion of macro 'FT_THROW' 44 | return FT_THROW( Invalid_Face_Handle ); | ^~~~~~~~
解决方法
确认config目录被加入包含路径
FreeType的fterror.h位于include/freetype/config下,检查CMakeLists.txt中是否正确添加了该路径:target_include_directories(freetype2 PRIVATE ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/include/freetype ${PROJECT_SOURCE_DIR}/include/freetype/config )确保编译时能找到这个头文件。
添加FT_CONFIG_OPTION_ERROR_STRINGS编译宏
在CMakeLists.txt中为FreeType目标强制添加该宏,它会触发fterror.h中FT_ERR_PREFIX等宏的定义:target_compile_definitions(freetype2 PRIVATE FT_CONFIG_OPTION_ERROR_STRINGS)Windows平台的默认Makefile默认开启了这个选项,而ESP32环境下需要手动指定。
强制提前包含fterror.h
如果头文件包含顺序导致FT_ERR_PREFIX在FT_THROW展开时未定义,可通过编译选项强制所有编译单元先包含fterror.h:target_compile_options(freetype2 PRIVATE -include "${PROJECT_SOURCE_DIR}/include/freetype/config/fterror.h" )使用ESP-IDF官方适配的FreeType配置
参考ESP-IDF自带的FreeType组件的CMake配置,避免自行编写时遗漏关键编译选项或宏定义。如果是手动引入FreeType源码,可复制官方组件的ftconfig.h和fterror.h替换自己的版本。
内容的提问来源于stack exchange,提问作者Chris. Kan

