banner
NEWS LETTER

嵌入式 Linux 系列 02:交叉编译、动态库和部署

Scroll down

嵌入式 Linux 开发绕不开交叉编译。开发机通常是 x86_64,目标板可能是 ARM、AArch64、MIPS 或 RISC-V。代码在开发机上编译,最终要在目标板上运行,这中间最容易出问题的是架构、动态链接器和依赖库。

一、确认目标架构

在板子上执行:

1
2
uname -m
cat /proc/cpuinfo

常见输出:

1
2
3
4
armv7l
aarch64
mips
riscv64

开发机上查看工具链:

1
2
arm-linux-gnueabihf-gcc -v
aarch64-linux-gnu-gcc -v

工具链前缀必须和目标架构、ABI、C 库匹配。

二、编译第一个程序

代码:

1
2
3
4
5
6
7
#include <stdio.h>

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

编译:

1
2
arm-linux-gnueabihf-gcc hello.c -o hello
file hello

传到板子:

1
2
scp hello root@192.168.1.100:/tmp/
ssh root@192.168.1.100 /tmp/hello

如果能打印内容,说明基本链路通了。

三、No such file or directory 不一定是文件不存在

嵌入式新手经常遇到:

1
./hello: No such file or directory

ls 明明能看到文件。这通常是动态链接器不存在。

检查:

1
readelf -l hello | grep interpreter

输出可能是:

1
[Requesting program interpreter: /lib/ld-linux-armhf.so.3]

再到板子上确认:

1
ls -l /lib/ld-linux-armhf.so.3

如果没有,要么换正确工具链,要么把对应运行库放进 rootfs。

四、动态链接和静态链接

动态链接:

1
arm-linux-gnueabihf-gcc hello.c -o hello

静态链接:

1
arm-linux-gnueabihf-gcc hello.c -static -o hello_static

静态链接部署简单,但文件大,部分库不适合静态链接。动态链接更常见,但要保证 rootfs 里有对应 .so

查看依赖:

1
readelf -d hello

或在目标板上:

1
ldd /tmp/hello

精简 rootfs 不一定带 ldd,这时优先用 readelf

五、Makefile 最小模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CROSS_COMPILE ?= arm-linux-gnueabihf-
CC := $(CROSS_COMPILE)gcc
CFLAGS := -Wall -Wextra -O2

TARGET := device_agent
SRCS := main.c config.c mqtt_client.c
OBJS := $(SRCS:.c=.o)

all: $(TARGET)

$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^

clean:
rm -f $(TARGET) $(OBJS)

编译:

1
make CROSS_COMPILE=arm-linux-gnueabihf-

这个模板足够支撑入门阶段的多文件项目。

六、部署策略

调试阶段:

1
2
scp device_agent root@192.168.1.100:/tmp/
ssh root@192.168.1.100 '/tmp/device_agent'

验证稳定后:

  • 放进 Buildroot package。
  • 或放入 rootfs overlay 的 /usr/bin
  • 配套启动脚本放到 /etc/init.d
  • 配置文件放到 /data/config

不要长期依赖手工 scp,否则重新烧录后环境无法复现。

七、排查清单

程序跑不起来时按顺序查:

1
2
3
4
5
file device_agent
readelf -h device_agent
readelf -l device_agent | grep interpreter
readelf -d device_agent
chmod +x device_agent

再看:

  • 架构是否匹配。
  • ABI 是否匹配。
  • 动态链接器是否存在。
  • .so 是否存在。
  • 程序是否有执行权限。
  • rootfs 是否缺少 /lib/usr/lib

交叉编译的重点不是记命令,而是能解释一个程序为什么能在目标板上运行。

其他文章
目录导航 置顶
  1. 1. 一、确认目标架构
  2. 2. 二、编译第一个程序
  3. 3. 三、No such file or directory 不一定是文件不存在
  4. 4. 四、动态链接和静态链接
  5. 5. 五、Makefile 最小模板
  6. 6. 六、部署策略
  7. 7. 七、排查清单
请输入关键词进行搜索