OpenWrt 是一个比较完善的嵌入式 Linux 开发平台,在 OpenWrt 中增加软件包极其方便,按照 OpenWrt 的约定就可以很简单的完成。软件包需要在 package 目录下创建一个目录,以包含该软件包的各种信息和与 OpenWrt 建立联系的文件。然后创建一个Makefile 与 OpenWrt 建立联系, Makefile 需要遵循 OpenWrt 的约定。下面就简单的说明一下具体的创建和测试过程。
一、源码编译使用模块,用户自定义安装,卸载
1、创建软件包
在package下新建文件夹,其名称一般为你要添加的软件包的名称,此处为测试特意使用别的名称,按 OpenWrt 的习惯,一般把自己设计的程序全部放在 src 目录下。 所以,文件结构如下
myapp/
├── Makefile
└── src
├── Makefile
└── myabcd.c
2、编写 src 文件下的文件内容
(1)myabcd.c 内容如下
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char **argv)
{
int i = 0;
FILE *fs;
fs = fopen("/dev/console", "w+");
for (i = 0; ; i++)
{
fprintf(fs, "[ %02d ] This is /dev/console Test\n", i);
sleep(1);
}
return 0;
}
(2)Makefile内容如下
all: mycode
mycode:
$(CC) $(CFLAGS) -o $@ myabcd.c -Wall
clean:
rm -f myabcd
3、上级 Makefile的写法
##############################################
#
# OpenWrt Makefile for mycode program
#
##############################################
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME := mycode
PKG_VERSION := 0.1
PKG_RELEASE := 1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Songshuai Package
SUBMENU:=Software Testing modules
TITLE:=This is SongShuai's test project.
MAINTAINER:=Songshuai
endef
define Package/$(PKG_NAME)/description
If you can't figure out what this program does, you're probably
brain-dead and need immediate medical attention.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Configure
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
ARCH="$(LINUX_KARCH)" \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS) -Wall" \
LDFLAGS="$(TARGET_LDFLAGS)"
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/app
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/app/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
OpenWrt 使用三个 Makefile 的子文件,分别为:
$(TOPDIR)/rules.mk # 一般在 Makefile 的开头,
$(INCLUDE_DIR)/kernel.mk # 文件对于软件包为内核时是不可缺少,
$(INCLUDE_DIR)/package.mk # 一般在软件包的基本信息完成后再引入。
由这些Makefile子文件确立软件包加入OpenWrt的方式和方法 。
说明一、软件包的信息均以 PKG_开头,其意思和作用如下:
PKG_NAME:示软件包名称,将在 menuconfig 和 ipkg 可以看到。
PKG_VERSION:表示软件包版本号。
PKG_RELEASE:表示 Makefile 的版本号。
PKG_SOURCE:表示源代码的文件名。
PKG_SOURCE_URL:表示源代码的下载网站位置。 @SF 表示在 sourceforge 网站,@GNU 表示在 GNU 网站,还有@GNOME、 @KERNEL。
PKG_MD5SUM:表示源代码文件的效验码。用于核对软件包是否正确下载。
PKG_CAT:表示源代码文件的解压方法。包括 zcat, bzcat, unzip 等。
PKG_BUILD_DIR:表示软件包编译目录。它的父目录为$(BUILD_DIR)。如果不指定,默认为
$(BUILD_DIR)/$(PKG_NAME)/$(PKG_VERSION)
说明二、应用程序的编译包以 Package/ 开头,然后接着软件名称,在 Package 定义中的软件名称可以与软件包名称不一样,而且可以多个定义
SECTION:表示包的类型,预留。
CATEGORY:表示分类,在 make menuconfig 的菜单下将可以找到。
TITLE:用于软件包的简短描述。
URL:表示软件包的下载位置。
MAINTAINER:表示维护者,选项。
DEPENDS:表示与其他软件的依赖。即如编译或安装需要其他软件时需要说明。如果有多个依赖,则每个依赖需要用空格分开。依赖前使用+号表示默认为显示,即对象沒有选中时也会显示,使用@则默认为不显示,即当依赖对象选中后才显示。
说明三、在Makefile中,package定义的说明
Package/$(PKG_NAME)/conffiles
本包安裝的配置文件,一行一个。如果文件结尾使用 / ,则表示为目录。用于备份配置文件说明,在 sysupgrade 命令执行时将会用到。Package/$(PKG_NAME)/description
软件包的详细描述,取代 DESCRIPTION 详细描述。Build/Prepare
编译准备方法,对于网上下载的软件包不需要再描述。对于非网上下载或自行开发的软件包必须说明编译准备方法。Build/Configure
在 Automake 中需要进行./configure,所以本配置方法主要针对需要配置的软件包而设计,一般自行开发的软件包可以不在这里说明。Build/Compile
编译方法,没有特别说明的可以不予以定义。如果不定义将使用默认的编译方法 Build/Compile/Default。Package/$(PKG_NAME)/install
软件包的安装方法,包括一系列拷贝编译好的文件到指定位置。调用时会带一个参数,就是嵌入系統的镜像文件系统目录,因此 $(1) 表示嵌入系统的镜像目录。可以用户自定义目录,本例中使用的是app目录。
INSTALL_DIR、 INSTALL_BIN 在 $(TOPDIR)/rules.mk 文件定义,基本不要额外关注。其中:
INSTALL_DIR :=install -d -m0755
意思是创建所属用戶可读写和执行,其他用戶可读可执行的目录。
INSTALL_BIN:=install -m0755
意思编译好的文件存放到镜像文件目录。
说明:
如果用戶空间的应用软件在 boot 时要自动运行, 则需要在安装方法说明中增加自动运行的脚本文件安装和配置文件安裝方法。详细说明可搭乘电梯直达查看
完成前面定义后,必须使用 eval 函数实现各种定义。其格式为:
对于一般应用软件包
$(eval $(call BuildPackage,$(PKG_NAME)))
如果一个软件包有多个程序,例如:一个应用程序有自己的內核驱动模块,上面使用的 PKG_NAME 需要灵活变通。 eval 函数可以设计多个。也可以当成多个软件包处理。
4、编译
首先进行 make menuconfig 进行选择,
Songshuai Package --> Software Testing modules
这里选择为 M,表示安装成 ipk 模块, 也可以选择 y 将其编译进固件。
现在可以单独编译该软件包, 执行如下命令
$ make package/myapp/compile V=99
编译完成后注意下生成的ipk文件的位置
或者也可以使用
find . -name "mycode*"
来查找一下。
5、安装测试
将编译完成后生成的ipk传到开发板上(如何传请自行解决 ^_^ ),进行下一步的安装和测试操作。
# opkg install mycode_0.1-1_mipsel_24kc.ipk
Installing mycode (0.1-1) to root...
Configuring mycode.
安装完成后可以将 mycode_0.1-1_mipsel_24kc.ipk 删除了,然后进入到安装目录 app 目录下
测试完成,可以通过指令卸载
# opkg remove mycode
Removing package mycode from root...
卸载完成后,在 /app/ 目录下,也会删除 mycode 可执行程序文件。
好奇心促使下面的内容诞生:
在网上看到大佬们一直在说 preinst、postinst、prerm、postrm 的,因为不知道具体的实际使用的场合,此处也是满足一下自己的好奇心,特意试了一下,在上面的 Makefile 中 $(eval $(call BuildPackage,$(PKG_NAME)))
之前添加如下内容
define Package/$(PKG_NAME)/preinst
#!/bin/bash
echo 'installing $(PKG_NAME)'
endef
define Package/$(PKG_NAME)/postinst
#!/bin/bash
echo '$(PKG_NAME) installed successed !'
endef
define Package/$(PKG_NAME)/prerm
#!/bin/bash
echo 'removeing $(PKG_NAME)'
endef
define Package/$(PKG_NAME)/postrm
#!/bin/bash
echo '$(PKG_NAME) remove successed !'
endef
说明:因为笔记的开发板上支持bash,所以此处使用的bash,但是Openwrt默认是使用ash,可以将bash替换成ash进行测试。
然后 编译、上传到开发板,之后进行安装
# opkg install mycode_0.1-1_mipsel_24kc.ipk
Installing mycode (0.1-1) to root...
installing mycode
Configuring mycode.
mycode installed successed !
# ls /app/
mycode
# opkg remove mycode
Removing package mycode from root...
removeing mycode
mycode remove successed !
含义说明:
Package/$(PKG_NAME)/preinst
软件包安装前处理方法,使用脚本语言,调用时带入的参数为嵌入式系統的镜像目录。
Package/$(PKG_NAME)/postinst
软件包安装后处理方法,使用脚本语言。
Package/$(PKG_NAME)/prerm
软件包删除前处理方法,使用脚本语言。
Package/$(PKG_NAME)/postrm
软件包删除后处理方法,使用脚本语言。
二、编译源码,直接编译到内核中
进行 make menuconfig 进行选择 y 将其编译进固件。
此时需要进行整个openwrt的全编译,使用
$ make V=99
进行编译,编译完成后,重新烧写内核文件即可,内核启动完成,可以直接在 /app/ 目录下看到 mycode 可执行程序的文件。
三、不使用源码编译
当然 ,如果不想这么麻烦的编辑Makefile,那么关于用户自定义添加的软件包的方法,还有另外一种比较省事情的方法,就是将通过交叉编译(我的交叉编译工具链为 mipsel-openwrt-linux-gcc
)完成的可执行程序文件 (比如本历程中的 mycode )直接放置在目录下 package/base-files/files/app/
,然后编译内核文件,再进行烧写即可,之后,可执行程序文件mycode也存在/app/下。
具体步骤以及指令可以使用:
$ mipsel-openwrt-linux-gcc myabcd.c -o mycode
$ cp mycode ~/openwrt/package/base-files/files/app/
$ make V=99
此效果与上面的 二 的效果一样。