Openwrt有一套自己管理软件包的方法,可以用来管理数千个软件包与数十个硬件平台,我们也可以使用这套管理方法将我们的软件加入到Openwrt系统中。
文件结构
下面的文件结构是dns软件包的结构,该软件包存放在 openwrt/package/network/services目录下,这个软件包下存在两个文件夹跟一个Makefile文件。
dnsmasq/
├── Makefile
├── files
└── patches
- Makefile:这个文件是必须有的,该文件的提供下载、编译、安装以及生成OPKG安装包的功能。这个Makefile与通常Makefile不同,Openwrt没有遵守传统的Makefile格式风格,而是将Makefile写成面向对象的格式,这样简化了多平台移植过程。
- files:这个目录是可选的,一般用于保存默认配置文件与初始化启动脚本
- patches:这个目录是可选的,一般用于存放缺陷修改或者用于优化可执行程序大小的补丁文件。如果为Openwrt本身项目所包含的软件模块,因为代码将完全收到自己控制,这时将不会有patches而是一个src目录,用于存放代码。
Makefile解析
这个是dnsmasq软件包的Makefile,这个Makefile的语法与传统的Makefile不一样。
这个Makefile大概过程就是:
- 使用“include”指示符导入顶层目录的rules.mk文件;
- 定义软件包的基本信息的变量,如名称、版本、下载地址、许可协议和编译目录等信息;
- 使用“include”指示符导入顶层目录的package.mk文件;
- 软件包的宏定义和一些编译选项定义;
- 最后调用BuildPackage。
#
# Copyright (C) 2006-2016 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=dnsmasq
PKG_UPSTREAM_VERSION:=2.86
PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION)))
PKG_RELEASE:=$(AUTORELEASE)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz
PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
PKG_HASH:=28d52cfc9e2004ac4f85274f52b32e1647b4dbc9761b82e7de1e41c49907eb08
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
PKG_CPE_ID:=cpe:/a:thekelleys:dnsmasq
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_UPSTREAM_VERSION)
PKG_INSTALL:=1
PKG_BUILD_PARALLEL:=1
PKG_ASLR_PIE_REGULAR:=1
PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcp \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6 \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc \
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_tftp
include $(INCLUDE_DIR)/package.mk
define Package/dnsmasq/Default
SECTION:=net
CATEGORY:=Base system
TITLE:=DNS and DHCP server
URL:=http://www.thekelleys.org.uk/dnsmasq/
DEPENDS:=+libubus
USERID:=dnsmasq=453:dnsmasq=453
endef
define Package/dnsmasq
$(call Package/dnsmasq/Default)
VARIANT:=nodhcpv6
endef
define Package/dnsmasq-dhcpv6
$(call Package/dnsmasq/Default)
TITLE += (with DHCPv6 support)
DEPENDS+=@IPV6
VARIANT:=dhcpv6
PROVIDES:=dnsmasq
endef
define Package/dnsmasq-full
$(call Package/dnsmasq/Default)
TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Conntrack, NO_ID enabled by default)
DEPENDS+=+PACKAGE_dnsmasq_full_dnssec:libnettle \
+PACKAGE_dnsmasq_full_ipset:kmod-ipt-ipset \
+PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack
VARIANT:=full
PROVIDES:=dnsmasq
endef
define Package/dnsmasq/description
It is intended to provide coupled DNS and DHCP service to a LAN.
endef
define Package/dnsmasq-dhcpv6/description
$(call Package/dnsmasq/description)
This is a variant with DHCPv6 support
endef
define Package/dnsmasq-full/description
$(call Package/dnsmasq/description)
This is a fully configurable variant with DHCPv4, DHCPv6, DNSSEC, Authoritative DNS
and IPset, Conntrack support & NO_ID enabled by default.
endef
define Package/dnsmasq/conffiles
/etc/config/dhcp
/etc/dnsmasq.conf
/etc/dnsmasq.d/
endef
define Package/dnsmasq-full/config
if PACKAGE_dnsmasq-full
config PACKAGE_dnsmasq_full_dhcp
bool "Build with DHCP support."
default y
config PACKAGE_dnsmasq_full_dhcpv6
bool "Build with DHCPv6 support."
depends on IPV6 && PACKAGE_dnsmasq_full_dhcp
default y
config PACKAGE_dnsmasq_full_dnssec
bool "Build with DNSSEC support."
default y
config PACKAGE_dnsmasq_full_auth
bool "Build with the facility to act as an authoritative DNS server."
default y
config PACKAGE_dnsmasq_full_ipset
bool "Build with IPset support."
default y
config PACKAGE_dnsmasq_full_conntrack
bool "Build with Conntrack support."
default y
config PACKAGE_dnsmasq_full_noid
bool "Build with NO_ID. (hide *.bind pseudo domain)"
default y
config PACKAGE_dnsmasq_full_broken_rtc
bool "Build with HAVE_BROKEN_RTC."
default n
config PACKAGE_dnsmasq_full_tftp
bool "Build with TFTP server support."
default y
endif
endef
Package/dnsmasq-dhcpv6/conffiles = $(Package/dnsmasq/conffiles)
Package/dnsmasq-full/conffiles = $(Package/dnsmasq/conffiles)
TARGET_CFLAGS += -flto
TARGET_LDFLAGS += -flto=jobserver
COPTS = -DHAVE_UBUS -DHAVE_POLL_H \
$(if $(CONFIG_IPV6),,-DNO_IPV6)
ifeq ($(BUILD_VARIANT),nodhcpv6)
COPTS += -DNO_DHCP6
endif
ifeq ($(BUILD_VARIANT),full)
COPTS += $(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcp),,-DNO_DHCP) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6),,-DNO_DHCP6) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec),-DHAVE_DNSSEC) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth),,-DNO_AUTH) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset),,-DNO_IPSET) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack),-DHAVE_CONNTRACK,) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid),-DNO_ID,) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc),-DHAVE_BROKEN_RTC) \
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_tftp),,-DNO_TFTP)
COPTS += $(if $(CONFIG_LIBNETTLE_MINI),-DNO_GMP,)
else
COPTS += -DNO_AUTH -DNO_IPSET -DNO_ID
endif
MAKE_FLAGS := \
$(TARGET_CONFIGURE_OPTS) \
CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
LDFLAGS="$(TARGET_LDFLAGS)" \
COPTS="$(COPTS)" \
PREFIX="/usr"
define Package/dnsmasq/install
$(INSTALL_DIR) $(1)/usr/sbin
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/dnsmasq $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/dhcp.conf $(1)/etc/config/dhcp
$(INSTALL_CONF) ./files/dnsmasq.conf $(1)/etc/dnsmasq.conf
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/dnsmasq.init $(1)/etc/init.d/dnsmasq
$(INSTALL_DIR) $(1)/etc/hotplug.d/dhcp
$(INSTALL_DIR) $(1)/etc/hotplug.d/neigh
$(INSTALL_DIR) $(1)/etc/hotplug.d/ntp
$(INSTALL_DIR) $(1)/etc/hotplug.d/tftp
$(INSTALL_DATA) ./files/dnsmasqsec.hotplug $(1)/etc/hotplug.d/ntp/25-dnsmasqsec
$(INSTALL_DIR) $(1)/usr/share/dnsmasq
$(INSTALL_CONF) ./files/dhcpbogushostname.conf $(1)/usr/share/dnsmasq/
$(INSTALL_CONF) ./files/rfc6761.conf $(1)/usr/share/dnsmasq/
$(INSTALL_DIR) $(1)/usr/lib/dnsmasq
$(INSTALL_BIN) ./files/dhcp-script.sh $(1)/usr/lib/dnsmasq/dhcp-script.sh
$(INSTALL_DIR) $(1)/usr/share/acl.d
$(INSTALL_DATA) ./files/dnsmasq_acl.json $(1)/usr/share/acl.d/
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/50-dnsmasq-migrate-resolv-conf-auto.sh $(1)/etc/uci-defaults
endef
Package/dnsmasq-dhcpv6/install = $(Package/dnsmasq/install)
define Package/dnsmasq-full/install
$(call Package/dnsmasq/install,$(1))
ifneq ($(CONFIG_PACKAGE_dnsmasq_full_dnssec),)
$(INSTALL_DIR) $(1)/usr/share/dnsmasq
$(INSTALL_CONF) $(PKG_BUILD_DIR)/trust-anchors.conf $(1)/usr/share/dnsmasq
endif
endef
$(eval $(call BuildPackage,dnsmasq))
$(eval $(call BuildPackage,dnsmasq-dhcpv6))
$(eval $(call BuildPackage,dnsmasq-full))
导入mk文件
以include开头,用来包含源码已经定义好的mk文件,以此来调用Openwrt已经定义好的语法。
Openwrt已经定义好了的文件:
- rules.mk:这个文件定义了全局的编译变量,在每一个软件包的Makefile文件的第一行均首先包含这个文件;
- package.mk:软件包的基本信息PKG_NAME PKG_SOURCE等完成再引入,用于编译一般的软件包;
定义变量
Openwrt预定义了很多变量,这些变量减少了使用者的开发代价,但需要使用者按照语义进行使用。
系统变量
下面的变量是定义好了系统变量,实际工程在使用时只需要调用这些变量即可。主要定义了编译时使用的系统信息,如头文件目录、安装软件包的解压目录。
变量名 | 定义的文件 | 含义 |
---|---|---|
INCLUDE_DIR | rules.mk | 源代码顶层目录下的include目录 |
BUILD_DIR | rules.mk | 代码编译的根目录,通常为“build_dir/target-*”目录 |
TARGET_CFLAGS | rules.mk | 指定平台的C语言编译选项 |
TARGET_LDFLAGS | rules.mk | 指定目标平台的编译链接选项 |
INSTALL_DIR | rules.mk | 创建目录,并设置目录权限为0755 |
INSTALL_DATA | rules.mk | 安装数据文件,即复制并设置权限为0644 |
INSTALL_CONF | rules.mk | 安装配置文件,即复制并设置权限为0600 |
INSTALL_BIN | rules.mk | 安装可执行程序,即复制并设置权限为0755 |
用户变量
下面的变量是Openwrt预定义好的部分变量,这些变量减少了使用者的开发代价,但需要使用者按照语义使用。
变量名 | 含义 | 示例 |
---|---|---|
PKG_NAME | 软件包名称,可以通过menuconfig和ipkg看到 | dnsmasq |
PKG_VERSION | 上游软件的版本号,为2.73 | 2.73 |
PKG_RELEASE | Makefile的版本号 | 1 |
PKG_SOURCE | 原始的源代码文件名 | |
PKG_SOURCE_URL | 用于下载源码的地址(目录) | http://thekelleys.org.uk/dnsmasq |
PKG_HASH | 软件包的MD5值,用于验证下载的文件是否正确 | 28d52cfc9e2004ac4f85274f52b32e1647b4dbc9761b82e7de1e41c49907eb08 |
PKG_LICENSE | 这个软件的许可证,开源软件的许可证以GPL家族最多 | GPL-2.0 |
PKG_LICENSE_FILES | 许可协议文件,是指代码目录下的文件名,一般均为COPYING | COPYING |
PKG_BUILD_DIR | 软件包的编译目录 | |
PKG_INSTALL | 设置为1将调用软件包自己的“make install”, 安装目录前缀为PKG_INSTALLDIR | 1 |
PKG_BUILD_PARALLEL | 是否可以并行编译 | 1 |
PKG_CONFIG_DEPENDS | 编译依赖,指定那些选项依赖本软件包 | |
PKG_INSTAll_DIR | 当调用原始软件包“make install”时的安装目录 | |
PKG_SOURCE_PROTO | 用于下载的传输协议(git、svn),如果为压缩包则不用指定 | |
PKG_SOURCE_SUBDIR | 下载目录,如果下载传输协议为“svn”或“git”时必须指定。 | |
PKG_SOURCE_VERSION | 下载协议为“git”时必须指定。指定的提交哈希点将会被检出 | |
PKG_MAINTAINER | 维护者的姓名和邮件地址 | |
PKG_BUILD_DEPENDS | 软件包编译依赖,即在这个包编译之前编译,但是在运行时不需要,和DEPENDS有相同的语法 |
软件包定义
宏定义以Package/开头,Package开头的定义用于make menuconfig选择及编译生成软件包。
Package选项
实际使用时,**<>**需要替换成软件包的名称。
变量名 | 是否必须 | 含义 |
---|---|---|
Package/<> | 是 | 定义软件包的描述信息,例如网站地址和menuconfig中的菜单分类等 |
Package/<>/Default | 可选 | 软件包的默认选项 |
Package/<>/description | 是 | 软件包的详细描述 |
Package/<>/install | 是 | 复制文件到ipkg目录中,使用 ( 1 ) 代表 i p k g 的目录,在源代码中使用相对目录。编译生成的安装文件由 (1)代表ipkg的目录,在源代码中使用相对目录。编译生成的安装文件由 (1)代表ipkg的目录,在源代码中使用相对目录。编译生成的安装文件由(PKG_INSTALL_DIR)目录复制到ipkg的目录下 |
Package/<>/config | 可选 | 根据软件包的选择对编译选项进行定义 |
Package/<>/conffiles | 可选 | 定义本软件包的运行配置文件列表,一行一个文件 |
Package/<>/preinst | 可选 | 这是在安装之前实际执行的脚本,需要包含#!/bin/sh。如果需要中止安装就返回false |
Package/<>/postinst | 可选 | 这是在安装之后实际执行的脚本,需要包含#!/bin/sh。 |
Package/<>/prerm | 可选 | 这是在删除之前实际执行的脚本,需要包含#!/bin/sh。如果需要中止安装就返回false |
Package/<>/postrm | 可选 | 这是在删除之后实际执行的脚本,需要包含#!/bin/sh。如果需要中止安装就返回false |
Package变量
软件包定义还需要定义一些变量,这些参数传递给buildroot进行交叉编译。这些参数会在menuconfig里面和实体的ipkg安装包中显示。在软件包**Package/**定义下需要给下列变量赋值。
- SECTION:软件包类型,如network、sound、Utilities或Multimedia。
- CATEGORY:在menuconfig中显示到菜单分类中。
- TITLE:标题,是软件包的简短描述。
- URL:软件包的原始网站网址。
- MAINTAINER:维护者的姓名和邮件地址。一般为这个软件包作者的邮件地址。
- DEPENDS:依赖项,需要在本软件包之前编译和安装的软件包。
构建
宏定义以**Build/**开头,这些用于代码编译。通常包含准备(Prepare)、配置(Configure)、编译(Compile)和安装(Install)等4步。这部分在构建时都是可选的。
Build步骤 | 是否必须 | 含义 |
---|---|---|
Build/Prepare | 是 | 一组用于解包及打补丁的命令,也可以不使用 |
Build/Configure | 是 | 如果源代码不需要configure来生成Makefile或者是通用的configure脚本,就不需要这部分。 |
Build/Compile | 是 | 编译源代码,大多数情况下不用定义而使用默认值。如果你想传递给make特定的参数,可以使用“$(call Build/Compile/Default, FOO=bar)” |
Build/Install | 是 | 安装编译后的文件,默认是调用make install。如果你想传递给make特定的参数,可以使用“$(call Build/Compile/Install, FOO=bar)” |
Build/InstallDev | 是 |
BuildPackage
BuildPackage是在头文件 include/package.mk中定义的。BuildPackage仅需要一个直接参数–要编译的软件包名称。