第2课:恢复出厂、掌握 Linux 基础命令并完成首次 GCC 编译

本节路线图

|-----------------|---|------------------|---|------------------|
| 为什么先学"恢复出厂" | → | 恢复出厂与固化到eMMC | → | Linux目录结构要先看 |

|-------------------------------------------------------------------------------------|----------------------------------------|
| | 小猫提醒 这节有分区、烧录或删除类操作,先确认盘符和路径,再按回车。 |

|--------------------------------------------------------------------------------------|-------------------------------------------|
| | 猫头鹰提示 编译前先对齐目标架构和工具链名字,别让主机程序和板卡程序搞混。 |

第 1 课我们把开发环境和整体链路搭起来了,这一课要把"能进系统"和"能在系统上做事"两件事真正落地。对于 Linux 驱动和 Qt 开发来说,开发板一旦因为误操作导致系统损坏、目录混乱、权限错误或者编译链没装对,后面的实验会变得非常低效。所以本节不追求花哨,而是先把恢复能力、命令行能力和编译能力打牢。

本节路线图(参考原理图)

|---------------------------------------------------|---|----------------------------------|---|-----------------------------------------|---|-------------------------------------|
| 阶段 1:救援准备 下载并整理 sdcard_imageemmc_image | → | 阶段 2:SD 卡救援启动 分区、格式化、写入可启动镜像 | → | 阶段 3:eMMC 固化 从 SD 启动后执行烧写脚本并切回 eMMC | → | 阶段 4:编译验收 用 GCC/交叉 GCC 验证开发环境闭环 |

|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
| | 小猫提醒: 这一课会碰到 make_parted.shdeploy_image.shrm -rf 这类高风险动作。先核对盘符、挂载点和启动模式,再按回车。 |

|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
| | **猫头鹰提示:**驱动和 Qt 开发最怕"环境坏了却以为是代码错了"。所以本节的重点不是背命令,而是建立"能恢复、能排查、能编译"的完整闭环。 |

本节目标

  • 学会在系统损坏或实验失败后恢复出厂,并重新固化到 eMMC。
  • 建立对 Linux 目录结构、文件权限和常用文件管理命令的基本认知。
  • 理解什么是交叉编译,为什么嵌入式开发离不开它。
  • 能在 Linux 环境下完成一次基础的 GCC/交叉 GCC 编译验证。

一、为什么先学"恢复出厂"

很多同学会低估这一节的重要性,觉得"恢复系统"只是售后动作,和开发没关系。实际上恰恰相反,在驱动调试、设备树修改、根文件系统裁剪、Qt 库替换这些工作中,只要某一步出错,就可能让系统无法正常启动。这个时候如果没有一套可复原的流程,整个开发就会被卡住。

恢复出厂流程的核心思路很简单:

  • 先把可启动的 SD 卡镜像烧好。
  • 再把 eMMC 镜像拷贝到 SD 卡启动后的系统里。
  • 从 SD 卡启动进入 Linux。
  • 通过串口或 SSH 登录板卡,执行 eMMC 分区和烧写脚本。
  • 最后切回 eMMC 启动,确认系统恢复成功。

这意味着 SD 卡不只是"临时启动盘",更像是一张救援卡。只要它准备好,哪怕后面把板卡系统改坏了,也能较快回到可工作的状态。

二、恢复出厂与固化到 eMMC 的实操逻辑

原始资料里的流程比较偏操作截图,这里把它整理成更容易复现的步骤。

0. 恢复出厂闭环参考图

|------------------------|---|------------------|---|--------------------------|---|-----------------------|
| Ubuntu 主机 准备恢复包与脚本 | → | SD 卡 制作救援启动盘 | → | 开发板 从 SD 启动并进入 Linux | → | eMMC 分区、部署、切回固化启动 |

|-------------------------------------------------------------------------------------|--------------------------------------------------------------|
| | **兔兔建议:**第一次操作时,建议你把"当前盘符""SD 挂载点""拨码开关状态"写在纸上。看起来笨一点,但会非常稳。 |

1. 准备镜像文件

先下载对应板卡型号的恢复镜像压缩包,解压后通常会得到两个目录:

  • sdcard_image
  • emmc_image

可以把整个恢复目录先放到 Ubuntu 用户主目录,例如:

复制代码
cp -r rst_to_factory /home/uisrc/

2. 制作 SD 启动卡

进入 sdcard_image 目录后,先切到 root 权限,再执行分区和镜像部署脚本:

复制代码
su
./make_parted.sh
./deploy_image.sh

这里有两个常见细节:

  • 脚本会要求你输入盘符,常见是 sdb,一定要先确认设备名,避免误格式化主机硬盘。
  • make_parted.sh 负责分区和格式化,deploy_image.sh 负责把启动镜像和根文件系统写进去。

3. 把 eMMC 镜像拷贝到 SD 卡系统里

烧好 SD 卡之后,还要把 eMMC 用到的镜像目录拷贝进去,便于开发板启动后直接本地烧写:

复制代码
cp -r /home/uisrc/rst_to_factory/emmc_image/ /media/uisrc/rootfs/home/uisrc/

如果你的挂载点不是 /media/uisrc/rootfs/,就要根据实际挂载路径调整命令。这里特别能体现 Linux 基础命令的重要性,因为后面你会经常依赖 pwdlscp 来确认路径是否正确。

4. 从 SD 卡启动并烧写 eMMC

把板卡切到 SD 启动模式,上电进入系统后,用串口或 SSH 登录,再执行 eMMC 烧写:

复制代码
su
cd /home/uisrc/emmc_image
./make_parted.sh
./deploy_image.sh

完成后,切换拨码开关回 eMMC 启动模式,再次上电验证。如果系统能从 eMMC 正常启动,说明恢复流程闭环了。

5. 这一步为什么对后续驱动开发很关键

因为驱动实验里最怕的是"我不知道是代码问题,还是系统环境已经坏了"。有了恢复出厂手段后,你就可以把问题切开:

  • 如果恢复后系统正常,说明硬件和基础镜像大概率没问题。
  • 如果恢复后还不正常,就要优先查硬件、启动文件或镜像版本。

这会让排障效率高很多。

三、Linux 目录结构要先看懂什么

驱动开发和 Qt 开发虽然看起来一个偏底层、一个偏界面,但它们最终都跑在 Linux 文件系统之上。目录不清楚,后面找驱动节点、库文件、配置文件都会很痛苦。

先记住几个最常用的目录:

  • /boot:启动相关文件,经常和内核、启动镜像打交道。
  • /dev:设备文件目录,驱动调试时最常去看。
  • /etc:系统配置文件目录。
  • /home:普通用户主目录,平时开发资料通常放这里。
  • /lib:动态库目录,Qt 程序和很多系统程序都依赖它。
  • /media:外部介质挂载点,U 盘、SD 卡、共享目录经常会出现在这里。
  • /proc:进程和内核状态的虚拟文件系统。
  • /sys:设备模型和驱动信息非常重要的虚拟文件系统。
  • /usr:大量应用程序和共享资源所在目录。
  • /var:日志、缓存和运行时数据常放在这里。

对驱动开发来说,最值得形成习惯的是这两个对应关系:

  • 看设备节点时,多去 /dev
  • 看设备枚举、总线和属性时,多去 /sys

后面我们讲字符设备、平台驱动、设备树的时候,这两个目录会反复出现。

目录参考图:遇到问题时先去哪里看

目录 你通常先看什么 驱动 / Qt 开发里常见动作
/dev 设备节点有没有出现 测试程序打开串口、LED、I2C、SPI 节点
/sys 总线、属性、驱动绑定关系 排查设备树、平台驱动、class 信息
/lib / /usr/lib 动态库是否齐全 Qt 程序运行失败时检查依赖库
/boot 内核、启动镜像、启动参数 恢复系统、替换内核、核对启动文件

四、权限模型必须先过关

Linux 和 Windows 很不一样的一点,是它天然面向多用户、多权限场景。很多"命令执行失败"其实不是命令错了,而是你没有权限。

一个典型权限串长这样:

复制代码
-rwxr-xr--

可以把它拆成三组:

  • 拥有者权限:rwx
  • 用户组权限:r-x
  • 其他用户权限:r--

其中:

  • r 表示可读
  • w 表示可写
  • x 表示可执行

1. 用数字表示权限

数字权限最常见:

  • r = 4
  • w = 2
  • x = 1

比如:

  • 755 = rwx r-x r-x
  • 644 = rw- r-- r--
  • 777 = rwx rwx rwx

2. 三个最常用的权限命令

复制代码
chgrp users test
chown root:root test
chmod 755 test

你可以把它们理解成:

  • chgrp:改属组
  • chown:改属主和属组
  • chmod:改读写执行权限

3. 驱动开发里为什么总会碰到权限问题

因为很多设备节点默认只有 root 可访问。如果你的测试程序或 Qt 程序打开 /dev/xxx 失败,除了怀疑驱动逻辑,也要先确认:

  • 节点有没有创建成功
  • 当前用户有没有访问权限
  • 设备节点属主和属组是否合理

所以权限并不是"系统运维知识",而是驱动调试的基础能力。

五、这几个 Linux 命令一定要熟

原始资料里介绍了很多基础命令,这里不求一口气背完,但下面这些是每天都会用到的。

1. ls:看目录和文件

复制代码
ls
ls -a
ls -l
ls -al

最常用的是 ls -al,它能同时看到隐藏文件和详细属性。很多时候你以为"目录里什么都没有",其实只是漏了隐藏文件。

2. cdpwd:搞清楚你现在在哪

复制代码
cd /root/test
cd ./test
cd ..
cd ~
pwd
pwd -P

这里最容易出错的不是命令本身,而是相对路径和绝对路径混用。建议初学阶段尽量多用绝对路径,先减少路径判断错误。

3. mkdirrmdir:创建和删除目录

复制代码
mkdir test
mkdir -p test1/test2/test3
rmdir test
rmdir -p test1/test2/test3

-p 很实用,它能递归创建或递归删除空目录。

4. cprmmv:文件管理三件套

复制代码
cp ~/test /tmp/test2
cp -r source_dir target_dir
rm -i test2
rm -rf old_dir
mv test mvtest
mv mvtest mvtest2

这里我建议你形成两个习惯:

  • 删除前先 ls 确认目标
  • 初学阶段多用 -i 交互确认,减少误删

因为在板卡根文件系统里,一次 rm -rf 用错目录,可能就直接把实验环境删坏了。

六、什么是 GCC 编译,为什么嵌入式里要讲"交叉编译"

对于桌面开发者来说,本地编译是很自然的事情:在自己的电脑上写代码、编译、运行,三个动作都在同一平台完成。

但嵌入式开发不是这样。

我们常见的开发模式是:

  • 在 x86 的 Ubuntu 主机上写代码
  • 编译出 ARM 或 AArch64 目标程序
  • 再把程序放到开发板上运行

这就是交叉编译。

参考原理图:本地编译与交叉编译的分工

|-----------------------------------|---|-----------------------------------------------------------|---|-----------------------------------|
| x86 Ubuntu 主机 写代码、调用 GCC、管理工程 | → | 交叉工具链 arm-linux-gnueabi-gcc aarch64-linux-gnu-gcc | → | ARM / AArch64 开发板 运行目标程序并验证结果 |

|--------------------------------------------------------------------------------------|----------------------------------------------------------------------|
| | 猫头鹰提示: "能编译"不等于"能在板卡上跑"。一定要再用 fileldd、实际运行结果去确认目标架构和依赖是否正确。 |

1. 本地编译和交叉编译的区别

  • 本地编译:编译平台和运行平台相同
  • 交叉编译:编译平台和运行平台不同

比如:

  • 在 Windows 上编出 .exe 给 Windows 跑,是本地编译
  • 在 Ubuntu 上编出 ARM Linux 程序给 MPSoC 板卡跑,是交叉编译

2. 为什么必须交叉编译

嵌入式板卡资源有限,这是最直接的原因。

  • 板卡 CPU、内存、存储空间都比 PC 紧张
  • 本地安装完整编译环境成本高
  • 编译大型项目会很慢
  • 真正量产时,不可能给每块板子都装一套开发工具链

所以最合理的做法,是在性能更强的主机上完成编译,再把结果部署到目标板。

七、交叉编译链到底是什么

很多同学会把编译器简单理解成一个 gcc 命令,但严格来说,真正工作的是一整套工具链。

一个 C 程序从源码到可执行文件,通常会经历:

  1. 预处理
  2. 编译
  3. 汇编
  4. 链接

对应会涉及头文件展开、宏替换、语法检查、汇编生成、目标文件生成和最终链接。也就是说,交叉编译不是"把一个命令改个名字"这么简单,而是一整套面向目标平台的工具集合。

八、怎么理解交叉编译器的命名

资料里提到两个已经安装过的交叉编译器:

  • gcc-arm-linux-gnueabi
  • gcc-aarch64-linux-gnu

你可以先粗略理解它们的差异:

  • arm-linux-gnueabi:偏 32 位 ARM 目标
  • aarch64-linux-gnu:偏 64 位 ARM 目标

名称里通常会体现几件事:

  • 目标架构
  • 运行系统
  • ABI 或工具链约定

现阶段不用死记所有命名规则,但要建立一个意识:编译器名字不一样,往往就意味着目标平台不一样。你后面编 Qt 程序、驱动测试程序时,一旦工具链选错,最终生成的程序就可能根本不能在板卡上运行。

九、第一次 GCC 编译该怎么做

本节不追求复杂项目,先验证"工具链通不通"。

1. 本机 GCC 验证

先确认 Ubuntu 主机本地 GCC 可用:

复制代码
gcc --version

再写一个最简单的 hello.c

复制代码
#include <stdio.h>

int main(void) {
    printf("hello linux\\n");
    return 0;
}

编译并运行:

复制代码
gcc hello.c -o hello
./hello

如果这一步成功,说明本机基础编译环境正常。

2. 交叉 GCC 验证

再确认交叉编译器是否存在:

复制代码
arm-linux-gnueabi-gcc --version
aarch64-linux-gnu-gcc --version

然后用交叉编译器把同一个 hello.c 编成目标板程序:

复制代码
arm-linux-gnueabi-gcc hello.c -o hello_arm
aarch64-linux-gnu-gcc hello.c -o hello_aarch64

这两个生成文件通常不能在当前 x86 Ubuntu 主机直接运行,但可以用 file 命令确认它们的目标架构:

复制代码
file hello
file hello_arm
file hello_aarch64

这一步的意义非常大,因为它相当于把"写代码 -> 编译 -> 得到目标平台程序"的基本通路先打通了。后面不管是写驱动配套的测试程序,还是写 Qt 应用,都离不开这条链路。

十、把这三部分串起来看,才是完整开发思路

这一课看似内容很散,其实正好构成了嵌入式 Linux 开发最常见的三种底层能力:

  • 系统坏了,能恢复
  • 进系统后,能熟练管理文件和路径
  • 写完代码后,能正确编译出目标平台程序

这三件事缺任何一个,后面的驱动和 Qt 实验都会反复卡住。

比如一个很真实的场景:

  • 你修改了某个库或脚本,把系统搞乱了
  • 用恢复流程把板卡救回来
  • cpmvchmod 重新整理部署文件
  • 用交叉 GCC 编译测试程序验证驱动节点是否可用

这才是工程里真正会发生的事情。

常见问题

1. 为什么我能进系统,但还是说不会 Linux 开发

因为"能登录"不等于"能定位问题"。真正开发时,你必须能看路径、改权限、复制文件、判断程序架构、恢复系统,这些都属于基本功。

2. chmod 777 是不是最省事

短期确实省事,但不推荐养成习惯。权限一旦全部放开,后面更难分辨到底是谁能访问、为什么能访问。调试时可以临时使用,正式项目里要更克制。

3. 为什么交叉编译好的程序在 Ubuntu 主机上运行不了

因为它不是为当前主机架构生成的。你在 x86 上编出来的 ARM 程序,应该放到 ARM 板卡上运行。

4. 为什么恢复出厂还要经过 SD 卡

因为很多时候 eMMC 上的系统已经不可依赖了,而 SD 卡更适合作为外部启动和修复介质。

课后练习

  • 自己完整走一遍 SD 卡恢复和 eMMC 固化流程,把关键命令抄成操作清单。
  • ls -alpwdcdmkdir -pcp -rmvrm -i 各做一次练习。
  • 新建一个 hello.c,分别用本机 GCC 和交叉 GCC 编译,并用 file 命令观察产物差异。
  • 试着解释 /dev/sys/etc/home 四个目录分别在后续驱动开发里会扮演什么角色。

下一课预告

下一课我们会继续往开发基本功推进,开始把 Makefile、编译组织方式和调试习惯串起来。等这部分稳定之后,再进入真正的驱动框架和 Qt 工程实践,整条学习曲线会顺得多。

相关推荐
摇滚侠15 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush416 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行52016 小时前
Linux 11 动态监控指令top
linux
不会C语言的男孩17 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
古城小栈17 小时前
Unix 与 Linux 异同小叙
linux·服务器·unix
桥田智能17 小时前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
凡人叶枫18 小时前
Effective C++ 条款42:了解 typename 的双重意义
java·linux·服务器·c++
2601_9618752419 小时前
决战申论100题2026|最新|范文
linux·容器·centos·debian·ssh·fabric·vagrant
java_cj19 小时前
深入kube-apiserver认证机制:从Bearer Token到mTLS的完整认证链解析
linux·运维·服务器·云原生·容器·kubernetes
lsyeei19 小时前
linux 系统目录详解
linux·运维·服务器