嵌入式 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 工作站传送文件。
posted @ 2023-01-16 15:04  KevinAshton  阅读(317)  评论(0编辑  收藏  举报