MT7688学习笔记(3)——定制OpenWrt系统及添加自开发软件

一、将文件直接编译进OpenWrt固件中

在源码目录下创建“files”目录,这个目录可以看成是根目录的映射,只要将要打包到固件的文件按照根目录的目录结构存放文件即可。

例如:
1.修改network配置文件源码固件
Ubuntu中openwrt-hiwooya-stable/files/etc/config/network <-----对应-----> 嵌入式系统中/etc/config/network

2.添加可执行文件setwifi
Ubuntu中openwrt-hiwooya-stable/files/usr/sbin/setwifi <-----对应-----> 嵌入式系统/usr/sbin/setwifi

二、添加软件包ipk的方法

2.1 简介

OpenWrt 是一个比较完善的嵌入式Linux开发平台,在无线路由器应用上已有4000多个软件包。用户可以按照OpenWrt的约定增加开源软件或自行开发的软件。加入软件包需要在package目录下创建一个目录,以包含该软件包的各种信息和与OpenWrt建立联系的文件。然后创建一个Makefile与OpenWrt建立联系,Makefile需要遵循OpenWrt的约定。另外可以创建一个patchs目录保存patch文件,对下载的源代码进行适量修改。

2.2 Makefile语法

2.2.1 引入文件

OpenWrt使用三个Makefile的子文件,分别为:

include $(TOPDIR)/rules.mk

include $(INCLUDE_DIR)/kernel.mk

include $(INCLUDE_DIR)/package.mk

由这些Makefile子文件确定软件包加入OpenWrt的方式和方法。$(TOPDIR)/rules.mk一般在Makefile的开头,$(INCLUDE_DIR)/kernel.mk文件对于软件包为内核时是不可缺少的,$(INCLUDE_DIR)/package.mk一般在软件包的基本信息完成后再引入。

2.2.2 编写软件包的基本信息

软件包的信息均以PKG_开头,其意思和作用如下:

  • PKG_NAME 表示软件包名称,将在menuconfig和ipkg可以看到。
  • PKG_VERSION 表示软件包版本号。
  • PKG_RELEASE 表示Makefile的版本号。
  • PKG_SOURCE 表示源代码的文件名。
  • PKG_SOURCE_URL 表示源代码的下载网站位置。@SF表示在sourceforge网站,@GNU表示在GNU网站,还有@GONE、@KERNEL。
  • PKG_MD5SUM 表示源代码文件的校验码。用于核对软件包是否下载正确。
  • PKG_CAT 表示源代码文件的解压方法。包括zcat,bzcat,unzip等。
  • PKG_BUILD_DIR 表示软件包编译目录。它的父目录为$(BUILD_DIR)。如果不指定,默认为$(BUILD_DIR)/$(PKG_NAME)/$(PKG_VERSION)。

2.2.3 编译包定义

应用程序和内核驱动模块的定义不一样。应用程序软件包使用Package,内核驱动模块使用KernelPackage。

2.2.3.1 应用程序编译包定义

应用程序的编译包以Package/开头。然后接着软件名,在Package定义中的软件名可以与软件包名不一样,而且可以多个定义。下面使用$(PKG_NAME)只是做一个标志,并非真正使用$(PKG_NAME),如Package/$(PKG_NAME)。

  • SECTION 表示包的类型,预留。
  • CATRGORY 表示分类,在make menuconfig的菜单下将可以找到。
  • TITLE 用于软件包的简短描述。
  • DESCRIPTION 用于软件包的详细描述,已放弃使用。如果使用DESCRIPTION将会提示“error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description”。
  • URL 表示软件包的下载位置。
  • MAINTAIER 表示维护者,选项。
  • DEPENDS 表示与其他软件的依赖。即编译或安装其他软件时需要说明。如果存在多个依赖,则每个依赖需要用空格分开。依赖前使用+号表示默认为显示,即对象没有选中时也会显示,使用@则默认为不显示,即当依赖对象选中后才显示。

在用户空间的应用程序软件包中没有内核驱动模块的AUTOLOAD参数。如果应用软件需要在boot时自动运行,则需要在/etc/init.d中增加相应的脚本文件。脚本文件需要START参数,说明在boot时的优先级,如果在boot过程启动后再关闭,则需要进一步设置STOP参数。如果STOP参数存在,其值必须大于START。脚本文件需要start()和stop()两个函数,start()是执行程序,stop()是关闭程序。关闭程序一般需要执行killall命令。由/etc/rc.d/S10boot知道,装载内核驱动模块的优先级为10,需要使用自己设计的内核驱动模块的程序其START的值必须大于10。同样由/etc/rc.d/S40network知道,使用网络通信的程序其START的值必须大于40。

  • Package/$(PKG_NAME)/conffiles 本包安装的配置文件,一行一个。如果文件结尾使用/,则表示为目录。用于备份配置文件说明,在sysupgrade命令执行时将会用到。
  • Package/$(PKG_NAME)/description 软件包的详细描述,取代前面提到的DESCRIPTION详细描述。
  • Build/Prepare 编译准备方法,对于网上下载的软件包不需要再描述。对于非网上下载或自行开发的软件包必须说明编译准备方法。一般的准备方法为:
define Build/Prepare
    mkdir -p $(PKG_BUILD_DIR)
    $(CP) ./src/* $(PKG_BUILD_DIR)/
endef

按OpenWrt的习惯,一般把自己设计的程序全部在src目录下。

  • Build/Compile 编译方法,没有特别说明的可以不予以定义。如果不定义将默认使用编译方法Build/Compile/Default。
    自行开发的软件包可以考虑使用下面的定义。
define Build/Compile
    $(MAKE) -C $(PKG_BUILD_DIR) \
    $(TARGET_CONFIGURE_OPTS)   CFLAGS="$(TARGET_CFLAGS) -I $(LINUX_DIR)/include"
endef
  • Package/$(PKG_NAME)/install 软件包的安装方法,包括一系列拷贝编译好的文件到指定位置。调用时会带一个参数,就是嵌入式系统的镜像文件系统目录,因此$(1)表示嵌入式系统的镜像目录。一般可以采用下面的方法:
define Package/$(PKG_NAME)/install
    $(INSTALL_DIR) $(1)/usr/bin
    $(INSTALL_DIR) $(PKG_BUILD_DIR)/ $(PKG_NAME) $(1)/usr/bin/
endef

INSTALL_DIR、INSTALL_BIN在$(TOPDIR)/rules.mk文件定义,所以本Makefile必须引入$(TOPDIR)/rules.mk文件。
INSTALL_DIR:=install -d -m0755 意思是创建所属用户可读写和执行,其他用户可读可执行的目录。
INSTALL_BIN:=install -m0755 意思是编译好的文件存放到镜像文件目录。
如果用户空间的应用软件在boot时要自动运行,则需要在安装方法说明中增加自动运行的脚本文件安装和配置文件安装方法。
例如:

define Package/mountd/install
    $(INSTALL_DIR) $(1)/sbin/ $(1)/etc/config/ $(1)/etc/init.d/
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/mountd $(1)/sbin/
    $(INSTALL_DATA) ./files/mountd.config $(1)/etc/config/mountd
    $(INSTALL_BIN) ./files/mountd.init $(1)/etc/init.d/mountd
endef

安装文件放在files子目录下,不要与源代码文件目录src混在一起,以提高可读性。使用清晰的文件扩展名,更方便安装识别文件。

  • Package/$(PKG_NAME)/preinst 软件包安装前处理方法,使用脚本语言,因此定义的第一行需要下面的格式
    #!/bin/sh
    调用时带入的参数为嵌入式系统的镜像目录。
  • Package/$(PKG_NAME)/postinst 软件包安装后处理方法,使用脚本语言。
  • Package/$(PKG_NAME)/prerm 软件包删除前处理方法,使用脚本语言。
  • Package/$(PKG_NAME)/postrm 软件包删除后处理方法,使用脚本语言。

2.2.3.2 内核驱动模块包定义

Linux分为内核空间和用户空间。开发者开发的内核部分可以直接加入Linux的Kernel程序,也可以生成内核模块以便需要时装入内核。OpenWrt一般希望开发者生成内核模块,在Linux启动后自动装载或手工使用insmod命令装载。内核模块使用KernelPackage开头,其他与一般应用软件包基本相同。
在内核驱动模块定义中增加了:

  • SUBMENU 表示子菜单位置,在$(INCLUDE)/kernel.mk对内核模块定义了CATEGORY为kernel modules,所以内核模块在menuconfig中的主菜单为kernel modules,然后有下一级子菜单$(SUBMENU)。在子菜单下可以看到以kmod-$(PKG_NAME)项目。
  • DEFAULT 表示直接编入内核或产生内核模块,y表示直接编入内核,m表示产生内核模块。
  • AUTOLOAD 表示自动装入内核,一般表示方法为:
    AUTOLOAD:=$(call AutoLoad, $(PRIORITY),$(AUTOLOAD_MODS))
    AutoLoad的第一个参数$(PRIORITY)为优先级,01为最优先,99为最后装载。有关自动装载可以在/etc/modules.d目录下看到,第二个参数$(AUTOLOAD_MODS)模块名,每个模块名以空格符分隔。即可同时装载多个内核模块。
    在开发过程最好不要使用自动装载,经过严格调试后再使用,可以减轻调试的工作量。

2.2.4 使用定义

完成前面定义后,必须使用eval函数实现各种定义。其格式为:
对于一般应用软件包
$(eval $(call Package, $(PKG_NAME)))
或对于内核驱动模块
$(eval $(call KernelPackage, $(PKG_NAME)))
如果一个软件包有多个程序,例如:一个应用程序有自己的内核驱动模块,上面使用PKG_NAME需要灵活变通。eval函数可以设计多个。也可以当成多个软件包处理。

2.3 写Makefile文件

在openwrt-hiwooya-stable-master/package/cpp(你的程序文件夹名)/src下创建一个Makefile,用于编译该应用程序。

# build helloworld executable when user executes "make"  

LDFLAGS += -L$(TOPDIR)/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/lib/mysql
LDFLAGS += -L$(TOPDIR)/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/lib/libevent
LDFLAGS += -L$(TOPDIR)/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/lib/ -lstdc++ -Wno-explicit

LDFLAGS += -L$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/libjsoncpp/

LIBS += -lmysqlclient -lpthread  -lrt -lcurl -ljsoncpp -levent

CXXFLAGS += -I$(TOPDIR)/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/include/mysql
CXXFLAGS += -I$(TOPDIR)/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/include/libevent
CXXFLAGS += -I$(TOPDIR)/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/include
#CXXFLAGS += -I$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/json-c-0.12
CXXFLAGS += -I$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/libjsoncpp/include/
CXXFLAGS += -std=c++11

OBJ=cpp.o common.o Serial.o protocol.o CHttpClient.o  \
    CSocket.o CUDPSocket.o DALReceive.o SocketSend.o DALSend.o Central.o CMsg.o  \
    DALBase.o  CustomMessage.o HCIModule.o HCIMatch.o \
    SQLBase.o HCIServiceObject.o SQLServiceObject.o HCIEvent.o SQLEvent.o \
    HCIGateway.o SQLGateway.o Gateway.o \
    HCIIfttt.o SQLIfttt.o HCIAction.o SQLAction.o HCIDebug.o ServiceObject.o CustomCfg.o \
    Load.o Event.o HandleThread.o HCIIftttLog.o SQLIftttLog.o Action.o \
    Ifttt.o IftttLog.o Timer.o JsonVector.o HttpServer.o WebServer.o TimerThread.o Buffer.o 
    
cpp: $(OBJ)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) $(LIBS) $(OBJ) -o $@
    
%.o: %.cpp
    $(CXX) $(CXXFLAGS) $(LDFLAGS) $(LIBS) -c $< -w

    
# remove object files and executable when user executes "make clean"  
clean:  
    rm *.o cpp  

在openwrt-hiwooya-stable-master/package/cpp(你的程序文件夹名)下创建一个Makefile,用于将该应用程序编译进OpenWrt系统。

##############################################  
# OpenWrt Makefile for cpp 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                  // 必须引入$(TOPDIR)/rules.mk文件
  
# Name and release number of this package  
PKG_NAME:=cpp                               // 软件包名称
PKG_RELEASE:=1                              // Makefile的版本号
  
  
# 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)   // 软件包编译目录
  
  
include $(INCLUDE_DIR)/package.mk           // 引入$(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/cpp
    SECTION:=utils                          // 包的类型
    CATEGORY:=Utilities                     // 包的分类,在make menuconfig的菜单下将可以找到。
                                            // 与其他软件的依赖
    DEPENDS:=+libmysqlclient +libpthread +libreadline +libstdcpp +librt +libcurl +libjsoncpp +libevent2
    TITLE:=alm-tn01                         // 软件包的简短描述
endef
  
  
# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above  
define Package/cpp/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                       // 自行开发软件包的编译准备方法
    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  
  
  
# Specify where and how to install the program. Since we only have one file,  
# the cpp 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/cpp/install                // 软件包的安装方法
    $(INSTALL_DIR) $(1)/bin
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/cpp $(1)/bin/

    $(INSTALL_DIR) $(1)/etc/init.d        // 自动运行的脚本文件安装和配置文件安装方法
    $(INSTALL_BIN) ./files/cpp.init $(1)/etc/init.d/cpp
    $(INSTALL_DIR) $(1)/etc/app
endef
  
  
# 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,cpp))          // 使用定义

2.4 编译应用程序

  1. 将应用程序的整个文件传到OpenWrt系统源码的openwrt/package目录下,然后进入OpenWrt系统源码的顶层目录,执行make menuconfig
  2. 在弹出的菜单选项中,首先进入Utilities选项。


    Utilities
  3. 接着就能看到我们自己写的应用程序的选项如cpp,将该选项配置进系统,即选为*。


    cpp
  4. 接下来,退出保存,并重新编译系统make V=99
  5. 编译完成后,新生成的固件里面,就已经包含了我们的应用程序了。

2.5 编译可执行文件

  1. 将应用程序的整个文件传到OpenWrt系统源码的openwrt/package目录下,然后进入OpenWrt系统源码的顶层目录,执行make package/cpp/compile V=99
  2. 编译会在/work/openwrt-hiwooya-stable-master/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/cpp目录下进行。
  3. 最终在/work/openwrt-hiwooya-stable-master/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/cpp目录下生成名为cpp的可执行文件(根据Makefile来生成的)。
  4. 将可执行文件编译进OpenWrt固件中,见上面 一、将文件直接编译进OpenWrt固件中

• 由 Leung 写于 2018 年 8 月 23 日

• 参考:F403科技创意室(www.f403tech.com)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,050评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,538评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,673评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,622评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,047评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,974评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,129评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,893评论 0 209
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,654评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,828评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,297评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,619评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,326评论 3 243
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,176评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,975评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,118评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,909评论 2 278

推荐阅读更多精彩内容