OpenWrt 制作软件包
软件包目录结构分析
如下图所示 :



一般软件包会下面几个文件
files目录:可选的,它一般用于保存默认配置文件和初始化启动脚本
patches目录:可选的,典型包含缺陷修改或者用于优化可执行程序大小的补丁文件
src目录:可选的,如果软件包是OpenWrt本身项目所包含的软件模块,因为代码将完全受到自己控制,这时将不会patches 目录存在,而是会有一个 src 目录,代码直接放在src目录下
Makefile文件:必须的,提供下载、编译、安装以及生成 OPKG 安装包的功能,这个文件是必须有的
软件包顶层Makefile分析
OpenWrt下的Makefile,与标准Linux的Makefile不同,OpenWrt没有遵守传统的Makefile格式风格,而是将Makefile写成面向对 象格式,这样就简化了多平台移植过程。下面分析一个系统自带的Makefile。
下面以lede/package/network/utils/iwinfo为例说明:
#
# Copyright (C) 2010-2016 Jo-Philipp Wich <jo@mein.io>
#
# This is free software, licensed under the GPL 2 license.
#
# 软件包makefile尽量隐藏和系统相关的东西,所以这里关于系统的一些东西基本在rules.mk中
include $(TOPDIR)/rules.mk
# 定义 软件包名字 libiwinfo 版本3
PKG_NAME:=libiwinfo
PKG_RELEASE:=3
# 下载方式git
# 下载地址为 $(PROJECT_GIT)/project/iwinfo.git
# 还有hash值 协议等等
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/iwinfo.git
PKG_SOURCE_DATE:=2021-06-28
PKG_SOURCE_VERSION:=c9b1672f5a83c8dcb14fdbaee651f775a7defe52
PKG_MIRROR_HASH:=f33779035153da6bd0b2f100f402f62f1554ab87ed6fbbd938d41df6b9947a1f
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=GPL-2.0
PKG_FLAGS := nonshared
# 定义变量 编译时候的依赖的模块
PKG_CONFIG_DEPENDS := \
CONFIG_PACKAGE_kmod-brcm-wl \
CONFIG_PACKAGE_kmod-brcm-wl-mini \
CONFIG_PACKAGE_kmod-brcm-wl-mimo \
CONFIG_PACKAGE_kmod-mt7615d_dbdc \
CONFIG_PACKAGE_kmod-cfg80211
IWINFO_ABI_VERSION:=20210430
# 注意:上面变量定义完后再包含 package.mk 不要问为什么,模块规则 否则编译可能会出现很多问题
include $(INCLUDE_DIR)/package.mk
# 第一个软件包libiwinfo宏定义
define Package/libiwinfo
SECTION:=libs # 说明是个库
CATEGORY:=Libraries
TITLE:=Generalized Wireless Information Library (iwinfo)
DEPENDS:=+PACKAGE_kmod-cfg80211:libnl-tiny +libuci +libubus
ABI_VERSION:=$(IWINFO_ABI_VERSION)
endef
# 一些简单描述
define Package/libiwinfo/description
Wireless information library with consistent interface for proprietary Broadcom,
nl80211 and wext driver interfaces.
endef
# 第二个软件包libiwinfo-lua宏定义
define Package/libiwinfo-lua
SUBMENU:=Lua # 存放目录
SECTION:=lang
CATEGORY:=Languages
TITLE:=libiwinfo Lua binding
DEPENDS:=+libiwinfo +liblua # 依赖
endef
# 一些简单描述
define Package/libiwinfo-lua/description
This is the Lua binding for the iwinfo library. It provides access to all enabled
backends.
endef
# 第三个个软件包iwinfo宏定义
define Package/iwinfo
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Generalized Wireless Information utility
DEPENDS:=+libiwinfo
endef
#一些简单的描述
define Package/iwinfo/description
Command line frontend for the wireless information library.
endef
# 编译前的配置,这里为空
define Build/Configure
endef
# 编译参数相关 不过多介绍
IWINFO_BACKENDS := \
$(if $(CONFIG_PACKAGE_kmod-brcm-wl),wl) \
$(if $(CONFIG_PACKAGE_kmod-brcm-wl-mini),wl) \
$(if $(CONFIG_PACKAGE_kmod-brcm-wl-mimo),wl) \
$(if $(CONFIG_PACKAGE_kmod-mt7615d_dbdc),ra) \
$(if $(CONFIG_PACKAGE_kmod-cfg80211),nl80211)
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include/libnl-tiny \
-I$(STAGING_DIR)/usr/include \
-D_GNU_SOURCE
MAKE_FLAGS += \
FPIC="$(FPIC)" \
CFLAGS="$(TARGET_CFLAGS)" \
LDFLAGS="$(TARGET_LDFLAGS)" \
BACKENDS="$(IWINFO_BACKENDS)" \
SOVERSION="$(IWINFO_ABI_VERSION)"
# 定义编译完成后操作的宏 可以看到会把头文件 so文件拷贝到安装目录下
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include/iwinfo
$(CP) $(PKG_BUILD_DIR)/include/iwinfo.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/include/iwinfo/* $(1)/usr/include/iwinfo/
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_BUILD_DIR)/libiwinfo.so* $(1)/usr/lib/
$(INSTALL_DIR) $(1)/usr/lib/lua
$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo.so $(1)/usr/lib/lua/iwinfo.so
endef
# 定义第一个软件包libiwinfo 安装时候执行的操作的宏
define Package/libiwinfo/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_BIN) $(PKG_BUILD_DIR)/libiwinfo.so.$(IWINFO_ABI_VERSION) $(1)/usr/lib/libiwinfo.so.$(IWINFO_ABI_VERSION)
$(INSTALL_DIR) $(1)/usr/share/libiwinfo
$(INSTALL_DATA) $(PKG_BUILD_DIR)/hardware.txt $(1)/usr/share/libiwinfo/hardware.txt
endef
# 定义第二个软件包libiwinfo-lua 安装时候执行的操作的宏
define Package/libiwinfo-lua/install
$(INSTALL_DIR) $(1)/usr/lib/lua
$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo.so $(1)/usr/lib/lua/iwinfo.so
endef
# 定义第三个软件包iwinfo 安装时候执行的操作的宏
define Package/iwinfo/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo $(1)/usr/bin/iwinfo
endef
# 调用BuildPackage 编译三个软件包 libiwinfo ibiwinfo-lua iwinfo
$(eval $(call BuildPackage,libiwinfo))
$(eval $(call BuildPackage,libiwinfo-lua))
$(eval $(call BuildPackage,iwinfo))
OpenWrt一些常用的变量
一些默认的变量
INCLUDE_DIR:源代码目录下的 include 目录BUILD_DIR:代码编译的根目录,通常为build_dir/target-*目录TARGET_CFLAGS:指定目标平台的 C 语言编译选项TARGET_LDFLAGS:指定目标平台的编译链接选项INSTALL_DIR:创建目录,并设置目录权限INSTALL_DATA:安装数据文件,即复制并设置权限为 0644INSTALL_CONF:安装配置文件,即复制并设置权限为 0600INSTALL_BIN:安装可执行程序,即复制并增加执行权限,设置权限表示为 0777
变量 |
含义 |
示例 |
|---|---|---|
PKG_NAME |
软件包的名称,可以通过 menuconfig 和 ipkg 查看到 |
PKG_NAME:=libiwinfo |
PKG_VERSION |
上游软件的版本号,为 2.73 |
2.73 |
PKG_RELEASE |
Makefile 的版本号 |
PKG_RELEASE:=3 |
PKG_SOURCE |
原始的源代码文件名 |
|
PKG_SOURCE_URL |
用于下载源码的地址 |
$(PROJECT_GIT)/project/iwinfo.git |
PKG_MD5SUM |
软件包的 MD5 值,用于验证下载的文件 是否正确 |
|
PKG_LICENSE |
这个软件的许可协议,开源软件的许可证 以 GPL 家族最多 |
|
PKG_LICENSE_FILES |
许可协议文件,是指代码目录下的文件名, 一般均为 COPYING |
|
PKG_BUILD_DIR |
软件包的编译目录(就是编译过程中的临时目录build_dir |
|
PKG_INSTALL |
设置为 1 将调用软件包自己的“make install”,安装目录前缀为 PKG_INSTALL_ DIR |
|
PKG_BUILD_PARALLEL |
是否可以并行编译 |
|
PKG_CONFIG_DEPENDS |
编译依赖,指定哪些选项依赖本软件包 |
|
PKG_INSTALL_DIR |
当调用原始软件包“make install”时的安 装目录 |
|
PKG_SOURCE_PROTO |
用于下载的传输协议(git、svn),如果为 压缩包则不用指定 |
|
PKG_SOURCE_SUBDIR |
下载目录,如果下载传输协议为“svn”或 “git”时必须指定。例如:”PKG_SOURCE_ SUBDIR:=$(PKG_NAME)-$(PKG_VERSI ON)” |
|
PKG_SOURCE_VERSION |
下载协议为git时必须指定,指定的提 交哈希点将会被检出 |
|
PKG_MAINTAINER |
维护者的姓名和邮件地址 |
|
PKG_BUILD_DEPENDS |
软件包编译依赖,即在这个包编译之前编 译,但是在运行时不需要,和 DEPENDS 有相同的语法 |
Package宏定义
可以将一个源代码包分割为多个安装包。 如下面所示
# 第一个软件包libiwinfo宏定义
define Package/libiwinfo
SECTION:=libs # 说明是个库
CATEGORY:=Libraries
TITLE:=Generalized Wireless Information Library (iwinfo)
DEPENDS:=+PACKAGE_kmod-cfg80211:libnl-tiny +libuci +libubus
ABI_VERSION:=$(IWINFO_ABI_VERSION)
endef
# 第二个软件包libiwinfo-lua宏定义
define Package/libiwinfo-lua
SUBMENU:=Lua # 存放目录
SECTION:=lang
CATEGORY:=Languages
TITLE:=libiwinfo Lua binding
DEPENDS:=+libiwinfo +liblua # 依赖
endef
# 第三个个软件包iwinfo宏定义
define Package/iwinfo
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Generalized Wireless Information utility
DEPENDS:=+libiwinfo
endef
安装包选项 |
是否必需 |
含 义 |
|---|---|---|
Package/<软件包名称> |
是 |
定义软件包的描述信息:例如 |
Package/<软件包名>/Default |
可选 |
软件包的默认选项 |
Package/<软件包名>/description |
是 |
软件包的详细描述 |
Package/<软件包名>/install |
是 |
复制文件到 ipkg 目录中, |
Package/<软件包名>/config |
可选 |
根据软件包的选择对编译选项进行定义 |
Package/<软件包名>/conffiles |
可选 |
定义本软件包的运行配置文件列表,一行一个文件 |
Package/<软件包名>/preinst |
可选 |
这是在安装之前实际执行的脚本,不要忘了包含#!/bin/sh。 |
Package/<软件包名>/postinst |
可选 |
在安装完成后执行的脚本,例如启动程序。不要忘了包含 #!/bin/sh |
Package/<软件包名>/prerm |
可选 |
在删除之前执行的脚本,例如停止程序的执行。不要忘了包含 #!/bin/sh。如果需要中止删除就返回 false |
Package/<软件包名>/postrm |
可选 |
在删除之后执行的脚本,不要忘了包含#!/bin/sh。 |
这里面的一些常变量说明
SECTION: 软件包的类型,如 Lua、libs、Utilities 或 Multimedia等CATEGORY: 在make menuconfig中显示到菜单分类中TITLE: 标题,是软件包的简短描述URL: 软件包的原始网站地址,可以在这里找到该软件MAINTAINER: 维护者的姓名和邮件地址。一般为这个软件包作者的邮件地址DEPENDS: (可选)依赖项,需要在本软件包之前编译和安装的软件包
Build宏定义
比如上面介绍的代碼
# 定义编译完成后操作的宏 可以看到会把头文件 so文件拷贝到安装目录下
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include/iwinfo
$(CP) $(PKG_BUILD_DIR)/include/iwinfo.h $(1)/usr/include/
$(CP) $(PKG_BUILD_DIR)/include/iwinfo/* $(1)/usr/include/iwinfo/
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_BUILD_DIR)/libiwinfo.so* $(1)/usr/lib/
$(INSTALL_DIR) $(1)/usr/lib/lua
$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo.so $(1)/usr/lib/lua/iwinfo.so
endef
一些常用的Build宏定义 安装执行的顺序介绍如下:
Build/Prepare可选
一组用于解压缩及打补丁的命令,也可以不使用
Build/Configure可选
如果源代码不需要configure来生成Makefile或者是通用的configure脚本, 就不需要这部分。
否则就需要你自己的命令脚本或者使用
$(call Build/Configure/Default, FOO=bar)增加额外的参数传递给 configure 脚本
Build/Compile可选
编译源代码,在大多数情况下应该不用定义而使用默认值。如果你想传递给 make 特定的参数,可以使用
$(call Build/Compile/Default, FOO=bar)
Build/Install可选
安装编译后的文件,默认是调用 make install,如果需要传递指定的参 数,使用
$(call Build/Install/Default,install install-foo)。注意你需要传递所有的参数,要增加在“install”参数后面,不要忘了“install”参数
Build/InstallDev可选
例如静态库和头文件等,但是不需要在目标设备上使用
构建自己的软件系统
程序实现的功能如下:
实现一个在路由器启动后访问指定网站的功能,这样就可以统计路由器的启动次数。
网站地址可以在配置文件中进行自定义配置,网址通过UCI编程接口读取配置文件来实现。
访问指定网站功能通过命令行工具wget来实现。但如果其他人也使用wget来访问服务器,这样就不能区分是路由器行为还是其他应用软件的行为,因此我们修改了代理字符串来作为我们的自定义字符串(使用wget的–user-agent参数,参数如何使用见wget文章),这样就可以和默认的访问行为区分开来。
为了防止某些小区在断电并自动启动后,全部一起立即访问服务器,对服务器产生瞬间流量冲击,因此路由器启动后产生一个随机延迟时间,然后再访问服务器。这个时间可以通过配置文件设置,假如设置为100秒,则访问服务器时间就为1~100秒的随机值。
软件包工程目录
files目录包含配置文件和初始化脚本
files目录下的hello.conf为配置文件,在安装后放在/etc/config/目录下的 hello 文件夹中
files目录下hello.init用于控制进程启动的初始化脚本
Makefile包含编译及安装指令,控制着代码在 OpenWrt 环境下的编译和生成安装包。
src目录保存C语言源代码和一个hello.c文件的Makefile。
src目录下的hello.c为上面的程序C语言代码。
src目录下Makefile为hello.c的Makefile。

文件内容分析
编译
配置
# M 代表模块 会生成.ipk文件 y在系统编译的时候会自动安装 如下图:我们这里选择M make menuconfig

编译
make package/hello/compile V=s
查看编译生成的文件
安装
opkg install .ipk
安裝后可以看到在/usr/sbin/hello目录下会有这个程序
配置文件在/etc/config目录下,开机自启动的程序在/etc/init.d目录下(Makefile脚本设计的)
在/etc.rc.d目录下也创建了我们的开机自启动脚本的软链接
样之后我们的软件就可以开机自启动了
卸载