下面用
表示 Openwrt 源码树顶层目录。Openwrt 所有的软件包都都保存在
目录下,一个软件包占一个子目录。
例如: helloworld,如下所示
重点,它定义了如何构建一个
Openwrt 软件包,包括从哪里下载源码,怎样编译和安装。
可选,一般存放配置文件和启动脚本。
可选,一般存放 bug 修复或者程序优化的补丁。
两种软件包目录格式:
1、没有源码的 Openwrt 软件包目录下,构建 Openwrt 软件包的第一步是从指定的 URL 下载指定的源码包,
这个 URL 在 Makefile 中定义,如下所示:
PKG_SOURCE:=helloworld.tar.gz
PKG_SOURCE_URL:=http://www.example.com/
PKG_MD5SUM:=e06c222e186f7cc013fd272d023710cb
用于验证下载的软件包的完整性。
下载的helloworld.tar.gz 一般存放在
目录,后
解压到
2、自己写的代码构建 Openwrt 软件包的方式是在
目录下创
建一个子目录 src,用来保存自己写的源码文件,如下所示:
这种方式没有任何源码包需要从 Web 下载,这里的
和通常的 GNU Makefile语法一样
每个包都包含一个Makefile,内容也大致相同,首先导入几个文件进来,它们定义了一些变量、规则、函数
include $(TOPDIR)/rules.mk
PKG_*
自定义软件包的一些信息
include $(INCLUDE_DIR)/package.mk
对PKG_*没有定义到的基本信息补充,以及其他mk文件的导入。最重要的是定义BuildPackage宏在 Makefile 的最后一行被引用。
include $(INCLUDE_DIR)/kernel.mk
定义内核模块时才需要
include $(INCLUDE_DIR)/cmake.mk
使用 cmake 构建软件时才需要
PKG_*
PKG_*
定义了软件包相关的一些基本信息,如下所示:
PKG_NAME
-包的名称。
PKG_VERSION
-下载的或者自己写的软件包的版本号(必须)
PKG_RELEASE
-当前的编译版本,可能根据不同需求,编译方式不同。
PKG_BUILD_DIR
- 在 哪个目录下编译该软件包, 默 认 为 $(BUILD_DIR) /$( PKG_NAME)
-$(PKG_VERSION)
PKG_SOURCE
-要从网上下载的的源码包的文件名
PKG_SOURCE_URL
-从哪里下载源码包
PKG_MD5SUM
-用于验证下载的源码包的完整性
PKG_CAT
-怎样解压源码包 (zcat, bzcat,unzip等)
PKG_BUILD_DEPENDS
-定义需要在该软件包之前编译的软件包或者一些版本的依赖。和下面的DEPENDS 语法相同。
define Package/xxx
描述软件包在 menuconfig 和 ipkg 中的条目(其中的 xxx要S与PKG_NAME一致, 即出现在 menuconfig 中的标签以及.config 中的CONFIG_PACKAGE_xxx=y)如下图:
左边
PKG_NAME
包名字,右边是如下说的TITLE
描述内容
SECTION
- 软件包的类型如(net、utilities等)
CATEGORY
- 该软件包出现在 menuconfig 中的哪个菜单下,如果是第一次使用,则 menuconfig 中会新创建一个菜单,如图:
TITLE
- 对该软件包的一个简短描述,如第一张图右半部分。
URL
- 在哪里可以找到该软件包的源码包
MAINTAINER
-定义该软件包的维护者的联系方式
DEPENDS
- 定义需要在该软件包之前编译/安装的软件包,或者其他一些依赖条件,比如版本依赖等,多个依赖之间使用空格分隔,下面列出其具体语法:
DEPENDS:=+foo
当前软件包和 foo 都会出现在 menuconfig 中,当前软件包被选中时,其依赖的软件DEPENDS:=foo
只有当其依赖的软件包 foo 被选中时,当前软件包才会出现在 menuconfig 中。DEPENDS:=@FOO
软件包依赖符号 CONFIG_FOO,只有当符号 CONFIG_FOO 被设置时,该软件包才会DEPENDS:=+FOO:bar
当前软件包和软件包 bar 都会出现在 menuconfig 中。如果符号 CONFIG_FOO 被DEPENDS:=@FOO:bar
如果符号 CONFIG_FOO 被设置,则当前软件包依赖于软件包 bar,否则不依赖,define KernelPackage/xxx
描述内核模块在 menuconfig 和 ipk 中的条目(在 menuconfig 中看到的标签为 kmod-xxx)
SUBMENU
– 该模块出现在 menuconfig 中的 Kernel modules
菜单下的哪个子菜单。
TITLE
– 对该模块的一个简短描述
FILES
– 模块名称(全路径),多个模块文件之间用空格分开
AUTOLOAD
– 自动加载,例如:AUTOLOAD:=$(call AutoLoad,40,timesync can)表示自动加载 timesync.ko
和 can.ko,其加载的优先级为 40
define Build/Prepare
定义一组指令,比如用于给源码打补丁,创建编译目录,拷贝自己的源码到编译目录。对于从网上下载源
码包一般不需要定义,对于从自己写的代码构建软件包,一般按如下方式定义:
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Configure
对于需要通过执行./ configure
的软件包可以在这里自定义。可参考 package/libs/openssl/Makefile
define Build/Compile
如何编译源码,一般不用定义。可参考 package/libs/openssl/Makefile。但对于内核模块需要这样定义
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
ARCH="$(LINUX_KARCH)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
SUBDIRS="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
$(EXTRA_KCONFIG) \
modules
endef
define Package/xxx/install
如何安装软件包。定义了一组命令,用来在嵌入式文件系统中创建目录或者拷贝相关文件到嵌入式文件系统或者 ipk。例如:
define Package/helloworld/install
echo "Here is Package/install"
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/
endef
这里的$(1)
表示嵌入式根文件系统 rootfs 的根目录
$(INSTALL_DIR) $(1)/bin
表示在嵌入式根文件系统中创建目录 bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin
/表示将可执行程序$(PKG_BUILD_DIR)/helloworld
拷贝到嵌入式根文件系统的 bin 目录下
INSTALL_XXX
在
中定义
INSTALL_DIR
用来安装目录,安装的目录权限为所属用户可读/写/执行,其他用户可读/执行。
INSTALL_DATA
用来安装数据文件,其权限为所属用户可读/写,其他用户可读
INSTALL_CONF
用来安装配置文件,其权限为所属用户可读/写,其他用户不能读/写/执行。
Package/xxx/preinst
定义一段需要在软件包安装前执行的脚本。例如
define Package/helloworld/preinst
#!/bin/sh
echo 'before install $(PKG_NAME)'
endef
Package/xxx/postinst
定义一段需要在软件包安装后执行的脚本
Package/xxx/prerm
定义一段需要在软件包删除前执行的脚本
Package/xxx/postrm
定义一段需要在软件包删除后执行的脚本
注意:这些脚本必须可以同时在嵌入式设备和主机上都能执行
$(eval $(call BuildPackage,xxx))
或者$(eval $(call KernelPackage,xxx))
,前者用于应用程序,后者用于内核模块,如果有多个软件包需要针对每个软件包调用。
helloworld实例
hellokernel实例