openwrt 一个比较重要的特点就是它采用 ipk 包的形式安装软件。有点像是 windows 下面的安装包一样,用户只需用简单的命令就可以将 ipk 安装包安装到 openwrt 系统中,非常方便。下面来介绍如何制作编译一个简单的安装包。
源码
切换到 openwrt 源码根目录,然后执行下列命令:
cd ./package //进入 package 目录
mkdir hello_world //创建一个名为“hello_world”的文件夹,用于放置安装包源码。
cd hello_world //进入“hello_world”目录
mkdir src //新建一个名为“src”的目录用于放置源码
vi src/hello_world.c //在 src 目录下新建一个名为 hello_world.c 文件
输入 hello_world.c 中的内容:
#include <stdio.h>
int main(char argc, char *argv[])
{
int i = 1;
while(1){
//1~10 循环
printf("Hello world!!!%d\n",i); //打印内容
if (i < 10){
i++;
}else{
i = 1;
}
sleep(1);// 一秒钟打印一次
}
return 0;
}
vi src/Makefile,//在 src 目录下新建一个 Makefile,输入下面内容:
all: hello_world
hello_world: hello_world.o
$(CC) $(LDFLAGS) hello_world.o -o hello_world
helloworld.o: hello_world.c
$(CC) $(CFLAGS) -c hello_world.c
clean:
rm *.o hello_world
vi Makefile,输入下面内容:
include $(TOPDIR)/rules.mk
PKG_NAME:=hello_world
PKG_VERSION:=1.0
PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/hello_world
SECTION:=base
CATEGORY:=Utilities
TITLE:=Hello world -prints a hello world message
endef
define Package/hello_world/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 Package/hello_world/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/hello_world $(1)/bin/
endef
$(eval $(call BuildPackage,hello_world))
配置
make menuconfig,选择我们已经加进去的安装包
Utilities --->
<M> hello_world.................... Hello world -prints a hello world message
编译
make V=99
make package/hello_world/compile V=99
文件:./bin/packages/hello_world_1.0_arm.ipk
安装
scp传输到板子:
scp ./bin/packages/hello_world_1.0_arm.ipk root@192.168.10.1:/tmp
root@192.168.10.1's password:
hello_world_1.0_arm.ipk 100% 2279 2.2KB/s 00:00
如提示host的key已经更改(换了其他板子):
需要删除用户目录下的~/.ssh/known_hosts文件,重新运行scp命令进行传输。
安装:
运行
安装路径:/bin/hello_world
扩展1、ipk包
ipk包,首先,IPK是个tar压缩包,安装其实就是通过解压到系统根目录/来完成安装的。所以,ipk的安装是覆盖安装。
也就是说,如果你之前安装过,然后自己有改动程序的话,再次安装会覆盖掉原来的文件,那你的改动就会被覆盖掉了。
解压:得到3个文件:control.tar.gz data.tar.gz debian-binary
[yubo.wang@localhost tmp-hello]$ tar -xvf hello_world_1.0_arm.ipk
./debian-binary
./data.tar.gz
./control.tar.gz
- ipk里的结构。
IPK包里首先是有3个文件,分别是:
debian-binary ##版本信息,一般写的都是2.0……这个无关紧要……无视掉……
data.tar.gz ##安装包的数据包,主要的安装文件都在这里,通过解压这个文件到根目录来达到安装的目的
control.tar.gz ##安装配置文件,里面放的是安装包的配置脚本。
- data和control这2个包。
data里的文件都是按照系统根目录来建立文件目录放至安装的程序的。这样在解压的时候就会自动的覆盖对应的文件夹和文件。
比如如果要把一个叫做test.sh的文件安装到/usr/local/bin里,那么data里的文件和文件夹夹结构就应该和安装目标是一样的:/usr/local/bin/test.sh,这样执行解压的时候就可以直接自动覆盖安装到对应的目录去了。
[yubo.wang@localhost tmp-hello]$ tar -xvzf data.tar.gz
./
./bin/
./bin/hello_world
然后是control包,这个包里一般有preinst、postinst、prerm和postrm这几个文件。这些文件都是Linux的sh脚本,它们对应的功能是这样的:
preinst(安装前执行), postinst(安装完成执行), prerm(卸载前执行), postrm(卸载完成执行)就比如说,如果你需要在安装test.ipk安装包前删掉/tmp里的所有文件,那么你就在preinst里写sh命令rm -r /tmp/*即可。如果你需要在安装完成后输出个日志文件,你就在postinst文件里写sh命令 echo '安装完成' > /tmp/test.ipk.log即可……其他的也一样的道理。
扩展2、三种编译package方式
1、第一种方式,Makefile,就是上面编译hello_world方式,使用源码同级目录下的Makefile文件方式,在没有实现Build/Compile情况下,通过默认的define Build/Compile/Default使用命令$(MAKE) -C $(PKG_BUILD_DIR)编译源码目录。如果自己实现就如下所示:
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS) -Wall" \
LDFLAGS="$(TARGET_LDFLAGS)"
endef
2、第二种方式,直接gcc编译文件,使用与文件数量很少的情况下就不用去写Makefile规则:
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) $(PKG_BUILD_DIR)/hello_world.c -o $(PKG_BUILD_DIR)/hello_world
endef
如果不加$(PKG_BUILD_DIR)路径会提示:aarch64-openwrt-linux-musl-gcc: error: hello_world.c: No such file or directory,这时候还在package/hello_world目录。
3、第三种方式,cmake,需要导入cmake.mk文件,不需实现Build/Compile。适用于网络包CMakeLists.txt情况。
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk