1. Tina Linux 系统概述:架构、目录与构建基础

各位好,欢迎来到《全志Tina Linux系统构建性能调优实战》的第一章。

做嵌入式Linux开发这么多年,我接触过不少芯片厂商的SDK。说实话,全志的Tina系统,在构建效率和灵活性上,算是很有特点的一个。你想想看,一个系统要同时支持从低功耗IoT设备到高性能多媒体盒子,底层构建系统如果设计得不好,后面调优根本无从下手。

这一章,我们先打好地基。我会从Tina的系统架构、源码目录结构,再到构建系统的基础概念,一步步带你理清楚。嗯,这些都是后续所有调优动作的“地图”,千万别跳过。

1.1 Tina 系统架构概览

Tina Linux 本质上是一个基于 OpenWrt 深度定制的嵌入式 Linux 发行版。全志在 OpenWrt 的基础上,加入了大量自研的硬件驱动、多媒体框架和电源管理组件。

它的整体架构,我习惯从下往上分成四层:

Tina Linux 系统四层架构 应用层 (Application Layer) GUI框架 (QT/LVGL) · 多媒体播放器 · 物联网协议栈 · 用户业务APP 系统服务层 (System Service Layer) init进程 · 网络管理 (netifd) · 音频服务 (tinyalsa) · 电源管理 (axp) 内核层 (Kernel Layer) Linux内核 (4.9/5.4/5.10) · 全志硬件驱动 (DMA/Display/CSI) · 文件系统 硬件层 (Hardware Layer) 全志SoC (V系列/T系列/R系列) · DDR · NAND/eMMC · 外设接口 用户态 内核态

这张图我建议你多看两眼。在实际调优中,你遇到的瓶颈往往就卡在这四层的某一层里。比如我之前调一个视频播放卡顿的问题,折腾了半天应用层代码,最后发现是内核层的显示驱动DMA配置没开——这就是典型的“上层表现、下层根源”。

1.2 源码目录结构:你的“作战地图”

拿到Tina SDK后,第一件事是什么?不是急着编译,而是先搞清楚东西都放在哪。我见过太多新手,直接在根目录下乱翻,最后连配置文件在哪都找不到。

Tina SDK的顶层目录,结构非常清晰:

tina/
├── build/               # 构建系统核心脚本 (Makefile, 编译规则)
├── config/              # 全局配置文件 (芯片选型, 内核配置)
├── device/              # 芯片级/板级配置 (dts, 分区表, 环境变量)
├── kernel/              # Linux内核源码 (linux-4.9, linux-5.4等)
├── package/             # 软件包源码 (应用, 库, 工具)
├── prebuilt/            # 预编译工具链和二进制文件
├── target/              # 目标板配置 (rootfs, 固件打包脚本)
├── toolchain/           # 交叉编译工具链源码
├── out/                 # 编译输出目录 (镜像, 包, 日志)
└── scripts/             # 辅助脚本 (打包, 烧录, 调试)

这里我重点说几个目录,因为后面调优会频繁打交道:

目录 核心作用 调优关注点
build/ 构建系统的“发动机”,包含顶层Makefile和编译规则 并行编译数、编译缓存、依赖关系
device/ 芯片和板级的硬件描述,如DTS、分区表 DTS配置错误导致外设初始化失败
package/ 所有软件包的源码和Makefile 包依赖冗余、编译选项优化
target/ 定义最终固件的组成和打包方式 rootfs大小、文件系统类型选择
out/ 编译产物,包括镜像、IPK包、编译日志 日志分析、增量编译效率
我的习惯: 每次拿到一个新板子,我会先在 device/config/chips/ 下找到对应的芯片目录,把 sys_config.fex 和 board.dts 通读一遍。这两个文件决定了硬件能不能正常跑起来,很多“玄学”问题其实都是这里配错了。

1.3 构建系统基础概念

Tina的构建系统,底层是OpenWrt的Buildroot风格,但全志做了大量魔改。说白了,它就是一个“自动化工厂”:你告诉它要什么芯片、什么功能,它自动下载源码、配置、编译、打包,最后生成一个可以烧录的固件镜像。

核心概念,我总结为三个:

1.3.1 软件包 (Package)

这是构建系统的最小单元。每个软件包在 package/ 目录下都有一个子目录,里面包含 Makefile 和 patches/。Makefile定义了从哪里下载、如何配置、如何编译、安装到哪个目录。

举个例子,一个典型的包结构:

package/hello/
├── Makefile          # 编译规则
├── src/              # 源码(可选)
│   └── hello.c
└── patches/          # 补丁(可选)
    └── 001-fix.patch

Makefile的核心写法是这样的:

include $(TOPDIR)/rules.mk

PKG_NAME:=hello
PKG_VERSION:=1.0
PKG_RELEASE:=1

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)

include $(INCLUDE_DIR)/package.mk

define Package/hello
  SECTION:=utils
  CATEGORY:=Utilities
  TITLE:=A simple hello world program
  DEPENDS:=+libpthread
endef

define Build/Compile
  $(MAKE) -C $(PKG_BUILD_DIR) \
    CC="$(TARGET_CC)" \
    CFLAGS="$(TARGET_CFLAGS)"
endef

define Package/hello/install
  $(INSTALL_DIR) $(1)/usr/bin
  $(INSTALL_BIN) $(PKG_BUILD_DIR)/hello $(1)/usr/bin/
endef

$(eval $(call BuildPackage,hello))

这里要注意 DEPENDS:=+libpthread 前面的加号。它表示“依赖但不强制安装”。我曾经在裁剪系统时,因为漏掉了一个依赖的加号,导致整个rootfs体积膨胀了30%。

1.3.2 配置系统 (Kconfig / mconfig)

Tina使用了一套基于Kconfig的图形化配置界面。你运行 make menuconfig 或 make kernel_menuconfig 时,就是在操作它。

配置项最终会生成 .config 文件,这个文件决定了:

  • 选择哪个芯片平台 (如 SUNXI_SOC_V853)
  • 启用哪些内核功能 (如 CONFIG_DRM_SUNXI)
  • 编译哪些用户态软件包 (如 PACKAGE_libopenssl)
避坑指南: 我曾经在配置内核时,为了“省事”直接 make kernel_menuconfig 手动勾选了一堆驱动。结果编译出来的内核镜像大了2MB,而且启动时因为驱动冲突导致系统崩溃。后来我学乖了——永远基于默认配置做增量修改,每次只改一个选项,然后编译测试。

1.3.3 编译流程 (Build Flow)

整个构建流程,我习惯用这张图来理解:

Tina 构建系统核心流程 1. 配置 menuconfig 2. 下载 源码/工具链 3. 编译 内核+包 4. 打包 生成固件 各阶段调优切入点 • 配置阶段:裁剪不必要的包和内核模块,减少编译量 • 下载阶段:配置本地镜像源,避免网络瓶颈 • 编译阶段:调整并行数(-j)、使用ccache、优化编译选项 • 打包阶段:选择合适文件系统(squashfs/ubifs),控制镜像大小

这个流程看起来简单,但实际跑起来,每一步都可能成为瓶颈。我记得有一次,团队里新来的同事直接 make -j1 编译,一个完整固件跑了快两个小时。后来我让他改成 make -j$(nproc),时间直接缩短到25分钟。

核心要点: Tina的构建系统,本质上是一个“依赖驱动的任务调度器”。它根据 .config 中的配置,自动解析包之间的依赖关系,然后按拓扑顺序编译。理解这一点,你就知道为什么有时候改了一个包,却要重新编译整个系统——因为依赖链被触发了。

1.4 本章小结

这一章,我们走马观花地看了Tina Linux的全貌。从四层架构,到源码目录,再到构建系统的三个核心概念。这些东西,说实话,光看是记不住的。我建议你:

  • 打开你的Tina SDK,对照目录结构,一个一个目录点进去看看
  • 运行一次 make menuconfig,感受一下配置界面
  • 找一个简单的包(比如 package/hello),读一读它的Makefile