第四节:设备树编译器——dtc工具的使用、编译与反编译、常用选项
设备树写好了,怎么变成机器能懂的东西?
答案就是——dtc,设备树编译器。全称 Device Tree Compiler。
说实话,这工具看着不起眼,但它是整个设备树生态的基石。我刚开始接触设备树时,觉得不就是个编译器嘛,跟gcc差不多。后来踩了几个坑才发现,dtc的细节远比想象中多。
4.1 dtc是什么?
dtc负责把人类可读的.dts文件,转成二进制.dtb文件。反过来也能把.dtb还原成.dts,这叫反编译。
你想想看,uboot、内核、TF-A这些组件,最终读的都是.dtb。所以dtc就是那个“翻译官”。
核心流程:
.dts(文本) → dtc编译 → .dtb(二进制) → 内核解析
我个人习惯在开发阶段频繁使用dtc的-W和-E选项,能提前发现很多问题。后面会细说。
4.2 编译:从.dts到.dtb
最基本的用法,一行命令搞定:
dtc -I dts -O dtb -o my_board.dtb my_board.dts
参数解释:
-I dts:输入格式是dts-O dtb:输出格式是dtb-o my_board.dtb:指定输出文件名
实际项目中,我更喜欢加几个选项:
dtc -I dts -O dtb -o my_board.dtb -W no-unit_address_vs_reg -@ my_board.dts
-@这个选项很重要。它允许生成符号节点,方便后续overlay。我在做模块化设计时,几乎必加这个选项。
4.3 反编译:从.dtb回到.dts
有时候拿到一个二进制的.dtb,想看看里面写了什么。反编译就派上用场了。
dtc -I dtb -O dts -o my_board_reverse.dts my_board.dtb
嗯,这里要注意:反编译出来的.dts,跟原始.dts不完全一样。注释会丢失,节点顺序也可能变化。但关键信息都在。
我曾经在调试一个第三方提供的固件时,对方只给了.dtb。我反编译后才发现,某个GPIO的配置跟原理图对不上。这种问题,不反编译根本发现不了。
4.4 常用选项详解
dtc的选项不少,但常用的就那几个。我整理了一张表:
| 选项 | 作用 | 我的建议 |
|---|---|---|
-I |
指定输入格式(dts/dtb/fs) | 默认是dts,但显式指定更安全 |
-O |
指定输出格式(dts/dtb) | 编译用dtb,反编译用dts |
-o |
输出文件名 | 建议跟板子名一致,方便管理 |
-W |
启用特定警告 | 开发阶段建议全开 |
-E |
启用特定错误检查 | 我习惯加 -E no_property_type |
-@ |
生成符号节点 | 做overlay时必须加 |
-H |
指定phandle格式 | 默认epapr,一般不用改 |
-V |
指定dtb版本 | 默认17,兼容性最好 |
小技巧:调试阶段可以用 dtc -I dts -O dts -o output.dts input.dts 来格式化dts文件。dtc会自动帮你整理缩进和对齐,比手动排版快多了。
4.5 编译过程中的常见错误
我见过太多人在dtc上栽跟头了。总结几个高频问题:
- 语法错误:少了个分号,或者花括号不匹配。dtc的错误信息还算友好,会告诉你哪一行出问题。
- 引用错误:用&引用节点时,节点不存在。检查一下标签名是否拼写正确。
- 类型不匹配:比如reg属性应该用
,结果写成了字符串。dtc会报warning,但不会阻止编译。
避坑指南:我曾经在项目中遇到一个诡异的问题——dtc编译通过,但内核启动时设备树解析失败。查了两天才发现,是某个节点的#address-cells写错了。dtc不会检查这种逻辑错误,它只负责语法层面。所以编译通过不代表设备树没问题。
4.6 实战:一个完整的编译流程
假设我们有一个项目,包含主设备树和两个overlay:
# 编译主设备树
dtc -I dts -O dtb -@ -o main.dtb main.dts
# 编译overlay
dtc -I dts -O dtb -@ -o overlay1.dtbo overlay1.dts
dtc -I dts -O dtb -@ -o overlay2.dtbo overlay2.dts
# 检查生成的dtb
dtc -I dtb -O dts -o main_check.dts main.dtb
注意overlay文件的扩展名是.dtbo,这是惯例。虽然dtc不强制,但uboot和内核都认这个命名规则。
4.7 知识体系图
下面这张图,是我对dtc工具知识点的梳理:
4.8 一些实用技巧
最后分享几个我积累的小经验:
- 批量编译:写个Makefile,用wildcard收集所有.dts文件,一行命令编译整个项目。
- 版本控制:我习惯把.dts和生成的.dtb都提交到git。虽然.dtb是二进制文件,但方便其他人直接使用。
- 调试技巧:用
dtc -V 16可以生成旧版本的dtb,有时候兼容老内核会用到。
个人习惯:我每次修改设备树后,都会先做一次反编译,对比修改前后的差异。这能帮我快速发现手误。比如少写了一个逗号,或者把0x写成了0X,反编译结果一眼就能看出来。
dtc工具本身不复杂,但用好它需要积累经验。多编译、多反编译、多对比,慢慢就熟练了。
可可精品资料库