OpenWrt软件包制作

OpenWrt软件包制作

OPKG概述

OPKG(Open/OpenWrt Package)是一个轻量快速的软件包管理系统,是 IPKG 的克隆,目前已成为开源嵌入式系统领域的事实标准。OPKG 常用于路由、交换机等嵌入式设备中,用来管理软件包的下载、安装、升级、卸载和查询等,并处理软件包的依赖关系。功能和桌面 Linux 操作系统Ubuntu 中的 apt-get、Redhat 中的 yum 类似。

OPKG 是一个针对根文件系统全功能的软件包管理器。它不仅仅是在独立的目录安装软件,还可以用于安装内核模块和驱动等。OPKG 在安装时会自动解决安装软件时的包依赖关系,如果遇见错误,就中止安装。

软件包制作依赖于 Openwrt Buildroot 系统,下面简单介绍一下其目录结构,其工作过程(交叉工具链下载,内核镜像、根文件系统等配置及制作)不在本文描述。

Openwrt Buildroot 目录

Openwrt Buildroot 是一个集合了 Makefile,patches 和 scripts 的一个系统构建环境。它能制作交叉编译工具链,下载 Linux 内核,制作根文件系统,管理第三方软件包。开发人员可以使用它来编译出自定义的固件 image 来支持自己的硬件设备。在 Openwrt Buildroot 源码树中没有任何 Linux 内核和第三方源码包。这些 Makefile 决定下载哪个版本的 Linux 内核以及哪个版本的源码包来编译固件。下图是表示了 Openwrt Buildroot 源码树组织结构

第一行目录是 Openwrt Buildroot 源码树原始的目录,第二行是编译过程中产生的。

  • tools:包含了一些 Makefile。编译固件需要一些命令,比如 mkimage、lzma 等,而这些 Makefile 则定义了如何获得这些命令的源码包,以及如何编译/安装这些命令。
  • toolchain:包含了一些 Makefile。这些 Makefile 定义了如何获得 kernel headers, C library, bin-utils,compiler, debugger 以及如何编译/安装它们。这些源码是用来制作交叉编译工具链的。如果你要添加一个全新的架构,你需要在这里添加一个配置。
  • target:各个硬件平台在这里面定义了编译固件和内核的步骤、方法。
  • package:包含了一些针对各个软件包的 Makefile 以及补丁。这些 Makefile 定义了如何获取这些软件包以及如何编译/安装。
  • include:存放了一些公用的 Makefile,这些 Makefile 会被其它 Makefile 包含。
  • scripts:一些用于 Openwrt 软件包管理的 perl 脚本。
  • dl:存放从网上下载的用户空间软件包的源码包
  • build_dir:所有软件包都解压到该目录,并在该目录下编译。
  • staging_dir:最终安装目录,包括运行在主机的工具、交叉编译工具链、嵌入式根文件系统 rootfs
  • bin:编译完成后,最终生成的固件 image 以及软件包的 ipk 文件都会放在这里。

软件包基本都包含有启动脚本,下面对 openwrt 启动脚本进行介绍。

启动脚本

init script

启动脚本存放在/etc/init.d 目录,创建一个示例启动脚本/etc/init.d/example,如下所示:

#!/bin/sh /etc/rc.common
START=10
STOP=15
start() {
	echo 'start example'
}
stop() {
	echo 'stop example'
}

然后给/etc/init.d/example 添加可执行权限

chmod a+x /etc/init.d/example start
# 执行 example
/etc/init.d/example start

可以看到,跟参数 start 时,程序执行了 start 函数,跟参数 stop 时,程序执行了 stop 函数,跟参数 restart 时,程序先执行 stop 函数,再执行 start 函数。
其实,在/etc/rc.common 中已经定义了所有默认的函数,当我们没有重新实现这些函数时,程序会执行/etc/rc.common中的默认函数,比如在这个 example 中,我们没有定义 restart 函数,我们跟参数 restart 时,程序执行/etc/rc.common中的 restart 函数,该函数首先调用 stop 函数,再调用 start 函数。而一旦我们重新实现了这些函数,在执行时,程序就会调用我们自己实现的函数。

脚本中的 START= 和 STOP= 分别决定了该脚本会在系统启动过程和系统关机过程的哪个点执行,数字越小越先执行。

当我们以 enable 参数调用启动脚本时,系统会创建一个该脚本文件的符号链接(例如 S10example、K15example),放在/etc/rc.d/目录下,而当以 disable 参数调用脚本时,系统会删除该符号链接。

  • START=10:意味着该脚本文件会被/etc/rc.d/S10example 链接。也就是说,该脚本会在 START=10 及之下这样的脚本后面执行,而在 START=11 及之上这样的脚本前面执行。
  • STOP=15:意味着该脚本文件会被/etc/rc.d/K15example 链接。也就是说,该脚本会在 STOP=14 及之下这样的脚本后面执行,而在 STOP=16 及之上这样的脚本前面执行。

添加自己的命令

#!/bin/sh /etc/rc.common
START=10
STOP=15
EXTRA_COMMANDS="custom"
EXTRA_HELP=" custom Help for the custom command"
start() {
	echo 'start example'
}
stop() {
	echo 'stop example'
}
custom() {
	echo 'custom command'
}

procd init script

procd 是 Openwrt 提供的一个进程管理工具。示例如下:

#!/bin/sh /etc/rc.common
START=50
USE_PROCD=1
PROG=/bin/helloworld
start_service() {
	procd_open_instance
	procd_set_param command $PROG -v ./web/ 8888
	procd_set_param respawn 5 1 -1
	procd_close_instance
}

这是一个最简单的 procd 形式的启动脚本。USE_PROCD=1 指明使用 procd。

如果定义了 USE_PROCD 变量,对 start、stop 和 reload函数进行重新定义,在调用这些函数时,将调用 start_service、stop_service 和 reload_service函数等。

(1)procd_open_instance 开始增加一个服务实例。

(2)procd_set_param 设置服务实例的参数值,通常会有以下几种类型的参数。

  • command: 服务的启动命令行。
  • respawn: 进程意外退出的重启机制及策略,它需要有 3 个设置值。第一个设置为判断异常失败边界值(threshold),默认为 3600 秒,如果小于这个时间退出,则会累加重新启动次数,如果大于这个临界值,则将重启次数置 0。第二个设置为重启延迟时间(timeout),将在多少秒后启动进程,默认为 5 秒。第三个设置是总的失败重启次数(retry),是进程永久退出之前的重新启动次数,超过这个次数进程退出之后将不会再启动。默认为 5 次。也可以不带任何设置,那这些设置都是默认值。
  • env:进程的环境变量。
  • file:配置文件名,比较其文件内容是否改变。
  • netdev:绑定的网络设备(探测 ifindex 更改)。
  • limits:进程资源限制。

(3)procd_close_instance 完成进程实例的增加。

(4)procd_add_reload_trigger,增加配置文件触发器,每次配置文件的修改,如果调用了 reload_config 时,当前实例都被重启。有一个可选的参数为配置文件名称。其实它在内部是调用 procd_open_trigger、procd_add_config_trigger 和 procd_close_trigger 这 3 个函数来增加触发器。

更多用法参考 Openwrt 官方文档:http://wiki.openwrt.org/inbox/procd-init-scripts

添加OPKG包

加入软件包需要在 package 目录下创建一个目录,以包含该软件包的各种信息和与 OpenWrt 建立联系的文件。然后创建一个Makefile 与 OpenWrt 建立联系,Makefile 需要遵循 OpenWrt 的约定。下面以智能网关应用软件包制作为例。

由于网关的程序其配置、依赖、脚本等均自行管理,故其 Makefile 定制如下。

网关Makefile示例

在 SDK pakege目录下新建 gateway目录,其Makefile 如下所示:

include $(TOPDIR)/rules.mk

# 软件包的基本信息
PKG_NAME:=gateway
PKG_VERSION:=2.14
PKG_RELEASE:=1

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
PROJECT_DIR := /home/wanghuan/workspace/gateway-all/Gateway_YZS

include $(INCLUDE_DIR)/package.mk

# 应用程序编译包定义
define Package/$(PKG_NAME)
	ECTION:=base
	CATEGORY:=Base system
	# DEPENDS:= +libavcodec +libavdevice
	TITLE:=smart gateway app
endef

define Package/$(PKG_NAME)/extra_provides
	echo "libavcodec.so.58"; \
	echo "libavdevice.so.58"; \
	echo "libavfilter.so.7"; \
	echo "libavformat.so.58"; \
	echo "libavutil.so.56"; \
	echo "libcrypto.so.3"; \
	echo "libcurl.so.4"; \
	echo "libevent-2.1.so.6"; \
	echo "libglib-2.0.so.0"; \
	echo "libgo.so"; \
	echo "libgsoap_onvif.so"; \
	echo "libgthread-2.0.so.0"; \
	echo "libiconv.so.2"; \
	echo "libmosquitto.so.1"; \
	echo "libsqlite3.so.0"; \
	echo "libssl.so.3"; \
	echo "libswresample.so.3"; \
	echo "libswscale.so.5"; \
	echo "libuci.so"; \
	echo "libuuid.so.1"; \
	echo "libwebsockets.so.15"; \
	echo "libz.so.1";
endef

# 软件包配置文件
define Package/$(PKG_NAME)/conffiles
endef

# 软件包的详细描述
define Package/$(PKG_NAME)/description
endef

# 编译准备
define Build/Prepare
	mkdir -p $(PKG_BUILD_DIR)
	$(CP) $(PROJECT_DIR)/* $(PKG_BUILD_DIR)/
endef

define Build/Configure
endef

# TARGET_LDFLAGS :=

# 编译
define Build/Compile
	$(MAKE) -C $(PKG_BUILD_DIR) \
		LIBS="$(TARGET_LDFLAGS)"
endef

# 软件包安装前执行脚本
define Package/$(PKG_NAME)/preinst
endef

# 软件包安装后执行脚本
define Package/$(PKG_NAME)/postinst
#!/bin/sh
# check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then
        echo "Enabling rc.d symlink for gateway"
        chmod +x /etc/init.d/gateway_server
        /etc/init.d/gateway_server enable
fi
exit 0
endef

# 软件包删除前执行脚本
define Package/$(PKG_NAME)/prerm
#!/bin/sh
# check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then
        echo "Removing rc.d symlink for gateway"
        /etc/init.d/gateway_server disable
fi
exit 0
endef

# 软件包删除后执行脚本
define Package/$(PKG_NAME)/postrm
endef

# 安装
define Package/$(PKG_NAME)/install
	$(INSTALL_DIR) $(1)/root/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/$(PKG_NAME) $(1)/root/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/daemon $(1)/root/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/ha $(1)/root/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/jiankong.sh $(1)/root/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/start.sh $(1)/root/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/stop.sh $(1)/root/bin
	$(INSTALL_DATA) $(PKG_BUILD_DIR)/bin/gateway.db $(1)/root/bin
	$(INSTALL_DATA) $(PKG_BUILD_DIR)/bin/zlog.conf $(1)/root/bin

	$(INSTALL_DIR) $(1)/etc/init.d
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/server/gateway_server $(1)/etc/init.d/gateway_server

	$(INSTALL_DIR) $(1)/root/bin/date
	$(CP) $(PKG_BUILD_DIR)/bin/date/* $(1)/root/bin/date

	$(INSTALL_DIR) $(1)/root/bin/goahead
	$(INSTALL_DIR) $(1)/root/bin/goahead/web
	$(CP) $(PKG_BUILD_DIR)/bin/goahead/web/* $(1)/root/bin/goahead/web
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/goahead/goahead $(1)/root/bin/goahead
	$(INSTALL_DATA) $(PKG_BUILD_DIR)/bin/goahead/auth.txt $(1)/root/bin/goahead
	$(INSTALL_DATA) $(PKG_BUILD_DIR)/bin/goahead/route.txt $(1)/root/bin/goahead
	$(INSTALL_DATA) $(PKG_BUILD_DIR)/bin/goahead/self.crt $(1)/root/bin/goahead
	$(INSTALL_DATA) $(PKG_BUILD_DIR)/bin/goahead/self.key $(1)/root/bin/goahead

	$(INSTALL_DIR) $(1)/root/bin/json
	$(CP) $(PKG_BUILD_DIR)/bin/json/* $(1)/root/bin/json

	$(INSTALL_DIR) $(1)/root/bin/lib
	$(CP) $(PKG_BUILD_DIR)/bin/lib/* $(1)/root/bin/lib
endef

$(eval $(call BuildPackage,$(PKG_NAME)))

然后在 sdk 根目录执行

make package/gateway/compile

软件包安装

安装包可以通过 web 界面安装

也可手动考入安装。手动拷入后执行如下安装命令:

opkg install gateway_2.14-1_aarch64_generic.ipk
posted @ 2025-06-20 11:09  silencehuan  阅读(165)  评论(0)    收藏  举报