嵌入式 Linux 开发 7:编译应用程序
简介 Linux 应用程序
从用户的角度来看,一台 Linux 产品的价值在于设备上运行的应用程序所能解决的问题。
而 Linux 得到广泛使用的一个原因是有很多开源的应用程序。
编译与部署应用程序的流程
交叉编译的 Makefile
如下所示,设计合理的 Makefile 通过执行以下 3 个命令即可调用交叉编译器:编译,清理和安装应用程序。
- 编译
make
- 清理
make clean
- 安装
make install
CROSS = arm-linux-
CC = $(CROSS)gcc
STRIP = $(CROSS)strip
PPPD_PATH = ./ppp-2.4.5
PPPD_EXEC = $(PPPD_PATH)/pppd
all:$(PPPD_EXEC)
.PHONY:$(PPPD_EXEC)
$(PPPD_EXEC):
$(MAKE) -C $(PPPD_PATH) CC=$(CC) all
clean:
make -C $(PPPD_PATH) clean
INSTALL_DIR=<install_directory>
install:$(PPPD_EXEC) ./options
$(STRIP) $(PPPD_EXEC)
sudo cp -f $^ ${INSTALL_DIR}
依赖库
程序库预定的位置是 /lib 如果将其放置在其他目录,这需要设定查找路径,即配置 LD_LIBRARY_PATH 环境变量。
这会迫使动态链接器到 LD_LIBRARY_PATH 指向的目录查找程序库。如同 PATH 环境变量,可以用冒号(:)隔开每个目录路径。
小窍门:
在 Linux 工作站或服务器,通常只会使用 LD_LIBRARY_PATH 暂存新程序库路径。
要永久加入一个程序库路径,这得修改 /etc/ld.so.conf 配置文件,接着使用 ldconfig 命令产生 /etc/ld.so.cache
动态链接器会依照 /etc/ld.so.cache 文件的指示找到应用程序所动态链接的程序库。
关联文件
关联文件依赖应用程序自身,一般包括:配置和日志文件。
一个良好的习惯是将关联文件写入 Makefile 的 install 目标,实现一键安装。
上电自启动
将应用程序的全路径写入 inittab 的 respawn 选项就可以实现上电自启动,参考下面的【配置 init】
BusyBox 嵌入式 Linux 命令行工具集
BusyBox 是什么
BusyBox 实现嵌入式 Linux 的命令行工具,相当于 Ubuntu/CentOS 的 Shell
它非常小巧,功能强大,易于编译和部署,是嵌入式 Linux 必不可少的基础软件。
鉴于它的广泛使用,一些社区人员称嵌入式 Linux 为 BusyBox/Linux
下载 BusyBox
一般说来 CPU 厂商会提供 BusyBox 软件包,很可能它已经落后很多年了,这会包含一些没有修复的缺陷。
目前 BusyBox 最新稳定版本是 19 May 2023 -- BusyBox 1.36.1 (stable) 下载链接为 https://busybox.net/downloads/
配置 BusyBox
如果图省事,执行 make defconfig
使用默认配置就足够了。
需要精细化定制 BusyBox 执行 make menuconfig
按菜单选择需要的功能。
编译 BusyBox
编译新版本的 BusyBox 几乎都会遇到工具链不兼容的错误。
比如 seedrng.c 它依赖 <sys/random.h> ,而低版本的 gcc 没有该头文件。
一个简单的办法是【取消】 seedrng 程序 -- 除非你确定要使用它!
从 BusyBox 取消 seedrng 至少有 2 种办法。
办法一:执行 make menuconfig
查找 seedrng 取消该程序
办法二:执行 make defconfig
调用下面 sed 取消 seedrng
sed -i 's/CONFIG_SEEDRNG=y/# CONFIG_SEEDRNG is not set/g' .config # seedrng.c:<sys/random.h> is lack!
先建立 ../busybox_install 用于存储 BusyBox 生成的二进制执行文件和链接符号。
下面的命令会编译 BusyBox 并安装二进制执行文件和链接符号到指定目录(此处是 ../busybox_install)
make ARCH=arm CROSS_COMPILE=arm-nuvoton-linux-uclibceabi- CONFIG_PREFIX=../busybox_install/ install
部署 BusyBox
查询 BusyBox 链接库
下面的命令会查找 BusyBox 依赖的动态链接库,本例中它依赖 3 个库(libm=数学库,libc=C库,ld=加载库)
请确保目标板 Linux 系统有这 3 个库文件(一般存放在 /lib),否则,BusyBox 无法正常运行。
arm-nuvoton-linux-uclibceabi-ldd busybox_install/bin/busybox
checking sub-depends for 'not found'
checking sub-depends for 'not found'
libm.so.0 => not found (0x00000000)
libc.so.0 => not found (0x00000000)
/lib/ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x00000000)
拷贝 BusyBox 到根文件系统
将 busybox_install 下的 4 个目录和文件:bin/ linuxrc sbin/ usr/ 复制到 rootfs 之下。
执行 chown root:root busybox
赋予 root 所有者,执行 chmod a+s busybox
设置 setuid 权限。
重启目标板 Linux 就可以运行新 BusyBox 了(运行 busybox --list 查看支持命令集)。
配置 init
表1 busybox init 所识得的 inittab 动作类型
动作 | 结果 |
---|---|
sysinit | 为 init 提供初始化命令脚本的路径 |
respawn | 每当相应的进程终止运行,便予以重新启动 |
shutdown | 关闭系统之前,执行相应的进程 |
restart | 当 init 重新启动时,执行相应的进程(通常指 init 本身) |
表2 busybox 使用 inittab 实例
语句 | 用途 |
---|---|
::sysinit:/etc/init.d/rcS | 将 /etc/init.d/rcS 设成系统的初始化文件 |
::respawn:/sbin/getty 115200 ttyS0 | 在串口 ttyS0 以 115200 波特率启动一个登录会话 |
::respawn:/<application_path>/exec_name | 启动应用程序 |
::restart:/sbin/init | 如果 init 重启,将 /sbin/init 设定成所要执行的程序 |
::shutdown:/bin/umount -a -r | 关机时卸载所有文件系统,卸载失败以只读模式重新挂载 |
Dropbear 嵌入式 Linux 的 ssh
为了更好地维护产品,这需要添加 Linux 网络通道。相比 Telnet 孱弱的安全性,ssh 使用公钥加密法,以确保端对端通信的机密性,并且相当容易使用以及部署。
Dropbear 是什么
工作站 Linux 大多使用 OpenSSH,它依赖独立的 OpenSSL 链接库。它有 2 个弊端:交叉编译困难重重,所产生的二进制文件超过 1MB。
幸运的是,有一个供嵌入式系统使用的开放源码 SSH 服务器+客户端,它就是 Dropbear。
下载 Dropbear
wget https://matt.ucc.asn.au/dropbear/dropbear-2022.83.tar.bz2
tar jxvf ./dropbear-2022.83.tar.bz2
编译 Dropbear
CROSS = arm-nuvoton-linux-uclibceabi-
CC = $(CROSS)gcc
STRIP = $(CROSS)strip
STRIP=${STRIP} CC=${CC} ./configure --host=${TARGET}
make PROGRAMS="dropbear dropbearkey scp dbclient" MULTI=1 strip
部署 Dropbear
复制 Dropbear 到根文件系统
cp -f dropbearmulti ${PRJROOT}/rootfs/usr/sbin/dropbear
ln -s ../sbin/dropbear ${PRJROOT}/rootfs/usr/bin/dropbearkey
ln -s ../sbin/dropbear ${PRJROOT}/rootfs/usr/bin/scp
ln -s ../sbin/dropbear ${PRJROOT}/rootfs/usr/bin/dbclient
ln -s ../sbin/dropbear ${PRJROOT}/rootfs/usr/bin/ssh
生成每台机器唯一的 RSA 和 DSS 密钥
RSA_KEY=/opt/dropbear_rsa_host_key
DSS_KEY=/opt/dropbear_dss_host_key
if [ ! -f $RSA_KEY ]; then
/usr/bin/dropbearkey -t rsa -f $RSA_KEY
fi
if [ ! -f $DSS_KEY ]; then
/usr/bin/dropbearkey -t dss -f $DSS_KEY
fi
小窍门1:此处的 /opt 是 writeable 分区
小窍门2:上述命令在第一次生成密钥时耗时比较多,小心它耽误了其他重要进程的调度(如:喂看门狗)。
上电自启动 Dropbear
添加下面的语句到 /etc/inittab 便可在引导的时候启动 dropbear。
::respawn:/usr/sbin/dropbear -r /opt/dropbear_rsa_host_key -d /opt/dropbear_dss_host_key
测试 Dropbear
- 基于 Linux 工作站通过 ssh 登录嵌入式 Linux 系统。
- 基于 嵌入式 Linux 系统通过 ssh 登录 Linux 工作站。
- 基于 Linux 工作站通过 scp 从嵌入式 Linux 传送文件。
- 基于嵌入式 Linux 通过 scp 从 Linux 工作站传送文件。