先谢一波 EEPW 和乐鑫提供的 ESP32-S31-Korvo-1 开发板。板子还在路上,索性先把开发环境搭起来,查了下,S31 是今年才出的新芯片,还在 preview 阶段,官方稳定版 IDF 根本没纳入它,只能用 master 分支
先看一下我的配置
| 系统 | ubuntu26 |
| 芯片 | ESP32-S31(preview,RISC-V) |
| 板子 | ESP32-S31-Korvo-1 |
| ESP-IDF | master(对应 v6.2.0) |
| 编译器 | riscv32-esp-elf GCC 16.1.0 |
| clangd | esp-clangd 21.1.3 |
master 是滚动分支,上面这些版本号会随时间变,你拉下来的具体号可能不一样,流程一致。
一、装 IDF master
EIM(乐鑫官方安装管理器)默认只装稳定版,master 得手动点名。两步走:先装 EIM,再让它装 master 版 IDF。
装 EIM
echo "deb [trusted=yes] https://dl.espressif.com/dl/eim/apt/ stable main" \ | sudo tee /etc/apt/sources.list.d/espressif.list sudo apt update sudo apt install eim
装 master
eim install -i master
-i 后面跟版本标识符,master 就是装开发主分支而非默认稳定版。
当然,网络环境还是需要的,这个大家应该都会
装到最后看到这些就是成了:
You have successfully installed ESP-IDF INFO - Successfully installed IDF INFO - Now you can start using IDF tools
二、激活环境
装完后,每次得先在终端里激活脚本,把环境变量导进当前会话。
source "/home/l/.espressif/tools/activate_idf_master.sh"
验证:
$ idf.py --version fatal: 没有发现名称,无法描述任何东西。 WARNING: Git version unavailable, reading from source ESP-IDF v6.2.0
出 v6.2.0 就对了。上面那两行是idf.py 想用 git describe 从 tag 读精确版本号,但 master 当前 commit 没打 tag,描述不出来,于是退回读源码里的版本文件。纯提示。
三、先拿一个能编译的基线
环境通了,先编一次空工程拿基线,哪怕所有 .c 都是空的。这一步两分钟,但它给你一个确定的参照:之后每加一个依赖编一次,一炸就知道是刚才那步引入的,不用回头怀疑环境本身。preview 阶段变量太多,你需要的就是不断缩小怀疑范围。
S31 是 preview 芯片,设目标要加 --preview:
idf.py --preview set-target esp32s31
空工程首编:
Project build complete. sample_project.bin binary size 0x301f0 bytes
我这桌宠语音助手规划了六个组件,基线拿到后逐个加:
components/ app_core/ 状态机 + 事件总线 audio_wake/ AFE + 唤醒词 + VAD face_id/ 人脸唤醒 net_client/ WiFi + 云端 audio_play/ TTS 播放 pet_ui/ LVGL
坑一:esp-sr 拖进 esp-dl,撞上 GCC 16 编不过
语音要用 esp-sr:
idf.py add-dependency "espressif/esp-sr"
然后就炸了,而且报错的不是我加的那个:
[1134/2496] Building CXX object .../espressif__esp-dl/.../dl_model_base.cpp.obj ninja: build stopped: subcommand failed.
esp-sr 会传递依赖 esp-dl(深度学习推理库,语音和视觉模型都靠它跑)。IDF 里加一个组件常带进来一串,报错的往往不是你直接加的那个。而 ninja 并行输出滚太快,真错误被后面的任务刷掉了,得这么捞:
idf.py build 2>&1 | grep -A25 "FAILED:"
根因出来了:
dl_image_bmp.cpp:10:16: error: anonymous non-C-compatible type given name for linkage purposes by 'typedef' declaration [-Werror=non-c-typedef-for-linkage]
esp-dl 里这么写的:
typedef struct {
uint16_t file_type{0x4D42}; // 带默认成员初始化
uint32_t file_size;
} bmp_file_header_t;匿名 struct + 成员默认初始化 + typedef 起名,这组合在 C++ 标准里影响 linkage。GCC 从某版本起把 -Wnon-c-typedef-for-linkage 提成默认警告,而 IDF 默认带 -Wall -Werror,警告直接变错误。应该是 esp-dl 的代码在老 GCC 上写的,现在撞上 GCC 16,跟代码无关。
修法:定点降级。 只对这一个组件、只降这一条——项目根 CMakeLists.txt 的 project() 之后:
idf_build_get_property(_build_components BUILD_COMPONENTS)
if("espressif__esp-dl" IN_LIST _build_components)
idf_component_get_property(_esp_dl_lib
espressif__esp-dl COMPONENT_LIB)
target_compile_options(${_esp_dl_lib} PRIVATE
-Wno-error=non-c-typedef-for-linkage)
endif()再编就过:
Project build complete. sample_project.bin binary size 0x2b710 bytes
坑二:编得过,但 IDE 满屏红波浪线
idf.py build 一切正常,但在编辑器里写代码时跳转失灵、补全没有、到处红线
第一层:路径就是错的
打开 .clangd
# .clangd 里写的是 esp-14.2.0_20241119 # 实际装的是 esp-16.1.0_20260609
再看 .vscode/c_cpp_properties.json,compilerPath 指向 xtensa,而 S31 是 RISC-V,架构都不对。这俩八成是从别的工程抄配置留下的——换芯片时大家只顾着改 sdkconfig,很少有人回头改它们,因为它们不参与编译,坏了没有任何提示。
第二层:改对路径后还有 24 个错误
,用 --check 让 clangd 把实际拿到的参数、诊断全打出来:
clangd --check=<file> \ --compile-commands-dir=build \ --query-driver='**'
结果 24 errors,核心是:
unknown argument: '-fno-shrink-wrap' unknown argument: '-fstrict-volatile-bitfields' 'stddef.h' file not found use of undeclared identifier 'NULL' (× 20)
一堆 NULL 未定义是表象,往上追是 stddef.h 找不到。一个交叉编译工具链,找不到 stddef.h?
看 esp-clangd 安装目录,整个包只有一个 78 MB 的二进制:
esp-clangd/esp-21.1.3_20260408/esp-clangd/ └── bin/ └── clangd 78 MB ← 就这一个 # 没有 lib/clang/21/include/
clang 跟 gcc 一样,有一批 builtin 头文件(stddef.h、stdarg.h 等)是编译器自带的,不属于 libc,默认去 <安装目录>/lib/clang/<版本>/include/ 找。而这个包只打了 language server 二进制,头文件一个没带。
借 GCC 的用?GCC 的 builtin 头在这,注意有俩目录:
.../16.1.0/include/ ← stddef.h 真在这 .../16.1.0/include-fixed/ ← 里面只有一个 README,空的
再翻 IDF 生成的 compile_commands.json,-isystem 传的偏偏是空的那个:
-isystem .../16.1.0/include-fixed ← 传了空的 # 真正有头文件的 include 没传
两个坑叠加:esp-clangd 缺自己的 builtin 头,而 IDF 给的 -isystem 又漏了 GCC 那份。 GCC 自己编译时会隐式找到 include,所以编译没事;但 clangd 只认命令行里明确给的路径,链子就断这儿。单独任何一个都不出事。
修法
.clangd 里显式补路径 + 清掉不认识的参数:
CompileFlags: Remove: [-f*, -m*] Add: - -isystem<路径>/riscv32-esp-elf/esp-16.1.0_20260609/riscv32-esp-elf/lib/gcc/riscv32-esp-elf/16.1.0/include Compiler: <路径>/.../bin/riscv32-esp-elf-gcc
Remove: [-f*, -m*] 顺手解决那批 unknown argument——GCC 16 的 -f/-m 开关 clang 21 不认。A/B 验证:
| 不加 -isystem | stddef.h file not found,1 error |
| 加上 | All checks completed, 0 errors |
最终结果
Project build complete. sample_project.bin binary size 0x2b710 bytes Smallest app partition is 0x100000 bytes. 0xd48f0 bytes (83%) free. clangd --check → All checks completed, 0 errors
我要赚赏金
