日志与构建产物
5 个工具处理一次构建产生的所有东西 —— 日志行、输出文件、固件清单、 结构化错误信息和尺寸报告。
| 工具 | 做什么 |
|---|---|
logs.tail | 拿一次构建最近的 N 行日志。 |
list_artifacts(别名 artifacts.list) | 列出一次构建产生的文件,按类型分组。 |
artifacts.manifest | 读一次完成构建的官方 manifest.json。 |
parse_build_errors | 把原始编译错误转成可读的形式。 |
parse_size_report | 把 idf.py size 输出转成 flash/RAM 细分。 |
logs.tail
返回某次构建日志最近的 N 行。
输入:
{
"task_id": "0abf...e2",
"lines": 200
}
| 字段 | 必需 | 说明 |
|---|---|---|
task_id | 是 | build 返回的 id。 |
lines | 否 | 返回多少尾部行。默认 100。 |
since_seq | 否 | 只返回这个序列号之后的行(从上次调用得到)。 |
返回:
{
"task_id": "0abf...e2",
"lines": [
{ "seq": 4198, "ts": 1712340060, "stream": "stdout", "text": "[1234/1500] CC main.o" },
{ "seq": 4199, "ts": 1712340061, "stream": "stderr", "text": "warning: ..." }
],
"next_seq": 4200,
"more": false
}
more: true 表示构建还在产生日志行,你应该再问一次。
提示: 对长时间构建,用 build://log/{task_id} 资源 —— 它在新行
到达时推送,而不是你反复问。
list_artifacts / artifacts.list
列出一次构建产生的文件,按类型分组。
输入:
{
"task_id": "0abf...e2",
"target": "esp32s3"
}
可以传 task_id(首选 —— 看实际跑的那次构建)或者 target(看
项目当前的 build/ 文件夹)。
返回:
{
"build_dir": "/work/build",
"artifacts": {
"firmware": [
{ "path": "build/my-app.bin", "size": 1048576, "sha256": "..." }
],
"elf": [
{ "path": "build/my-app.elf", "size": 4823104 }
],
"bootloader": [
{ "path": "build/bootloader/bootloader.bin", "size": 24576 }
],
"partitions": [
{ "path": "build/partition_table/partition-table.bin", "size": 3072 }
],
"maps": [
{ "path": "build/my-app.map", "size": 8421376 }
],
"other": []
}
}
分组器了解 ESP-IDF 的标准输出布局(固件、bootloader、分区表、ELF、
map),按此分组。它不认识的东西落到 other。
CLI: espctl artifacts
本地扫描 build/<target>/,挑出符合分类器的文件(.bin、.elf、
.map、bootloader、分区表、sdkconfig 等),输出一份
ArtifactManifest。不联系构建服务器。
espctl artifacts [--target <chip>]
输入
| 标志 | 默认 | 说明 |
|---|---|---|
--target | .espctl.toml 里的 default_target | 芯片 —— 没传就用项目默认值。 |
输出
Human 模式列出每个被分类的文件:
Artifacts in /path/to/build/esp32s3:
Bin bootloader/bootloader.bin (24576 bytes)
Bin esp32s3.bin (1048576 bytes)
Elf esp32s3.elf (4823104 bytes)
Map esp32s3.map (8421376 bytes)
JSON(--json):完整的 ArtifactManifest,artifacts[] 中每一项
有 artifact_type、path、size_bytes。
失败模式
build/<target>/不存在 → 退出 1。- target 不合法 → 退出 2。
示例
# 使用 .espctl.toml 里的 default_target
espctl artifacts
# 显式指定 target
espctl artifacts --target esp32s3
# JSON 输出,方便脚本消费
espctl --json artifacts --target esp32s3
相关
list_artifacts/artifacts.list—— MCP 等价工具,可以用task_id限定范围。artifacts.manifest—— 构建服务器写出的 官方 manifest(形状不同)。
artifacts.manifest
读一次已完成构建的官方 manifest.json。清单是构建产生了什么以及
怎么烧录的权威记录。
输入:
{ "task_id": "0abf...e2" }
返回: manifest.json 的内容。具体形状和配方有关,但总是包含:
{
"task_id": "0abf...e2",
"target": "esp32s3",
"idf_version": "v5.3.1",
"profile": "release",
"git_commit": "abc123",
"built_at": 1712340060,
"artifacts": [
{ "name": "firmware", "path": "build/my-app.bin", "size": 1048576, "sha256": "..." },
{ "name": "bootloader", "path": "build/bootloader/bootloader.bin", "offset": "0x0" },
{ "name": "partition-table", "path": "build/partition_table/partition-table.bin", "offset": "0x8000" },
{ "name": "app", "path": "build/my-app.bin", "offset": "0x10000" }
],
"flash_size": "4MB",
"flash_freq": "80m",
"flash_mode": "dio"
}
当你的助手需要知道“哪个文件烧到哪个 flash 地址“时,这是要调的工具。
安全提示: 你编译好的固件可能包含嵌入的敏感信息(Wi-Fi 密码、 API key)。把
.bin文件当作敏感文件,不要公开分享。
parse_build_errors
接收原始的编译/链接错误日志(或一个 task_id),返回结构化、去重的
错误信息。
输入:
{ "task_id": "0abf...e2" }
…或者:
{ "log_text": "main.c:42:5: error: ..." }
返回:
{
"errors": [
{
"file": "main/app_main.c",
"line": 42,
"column": 5,
"severity": "error",
"message": "implicit declaration of function 'foo'",
"context": [
" 40 | void app_main(void) {",
" 41 | printf(\"hello\\n\");",
" 42 | foo();",
" ^"
]
}
],
"warnings": [...],
"summary": "1 error, 0 warnings"
}
了解 GCC、Clang、CMake 和 ESP-IDF 自己的错误格式。当你的助手想给你 看“这是要改的那一行“而不是堆 500 行日志时很有用。
parse_size_report
解析 idf.py size 的输出,返回按 section 分的 flash/RAM 用量细分。
输入:
{ "task_id": "0abf...e2" }
返回:
{
"target": "esp32s3",
"total_flash": { "used": 1048576, "free": 3145728, "total": 4194304 },
"total_ram": { "used": 131072, "free": 393216, "total": 524288 },
"sections": [
{ "name": ".text", "size": 524288, "memory": "flash" },
{ "name": ".rodata", "size": 262144, "memory": "flash" },
{ "name": ".data", "size": 16384, "memory": "ram" },
{ "name": ".bss", "size": 114688, "memory": "ram" }
]
}
和 parse_build_errors 配合,可以一次性给出完整的构建后摘要。
CLI: espctl clean
按 target 删除构建产物。带 --full 时,把整个 build/、sdkconfig、
managed_components/ 一起删。仅本地操作,不会联系构建服务器。
espctl clean [--full] [target]
两种模式
- 增量清理 ——
espctl clean <target>按espctl_core::clean_plan给出的清单删build/<target>/...下的 文件。 - 完全清理 ——
espctl clean --full把整个build/、sdkconfig、managed_components/都删掉(fullclean_plan)。带--full时 位置参数target会被忽略。
标志矩阵
| 参数 | 默认 | 说明 |
|---|---|---|
target(位置参数) | — | 不带 --full 时必填。芯片名。 |
--full | false | 切到完全清理模式。 |
输出
Human 模式:
Removed:
/path/to/build/esp32s3/CMakeCache.txt
/path/to/build/esp32s3/CMakeFiles
...
…或在没有任何东西匹配时输出 Nothing to clean.。
JSON(--json):{ "removed": ["/path/...", ...] }。
失败模式
| 情况 | 退出码 | 消息 |
|---|---|---|
既没传 target,也没传 --full | 2 | target required for clean (use --full for full clean) |
| target 不合法 | 2 | invalid target: <name> |
预演
破坏性清理前(尤其在 CI 里),先用 MCP 的
get_clean_plan 工具看一眼会删什么 ——
它只告诉你结果,不会真删。
示例
# 增量 —— 只删 build/esp32s3/...
espctl clean esp32s3
# 完全清理 —— build/、sdkconfig、managed_components/
espctl clean --full
# JSON 输出,方便脚本消费
espctl --json clean esp32s3