1、Buildroot 是干什么的?
一个 "一键生成好"嵌入式Linux系统的工具。
-
输入 :一个配置文件 (比如
100ask_imx6ull_defconfig)。 -
处理 :它自动去官方网站下载你指定的U-boot、Linux内核、各种APP (如
sshd,alsa-utils) 的源码,然后自动打补丁、配置、交叉编译。 -
输出:三个可以直接烧录到开发板的成品:
u-boot.imx(引导程序)zImage(Linux内核)rootfs.tar(根文件系统,包含/bin,/etc,/lib等)
一句话:你告诉它板子型号,它就能自动编译出完整的系统镜像。
1.1 与当前工作流程的对比
| 功能 | 目前在做 (手动) | Buildroot 的做法 (自动) |
|---|---|---|
| 编译 U-boot | 进入U-boot目录,执行 make 命令手动编译。 |
自动下载、配置、编译。 |
| 编译 Kernel | 进入Kernel目录,执行 make zImage 和 make modules。 |
自动下载、配置、编译。 |
| 制作根文件系统 | (最复杂的部分) :需要手动下载 Busybox,编译,创建 /dev, /proc 等目录,配置 inittab 等。 |
自动完成:自动编译 Busybox,自动创建目录结构,生成完整的文件系统镜像。 |
| 管理依赖库 | 手动下载 libpng, zlib 等库,手动交叉编译。 |
自动解决依赖 (选中某个APP,会自动选中它所需的库)。 |
1.2、 从零构建完整系统的大致步骤
从一个空白的 Ubuntu 环境 开始,用 Buildroot 工具,生成一个可以直接在开发板上运行的全功能 Linux 系统。步骤大致如下:
第一步:获取 Buildroot 源码
bash
git clone https://e.coding.net/weidongshan/buildroot.git
cd buildroot
第二步:配置开发板
Buildroot 支持数不清的板子,配置文件在 configs/ 目录下。
bash
# 例如,为你的 100ask_imx6ull 开发板进行配置
make 100ask_imx6ull_defconfig
这步Buildroot会生成一个 .config 文件,告诉他"目标板是100ask的6ull"。
第三步:定制内容
这一步是可选的,也挺重要,可以打开图形化界面微调:
go
make menuconfig
在这里可以:
- Target packages :选择要把哪些应用编译进系统(例如,选上
python3,openssh,alsa-utils等)。 - Filesystem images :选择最终生成文件系统的格式,比如
tar压缩包,或者直接生成可以烧录到 SD 卡的ext4镜像。
第四步:一键自动编译
这是最关键的一步,执行这个命令后:
go
make
Buildroot 在后台会自动化完成以下所有工作:
- 检查工具链:如果没有,它会自动下载并编译一个合适的交叉编译工具链。
- 下载源码:它会自动从官网下载 U-boot、Linux Kernel、Busybox 以及你选中的所有APP的源码。
- 编译:自动交叉编译 U-boot、Kernel、所有APP和库。
- 构建根文件系统 :自动创建
bin,sbin,etc,usr等目录,将编译好的命令和库文件放到正确的位置。 - 生成镜像 :最终在
output/images/目录下,生成你需要的所有文件。
第五步:烧录到开发板
最终,可以直接从 output/images/ 目录下获取三个文件:
u-boot-dtb.imx:使用我们在 6.2.2 章节学到的方法(dd命令)烧录到 SD 卡或 EMMC。zImage和.dtb文件 :使用 5.4 章节学到的方法,复制到/boot分区。rootfs.tar:将其解压到你的根文件系统分区。
2、NFS挂载文件流程
简单来说,NFS(Network File System,网络文件系统)可以让你在开发板上,通过网络直接访问和使用你 Ubuntu 虚拟机里的一个指定文件夹,就像访问开发板自身存储空间一样方便。
这个过程的核心,是把 Ubuntu 的一个目录通过网络"分享"出去,然后在开发板上把这个网络位置"挂载"到自己的一个空目录下,两者就神奇的"连接"起来了。这种方式在嵌入式开发中非常常用,尤其适合调试程序,因为它省去了反复烧写的繁琐流程。
把这个过程拆解为下面几步:
第一步:让 Ubuntu 和开发板"网上"互通
NFS 基于网络,所以 Ubuntu 虚拟机与开发板必须能够互相通信。它们通常通过网线连接到同一个路由器或交换机,从而处于同一个局域网段。
最关键的一步是设置虚拟机的网络模式。你需要将 VMware 或 VirtualBox 的网络适配器设置为 "桥接模式" 。这样,你的虚拟机就会和你的 Windows 电脑一样,从路由器获取一个独立的 IP 地址,并与开发板处于同一网络层面。
接着就可以进行网络测试了:
- 在 Ubuntu 终端输入
ifconfig,查看其 IP 地址(例如192.168.1.10)。 - 在开发板的串口终端输入
ifconfig,查看其 IP 地址(例如192.168.1.20)。 - 互相
ping一下测试连通性:- 在 Ubuntu 上:
ping 192.168.1.20。 - 在开发板上:
ping 192.168.1.10。 如果ping通,说明网络连接成功。
- 在 Ubuntu 上:
第二步:配置 Ubuntu 作为 NFS"服务器"
Ubuntu 作为服务器,需要安装并配置 NFS 服务,来决定哪个文件夹可以被分享。
-
安装 NFS 服务器:在 Ubuntu 终端执行:
bashsudo apt-get install nfs-kernel-server -
创建一个共享目录:这个目录就是用来存放你希望开发板访问的文件的。例如:
bashmkdir /home/book/nfs_share -
配置 NFS 导出目录 :这是关键步骤。需要通过修改配置文件
/etc/exports,来告诉 NFS 服务器哪个目录可以被谁访问。编辑文件:bashsudo vi /etc/exports在文件末尾添加一行,格式如下: /home/book/nfs_share *(rw,sync,no_root_squash) 参数解析:
/home/book/nfs_share:是你刚创建的共享目录的路径。*:代表允许所有IP地址 的客户端访问。你也可以指定一个网段,如192.168.1.0/24。rw:表示客户端对该目录有**读写(Read-Write)**权限。sync:数据同步写入内存和硬盘,保证数据安全。no_root_squash:允许开发板上的root用户保留root权限访问共享目录,方便文件操作。
-
重启 NFS 服务:使配置生效:
bashsudo /etc/init.d/nfs-kernel-server restart
第三步:让开发板"挂载"共享文件夹
在开发板上安装 NFS 客户端并进行挂载。
-
安装 NFS 客户端(通常开发板系统已集成,如果未安装则执行):
bashsudo apt install nfs-common -y -
创建一个挂载点:在开发板上创建一个空目录,作为访问 Ubuntu 共享文件夹的入口。
bashmkdir /mnt/nfs -
执行挂载命令:将 Ubuntu 的共享文件夹挂载到刚刚创建的目录上。
bashmount -t nfs -o nolock 192.168.1.10:/home/book/nfs_share /mnt/nfs命令解析:
-t nfs:指定挂载的文件系统类型为 NFS。-o nolock:一个常用选项,用于解决某些环境下的锁问题。192.168.1.10:你的 Ubuntu 虚拟机的 IP 地址。/home/book/nfs_share:Ubuntu 上配置的共享目录 ,注意 IP 后紧跟一个冒号:。/mnt/nfs:开发板上的挂载点。
挂载成功后,就可以自由地"穿梭"在两个系统之间了,下面是更具体的验证和操作方式。
如何验证 NFS 挂载成功?
挂载命令执行后,如果没有报错,通常就是成功了。可以按以下步骤测试:
-
在 Ubuntu 中创建文件 :进入 Ubuntu 的共享目录
nfs_share,新建一个测试文件。bashcd /home/book/nfs_share touch test.txt -
在开发板上查看 :在开发板的挂载点
/mnt/nfs下,你应该能立刻看到刚才创建的test.txt文件。bashls /mnt/nfs
你也可以反向操作:在开发板的 /mnt/nfs 目录下创建一个文件,然后去 Ubuntu 的 nfs_share 目录下查看,效果是一样的。
3、gcc流程
3.1流程

| 阶段 | 命令示例 | 产出 | 作用 |
|---|---|---|---|
| 预处理 | gcc -E main.c -o main.i |
.i 文件 |
展开宏、头文件 |
| 编译 | gcc -S main.i -o main.S |
.S 汇编文件 |
生成汇编代码 |
| 汇编 | gcc -c main.S -o main.o |
.o 目标文件 |
生成机器码(未链接) |
| 链接 | gcc -o test main.o sub.o |
可执行文件 | 合并 + 符号解析 + 重定位 |
3.2 链接器
链接 = 把多个
.o目标文件和库"拼"成一个完整的可执行文件
css
# 多文件直接链接(最简单)
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o # main.o + sub.o 直接合成 test
3.3 静态库 vs 动态库
| 特性 | 静态库 .a |
动态库 .so |
|---|---|---|
| 链接时机 | 链接期间 | 编译时记录依赖,运行时加载 |
| 是否复制代码 | 是,复制到可执行文件中 | 否,只记录需要哪个库 |
| 可执行文件大小 | 大 | 小 |
| 内存占用 | 每个程序各有一份拷贝 | 多程序共享同一份 .so 内存 |
| 库更新 | 需重新链接整个程序 | 替换 .so 文件即可(接口不变时) |
| 运行时依赖 | 无 | 必须能找到 .so 文件 |
| 适用场景 | 小项目、独立部署 | 多程序共用、节省存储/内存 |
3.3.1 静态库制作与使用
bash
# 1. 生成目标文件
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
# 2. 打包成静态库(ar = archive)
ar rcs libsub.a sub.o
# 3. 使用静态库链接
gcc -o test main.o -L. -lsub
# 或直接写文件名
gcc -o test main.o libsub.a
3.3.2 动态库制作与使用
bash
# 1. 生成目标文件(位置无关代码 -fPIC 通常推荐加)
gcc -c -fPIC -o main.o main.c
gcc -c -fPIC -o sub.o sub.c
# 2. 生成动态库(-shared)
gcc -shared -o libsub.so sub.o
# 3. 使用动态库链接
gcc -o test main.o -L. -lsub
# 4. 运行时让系统找到动态库
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./test
-lname 对应查找 libname.so(动态库)或 libname.a(静态库)
-l 参数 |
对应的库文件 |
|---|---|
-lsub |
libsub.so 或 libsub.a |
-lm |
libm.so(数学库) |
-lpthread |
libpthread.so(线程库) |
-lxxx |
libxxx.so 或 libxxx.a |
规律 :-l 后面跟的名字会被自动加上 lib 前缀和 .so/.a 后缀
3.4 链接时库的搜索顺序
3.4.1 编译时(链接器查找库)
-L指定的目录- 环境变量
LIBRARY_PATH - 系统默认目录(
/lib、/usr/lib、/usr/local/lib)
bash
gcc -o test main.o -lsub -L/home/book/mylibs -L.
3.4.2 运行时(动态链接器查找 .so)
- 环境变量
LD_LIBRARY_PATH - 配置文件
/etc/ld.so.conf中的目录 - 系统默认目录(
/lib、/usr/lib)
ruby
# 临时添加搜索路径
export LD_LIBRARY_PATH=$LD_LIBRASRY_PATH:/my/lib/path
# 永久添加(需要 root)
sudo sh -c "echo '/my/lib/path' > /etc/ld.so.conf.d/mylib.conf"
sudo ldconfig