前言:
关于openwrt编写应用程序, 这个网上有很多的文章,都仅仅是helloworld的例子,对于开发应用程序来说是远远不够的, 本文以编译编译redis-server.ipk包为例,来讲述在openwrt平台下如何开发应用程序,这篇文章的目的是可以再openwrt下开发任意ipk包
前期准备:
首先要创建openwrt sdk环境,这个官网有个精华帖,可以跟着做, 我是差不多整整两天的时间弄好了这个SDK环境, 因为在编译openwrt源码时会在网上下载各种各样的资源,网速不好的话会很慢
大家可以注意到,源码编译后,会在 /bin/ramips下生成SDK, 将这个SDK:openWrt-SDK-ramips-mt7620...tar.bz2 放在非root用户下使用, 尝试了下,放在root用户下不好使,生成不出来ipk
大家可以看到, 把SDK放入非root用户下, 之后看下上图中的package目录, 就是今天的猪脚了
开始行动:
1.对于编译应用程序, 大家必须把对应的文件做好放在package目录里,如图所示就是这个Ma文件夹了, 这个Ma文件夹有一个makefile与src文件夹,这结构是必须的
package
|-----Makefile(SDK自带)
|-----XXX(文件夹,随便起名字)
|-----Makefile(需要自己写,根据模板)
|-----src(文件夹, 必须是src这个名字)
|----src里就是需要编译的源码, 里面就自己随便写了,就跟平时做linux开发一样的
当然,我把下载的redis的源码都拷贝到了src里面去了(说白了就是把redis-3.2-rc1.tar.gz解压到XXX文件夹中,然后将解压后生成的redis-3.2-rc1/文件夹替换名字为src)
之后对XXX中的Makefile进行编写
2.对于Makefile的编写,其实就是参考模板进行修改
##############################################
# OpenWrt Makefile for helloworld program
#
#
# Most of the variables used here are defined in
# the include directives below. We just need to
# specify a basic description of the package,
# where to build our program, where to find
# the source files, and where to install the
# compiled program on the router.
#
# Be very careful of spacing in this file.
# Indents should be tabs, not spaces, and
# there should be no trailing whitespace in
# lines that are not commented.
#
##############################################
include $(TOPDIR)/rules.mk
# Name and release number of this package
PKG_NAME:=redis-server_x //在SDK根目录下编译,它会遍历package下的文件夹(XXX)/src进行编译,所以XXX随便起名字,只要有src在就可以,src目录下是自己的源码,make刚开始的时候,sdk会将src下的所有源文件拷贝到 build_dir/PKG_NAME/目录下,之后在PKG_NAME目录下进行编译
PKG_RELEASE:=1 //版本号,比如最终会生成redis-server_x_1_ramips_24kec.ipk
# This specifies the directory where we're going to build the program.
# The root build directory, $(BUILD_DIR), is by default the build_mipsel
# directory in your OpenWrt SDK directory
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) //注意这个BUILD_DIR 是SDK目录下的build_dir文件夹,开始编译时会把package/Ma/src/下的所有东西拷贝到这里进行编译
include $(INCLUDE_DIR)/package.mk
# Specify package information for this program.
# The variables defined here should be self explanatory.
# If you are running Kamikaze, delete the DESCRIPTION
# variable below and uncomment the Kamikaze define
# directive for the description below
define Package/redis-server_x
SECTION:=utils
CATEGORY:=Utilities
TITLE:=redis-server -- prints a snarky message
DEPENDS:= +libpthread //在这个redis-server_x文件夹下编译需要线程库函数,当然,如果过程中还需要什么库就添加在这里
endef
# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above
define Package/redis-server_x/description
If you can't figure out what this program does, you're probably
brain-dead and need immediate medical attention.
endef
# Specify what needs to be done to prepare for building the package.
# In our case, we need to copy the source files to the build directory.
# This is NOT the default. The default uses the PKG_SOURCE_URL and the
# PKG_SOURCE which is not defined here to download the source from the web.
# In order to just build a simple program that we have just written, it is
# much easier to do it this way.
define Build/Prepare //编译的前期准备,make刚开始时,会在build_dir目录下创建redis_server_x这个文件夹,
//然后将package/Ma/src文件夹下所有的东西拷贝到redis_server_x文件夹中
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
# We do not need to define Build/Configure or Build/Compile directives
# The defaults are appropriate for compiling a simple program such as this one
define Build/Compile//在buil_dir下进行编译
$(MAKE) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include"MALLOC=libc
//编译时加入的参数,由于redis单独交叉编译需要这个参数,要不编译不过,所以的加上
endef
# Specify where and how to install the program. Since we only have one file,
# the helloworld executable, install it by copying it to the /bin directory on
# the router. The $(1) variable represents the root directory on the router running
# OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install
# directory if it does not already exist. Likewise $(INSTALL_BIN) contains the
# command to copy the binary file from its current location (in our case the build
# directory) to the install directory.
define Package/redis-server_x/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/redis-server $(1)/bin/ 这一步是最终需要到底打那个包, /buid_dir/redis_server_x/src/redis-server(可执行文件)
endef
//当然也可以写成redis-cli,即对client进行打包,但是redis_server_x名字需要换下,要不打出的包是客户端的,但是包的名字是redis-server_x,怪怪的
# This line executes the necessary commands to compile our program.
# The above define directives specify all the information needed, but this
# line calls BuildPackage which in turn actually uses this information to
# build a package.
$(eval $(call BuildPackage,redis-server_x)) //开始对redis-server_x这个文件夹进行打包, 最终会生成以这个文件夹为名字的ipk的包
我们可以看到 对package下的Ma文件夹进行编译
编译后,可以看到在build_dir下生成 redis_server_x这个文件夹,之后进入此文件夹发现以已经将Package/Ma/src里的东西都拷进来了,之后src目录下是编译后的一些文件,其中有redis-server
之后在bin/ramips/packages/base目录下可以看到生成的ipk redis_server_x_1_ramips_24kec.ipk
补充:
对redis数据库进行编译时,除了加参数MALLOC=libc外,还需要对redisXX/src/下的config.h文件 把宏 #define HAVE_PACKTRACE 1注释掉, 因为m7620A这个平台用的是uClib的库,redis用到了strace这些堆栈信息的函数,这些函数uClib没有实现,所以编译不过,但是如果用buildroot那就方便多了,可参考buildroot之交叉编译这篇文章