全志T113 Tina-SDK 配套工具链开发应用(从Makefile到CMake再到Autotools)

全志T113 Tina-SDK 配套工具链开发应用(从Makefile到CMake再到Autotools)

本章内容:掌握Tina-SDK中交叉编译工具链的用法,学会编写Makefile、CMakeLists.txt以及Autotools构建脚本,将你的C程序交叉编译为ARM可执行文件,并通过ADB部署到开发板上运行。这是嵌入式Linux应用开发的起点,学完本章你就能独立完成"编译-部署-运行"的完整闭环。


文章目录

    • [全志T113 Tina-SDK 配套工具链开发应用(从Makefile到CMake再到Autotools)](#全志T113 Tina-SDK 配套工具链开发应用(从Makefile到CMake再到Autotools))
    • 第一部分:交叉编译工具链位置与配置
    • 第二部分:系统库和头文件位置
    • [第三部分:使用 Makefile 交叉编译 Hello 程序](#第三部分:使用 Makefile 交叉编译 Hello 程序)
      • [3.1 编写源代码 hello.c](#3.1 编写源代码 hello.c)
      • [3.2 编写 Makefile](#3.2 编写 Makefile)
      • [3.3 执行编译](#3.3 执行编译)
    • [第四部分:使用 CMake 交叉编译](#第四部分:使用 CMake 交叉编译)
      • [4.1 安装 CMake](#4.1 安装 CMake)
      • [4.2 编写 CMakeLists.txt](#4.2 编写 CMakeLists.txt)
      • [4.3 使用外部构建(out-of-source)](#4.3 使用外部构建(out-of-source))
      • [4.4 编译](#4.4 编译)
      • [4.5 验证](#4.5 验证)
    • [第六部分:使用 Autotools 交叉编译](#第六部分:使用 Autotools 交叉编译)
        • [5.1 准备工作:确认开发板架构和交叉工具链](#5.1 准备工作:确认开发板架构和交叉工具链)
        • [5.2 清理之前编译的残留文件](#5.2 清理之前编译的残留文件)
        • [5.3 配置交叉编译(静态链接)](#5.3 配置交叉编译(静态链接))
        • [5.4 编译](#5.4 编译)
        • [5.5 验证生成的可执行文件](#5.5 验证生成的可执行文件)
        • [5.6 通过 ADB 传输到开发板并运行](#5.6 通过 ADB 传输到开发板并运行)
        • [5.7 常见错误汇总与解决方案](#5.7 常见错误汇总与解决方案)
        • [5.8 完整一键脚本(供参考)](#5.8 完整一键脚本(供参考))
    • [第六部分:ADB 连接开发板并部署程序](#第六部分:ADB 连接开发板并部署程序)
      • [6.1 连接开发板 USB 到虚拟机](#6.1 连接开发板 USB 到虚拟机)
      • [6.2 推送可执行文件到开发板](#6.2 推送可执行文件到开发板)
      • [6.3 通过串口或 adb shell 运行](#6.3 通过串口或 adb shell 运行)
    • 第七部分:常见错误与注意事项
      • [7.1 Makefile 中缺少 TAB 键](#7.1 Makefile 中缺少 TAB 键)
      • [7.2 STAGING_DIR 未定义警告](#7.2 STAGING_DIR 未定义警告)
      • [7.3 CMake 未使用交叉编译器](#7.3 CMake 未使用交叉编译器)
      • [7.4 Autotools 缺少宏或工具](#7.4 Autotools 缺少宏或工具)
    • 面试官提问环节
      • [第1问:Tina-SDK 交叉编译工具链的前缀是什么?如何将其加入 PATH?](#第1问:Tina-SDK 交叉编译工具链的前缀是什么?如何将其加入 PATH?)
      • [第2问:使用 Makefile 交叉编译时,常见的缩进错误是什么?如何解决?](#第2问:使用 Makefile 交叉编译时,常见的缩进错误是什么?如何解决?)
      • [第3问:CMake 交叉编译时,如何指定交叉编译器?需要注意什么顺序?](#第3问:CMake 交叉编译时,如何指定交叉编译器?需要注意什么顺序?)
      • [第4问:Autotools 项目的 `./configure` 中 `--host` 和 `--prefix` 分别有什么作用?](#第4问:Autotools 项目的 ./configure--host--prefix 分别有什么作用?)
      • [第5问:`adb push` 和 `adb shell` 的作用是什么?](#第5问:adb pushadb shell 的作用是什么?)

第一部分:交叉编译工具链位置与配置

bash

复制代码
book@ubuntu1804:~/tina-d1-h/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin$ ls
arm-openwrt-linux-addr2line    arm-openwrt-linux-muslgnueabi-addr2line
arm-openwrt-linux-ar           arm-openwrt-linux-muslgnueabi-ar
arm-openwrt-linux-as           arm-openwrt-linux-muslgnueabi-as
arm-openwrt-linux-c++          arm-openwrt-linux-muslgnueabi-c++
...
arm-openwrt-linux-gcc          arm-openwrt-linux-muslgnueabi-gcc
arm-openwrt-linux-gcc-6.4.1    arm-openwrt-linux-muslgnueabi-gcc-6.4.1
...

讲解

Tina-SDK 自带的交叉编译工具链位于 SDK 目录下的 prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin

工具链命名规则 :前缀为 arm-openwrt-linux-muslgnueabi-,后面跟具体工具名,例如:

  • arm-openwrt-linux-muslgnueabi-gcc:C 编译器
  • arm-openwrt-linux-muslgnueabi-g++:C++ 编译器
  • arm-openwrt-linux-muslgnueabi-ld:链接器
  • arm-openwrt-linux-muslgnueabi-strip:去除调试符号

C 库类型musl ------ 轻量级 C 库,适合嵌入式系统。工具链基于 GCC 6.4.1。

配置 PATH 环境变量(临时,仅当前终端有效):

bash

复制代码
export PATH=$PATH:/home/ubuntu/tina-d1-h/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin

验证工具链

bash

复制代码
arm-openwrt-linux-muslgnueabi-gcc -v

你应该能看到 gcc version 6.4.1 (OpenWrt/Linaro GCC 6.4.2017.11) 等信息。

提示 :每次新开终端都需要重新执行 export,或者将命令写入 ~/.bashrc 永久生效。


第二部分:系统库和头文件位置

bash

复制代码
# 系统lib库所在路径
~/tina-d1-h/out/t113-100ask/staging_dir/target/usr/lib

# 系统头文件所在路径
~/tina-d1-h/out/t113-100ask/staging_dir/target/usr/include

# 全志专用头文件
~/tina-d1-h/out/t113-100ask/staging_dir/target/usr/include/allwinner

讲解

当你用 Tina-SDK 编译完系统(执行过 make)后,out/t113-100ask/staging_dir/target/ 目录下会生成一个临时的根文件系统镜像,里面包含了:

  • usr/lib:所有编译好的动态库(.so)和静态库(.a
  • usr/include:所有头文件
  • usr/include/allwinner:全志芯片专用驱动/硬件接口头文件

为什么需要这些路径? 当你编写应用程序并依赖某些库(如 libcurl、libxml2、libaw_aacdec 等)时,编译器和链接器需要知道:

  • 头文件位置(用 -I 参数)
  • 库文件位置(用 -L 参数)

后面我们的 Makefile 和 CMake 都会引用这些路径。


第三部分:使用 Makefile 交叉编译 Hello 程序

3.1 编写源代码 hello.c

c

复制代码
#include <stdio.h>
int main(void)
{
    printf ("Hello 100ASK T113-Pro !!! \r\n");
    return 0;
}

3.2 编写 Makefile

makefile

复制代码
CC := arm-openwrt-linux-muslgnueabi-gcc
hello: hello.c
    ${CC} -o hello hello.c   # 注意:这行前面必须是【TAB】键,不能是空格
clean:
    rm hello

重要错误 :Makefile 中命令行的缩进必须使用 TAB 键,不能用空格。如果使用空格,会报错:

text

复制代码
Makefile:3: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.

解决方法:用 vivim 打开 Makefile,将 hello: 下一行的空格全部删除,然后按 Tab 键重新缩进。

3.3 执行编译

bash

复制代码
ubuntu@ubuntu1804:~$ make
arm-openwrt-linux-muslgnueabi-gcc -o hello hello.c
arm-openwrt-linux-muslgnueabi-gcc.bin: warning: environment variable 'STAGING_DIR' not defined
arm-openwrt-linux-muslgnueabi-gcc.bin: warning; environment variable 'STAGING_DIR' not defined

警告解释STAGING_DIR 是 Tina 构建系统使用的环境变量,指向 out/.../staging_dir 目录。如果不定义,工具链可能找不到一些库和头文件。但对于一个简单的 printf 程序,这个警告可以忽略(因为 libc 是工具链自带的)。

验证生成的文件

bash

复制代码
file hello

输出:

text

复制代码
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-armhf.so.1, not stripped
  • ARM:说明是 ARM 架构
  • dynamically linked:动态链接,需要依赖板子上的 musl C 库
  • interpreter /lib/ld-musl-armhf.so.1:动态链接器的路径

ADB 传输要点:OTG/Debug都要接上串口线,并且虚拟机也要连接上ADB

  • adb push:推送通过串口到开发板

正常应该看到这样的效果

第四部分:使用 CMake 交叉编译

4.1 安装 CMake

bash

复制代码
ubuntu@ubuntu1804:~$ sudo apt install cmake

4.2 编写 CMakeLists.txt

cmake

复制代码
cmake_minimum_required(VERSION 3.10)
project(helloword)
SET(CROSS_COMPILE 1)
set(CMAKE_SYSTEM_NAME Linux)

# 交叉编译器路径
set(CMAKE_C_COMPILER "/home/ubuntu/tina-d1-h/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin/arm-openwrt-linux-muslgnueabi-gcc")

# 链接库路径
link_directories(
    /home/ubuntu/tina-d1-h/out/t113-100ask/staging_dir/target/usr/lib
)

# 头文件路径
include_directories(/home/ubuntu/tina-d1-h/out/t113-100ask/staging_dir/target/usr/include/)
include_directories(/home/ubuntu/tina-d1-h/out/t113-100ask/staging_dir/target/usr/include/allwinner/)
include_directories(/home/ubuntu/tina-d1-h/out/t113-100ask/staging_dir/target/usr/include/allwinner/include/)

add_executable(hello_word hello.c)

4.3 使用外部构建(out-of-source)

bash

复制代码
mkdir build
cd build
cmake ..

执行 cmake .. 后,会生成 Makefile 文件。

输出 (注意此处 cmake 检测到的是主机 GCC,而不是交叉编译器------这是错误的):

text

复制代码
-- The C compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
...

问题 :上面的 CMakeLists.txt 中明明设置了 CMAKE_C_COMPILER,为什么还是用了主机的 /usr/bin/cc
原因set(CMAKE_C_COMPILER ...) 必须在 project() 之前定义,否则 CMake 会先使用默认编译器探测。修正后的 CMakeLists.txt 开头应该是:

cmake

复制代码
cmake_minimum_required(VERSION 3.10)
set(CMAKE_C_COMPILER "/path/to/arm-openwrt-linux-muslgnueabi-gcc")
project(helloword)
...

同学们可以按照修正后的顺序编写。

4.4 编译

bash

复制代码
make

输出显示交叉编译器被调用,同样会有 STAGING_DIR 警告。最终生成 hello_word 可执行文件。

4.5 验证

bash

复制代码
file hello_word

应该看到 ELF 32-bit LSB executable, ARM


依旧串口传输

正常结果

第六部分:使用 Autotools 交叉编译

5.1 准备工作:确认开发板架构和交叉工具链

首先登录开发板(通过串口或 ADB),查看架构:

bash

复制代码
# 在开发板上执行
uname -m

典型输出:armv7l(32位 ARM)或 aarch64(64位 ARM)。

本文以 armv7l + TinaLinux(使用 musl libc)为例。

在 Ubuntu 宿主机上,你需要目标平台的交叉编译器 。Tina SDK 通常自带工具链,其前缀类似 arm-openwrt-linux-muslgnueabi。如果你还没有配置好环境变量,可以先定位工具链位置:

bash

复制代码
# 假设 $T 指向 Tina SDK 根目录
ls $T/prebuilt/gcc/linux-x86/arm/arm-openwrt-linux-muslgnueabi/bin/

确认存在 arm-openwrt-linux-muslgnueabi-gcc 后,将其加入 PATH:

bash

复制代码
export PATH=$T/prebuilt/gcc/linux-x86/arm/arm-openwrt-linux-muslgnueabi/bin:$PATH

注意 :如果你的 SDK 路径不同,请相应修改。也可以使用系统自带的 gcc-arm-linux-gnueabihf,但 TinaLinux 使用 musl,静态链接时一般能兼容,不过推荐使用 SDK 配套的工具链。

5.2 清理之前编译的残留文件

~/hello_auto 目录下执行:

bash

复制代码
cd ~/hello_auto
make distclean

这会删除所有由 configuremake 生成的文件,让项目回到刚跑完 automake --add-missing 的状态。

5.3 配置交叉编译(静态链接)

运行 configure 脚本,并指定:

  • --host:目标三元组(告诉 build 系统我们要交叉编译)
  • CC:明确指定交叉编译器(防止 configure 找到宿主机 gcc)
  • LDFLAGS="-static":静态链接,避免开发板上缺少动态库

bash

复制代码
./configure --host=arm-openwrt-linux-muslgnueabi \
            --prefix=/usr \
            CC=arm-openwrt-linux-muslgnueabi-gcc \
            LDFLAGS="-static"

成功标志 :输出中应出现 checking whether we are cross compiling... yes

如果报错 C compiler cannot create executables,请检查:

  • 交叉编译器路径是否正确(which arm-openwrt-linux-muslgnueabi-gcc
  • 是否缺少必要的库(如静态 libc),可尝试去掉 LDFLAGS="-static" 先测试动态链接。
5.4 编译

bash

复制代码
make

输出中应看到交叉编译器被调用,例如:

text

复制代码
arm-openwrt-linux-muslgnueabi-gcc -DHAVE_CONFIG_H ... -c -o main.o main.c
arm-openwrt-linux-muslgnueabi-gcc -static -o hello main.o

如果出现 warning: environment variable 'STAGING_DIR' not defined,可忽略(不影响结果)。

5.5 验证生成的可执行文件

bash

复制代码
file src/hello

期望输出:

text

复制代码
src/hello: ELF 32-bit LSB executable, ARM, statically linked, ...
5.6 通过 ADB 传输到开发板并运行

常见错误1:adb push 时目标路径写错

bash

复制代码
# 错误:目标是一个目录,未指定文件名
adb push src/hello /data/local/tmp/          # 报错:remote Is a directory

# 正确:指定完整路径+文件名
adb push src/hello /data/local/tmp/hello

常见错误2:推送到 /root 后无法 chmod

如果你 push 到 /root/hello_arm,在 Ubuntu 宿主机上执行 chmod 755 /root/hello_arm 会报 Permission denied,因为 /root 是开发板上的目录,你需要在开发板上执行 chmod。

正确做法:

bash

复制代码
# 1. 推送到开发板可写的目录(例如 /data/local/tmp/ 或 /root)
adb push src/hello /data/local/tmp/hello_arm

# 2. 通过 adb shell 登录开发板,修改权限并运行
adb shell
chmod 755 /data/local/tmp/hello_arm
/data/local/tmp/hello_arm

或者一条命令完成:

bash

复制代码
adb push src/hello /data/local/tmp/hello_arm && \
adb shell chmod 755 /data/local/tmp/hello_arm && \
adb shell /data/local/tmp/hello_arm

预期输出

text

复制代码
Hello World!
This is amhello 1.0:
5.7 常见错误汇总与解决方案
错误现象 原因 解决方法
config.status: error: cannot find input file: 'Makefile.in' 忘记运行 automake --add-missingautoheader 执行 aclocal; autoheader; autoconf; automake --add-missing
make: *** No targets specified and no makefile found. 没有先运行 ./configure 先运行 ./configure 生成 Makefile
./hello: line 1: syntax error: unexpected word 在开发板上运行了 x86 版本的可执行文件 确认交叉编译并 file 查看架构
adb push: remote Is a directory 目标路径末尾带了 / 且未指定文件名 指定完整文件名,如 /data/local/tmp/hello
chmod: cannot access '/root/hello_arm': Permission denied 在宿主机上对开发板路径执行 chmod 应通过 adb shell chmod ... 在开发板上执行
arm-openwrt-linux-muslgnueabi-gcc.bin: warning: environment variable 'STAGING_DIR' not defined Tina SDK 环境变量缺失 可忽略,不影响编译;若要消除,export STAGING_DIR=$T/staging_dir/target-...
cannot execute binary file: Exec format error 开发板架构与编译目标不匹配(如 64 位板子运行 32 位程序) 检查开发板 uname -m,重新配置正确的 --host(如 aarch64-openwrt-linux-musl
5.8 完整一键脚本(供参考)

将以下内容保存为 cross_build.sh,根据你的实际工具链路径修改:

bash

复制代码
#!/bin/bash
# 交叉编译并自动部署到开发板

# 设置工具链路径(根据实际修改)
export PATH=/path/to/tina-sdk/prebuilt/gcc/linux-x86/arm/arm-openwrt-linux-muslgnueabi/bin:$PATH
export STAGING_DIR=/path/to/tina-sdk/staging_dir/target-arm_cortex-a7_musl-1.1.16_eabi  # 可选

# 清理
make distclean

# 配置
./configure --host=arm-openwrt-linux-muslgnueabi \
            --prefix=/usr \
            CC=arm-openwrt-linux-muslgnueabi-gcc \
            LDFLAGS="-static"

# 编译
make

# 检查
file src/hello

# 部署
adb push src/hello /data/local/tmp/hello_arm
adb shell chmod 755 /data/local/tmp/hello_arm
adb shell /data/local/tmp/hello_arm

执行 bash cross_build.sh 即可完成全流程。

第六部分:ADB 连接开发板并部署程序


6.1 连接开发板 USB 到虚拟机

VMware 菜单 → 可移动设备 → 选择 Google Tina ADB → 连接。

确保开发板已启动并且 USB 线(OTG 口)连接到电脑。在虚拟机中执行:

bash

复制代码
adb devices

输出

text

复制代码
List of devices attached
20080411    device

说明设备已识别。

6.2 推送可执行文件到开发板

bash

复制代码
adb push hello /root/

输出

text

复制代码
hello: 1 file pushed. 1.3 MB/s (7132 bytes in 0.005s)

6.3 通过串口或 adb shell 运行

bash

复制代码
adb shell
# 进入板子 shell
cd /root
./hello

图片输出

text

复制代码
Hello 100ASK T113-Pro !!!

第七部分:常见错误与注意事项

7.1 Makefile 中缺少 TAB 键

错误信息missing separator
解决 :用 vi 确保命令行前是 Tab 而不是空格。

7.2 STAGING_DIR 未定义警告

警告environment variable 'STAGING_DIR' not defined
影响 :简单程序无影响;若依赖外部库可能找不到。
解决(可选):

bash

复制代码
export STAGING_DIR=/home/ubuntu/tina-d1-h/out/t113-100ask/staging_dir

7.3 CMake 未使用交叉编译器

现象cmake 输出显示 /usr/bin/cc
解决 :将 set(CMAKE_C_COMPILER ...) 放在 project() 之前

7.4 Autotools 缺少宏或工具

bash

复制代码
sudo apt install autoconf automake libtool

面试官提问环节

第1问:Tina-SDK 交叉编译工具链的前缀是什么?如何将其加入 PATH?

参考答案

前缀为 arm-openwrt-linux-muslgnueabi-。加入 PATH:

bash

复制代码
export PATH=$PATH:/home/ubuntu/tina-d1-h/prebuilt/gcc/linux-x86/arm/toolchain-sunxi-musl/toolchain/bin

第2问:使用 Makefile 交叉编译时,常见的缩进错误是什么?如何解决?

参考答案

Makefile 中命令必须以 Tab 字符 开头,不能用空格。错误提示 missing separator。用 vi 打开,将空格删除后按 Tab 键即可。

第3问:CMake 交叉编译时,如何指定交叉编译器?需要注意什么顺序?

参考答案

在 CMakeLists.txt 中:

cmake

复制代码
set(CMAKE_C_COMPILER "/path/to/arm-openwrt-linux-muslgnueabi-gcc")
project(helloword)

必须先设置编译器再调用 project(),否则 CMake 会先使用默认编译器探测。

第4问:Autotools 项目的 ./configure--host--prefix 分别有什么作用?

参考答案

  • --host:指定目标系统三元组,使 configure 查找对应的交叉编译器。
  • --prefix:指定安装目录(例如 /usr),最终可执行文件会安装在 /usr/bin(相对于 DESTDIR 而言)。

第5问:adb pushadb shell 的作用是什么?

参考答案

  • adb push <本地文件> <远程路径>:将主机文件传输到开发板。
  • adb shell:打开开发板的远程终端,可直接执行板子上的命令。

结束语:本章通过 Makefile、CMake、Autotools 三种方式演示了如何交叉编译应用程序,并通过 ADB 部署到 T113 开发板运行。这三种构建系统覆盖了绝大多数嵌入式项目的需求。作为初学者,建议先熟练掌握 Makefile 方法(最直接),再了解 CMake 和 Autotools(阅读开源项目时会遇到)。反复练习,直到能独立完成从编写代码到板子上运行的完整流程。加油!

相关推荐
HLC++2 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室3 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy6 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕6 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫8 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生8 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.119 小时前
linux基础IO
linux·运维·服务器
BelongPanda11 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯11 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983411 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器