Openwrt 学习记录:openWRT添加用户模块-helloword(四)

      外国人的helloworld:https://www.componentality.com/res/Step-By-Step-Instruction-To-Run-Apps-On-FlexRoad-HW.en.pdf  

     加 入的软件包可以是网上可下载的开源软件或自行开发的软件。為加入软件包需要在package目錄下创建一个目录,以包含软件包的各种信息和与 OpenWrt建立联系的文件。然后创建一个Makefile与OpenWrt建立联系,Makefile需要遵循OpenWrt的约定。另外可以創建一 個patchs目錄保存patch文件,對下載的源代碼進行適量修改。下面主要介紹Makefile的基本約定。

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、编写软件包的基本信息

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

PKG_NAME 表示软件包名称,将在menuconfig和ipkg可以看到。
  PKG_VERSION   表示软件版本号。
PKG_RELEASE 表示Makefile的版本号
PKG_SOURCE 表示源代码的文件名。
PKG_SOURCE_URL 表示源代码的下载网站位置。@SF表示在sourceforge网站,@GNU表示在GNU网站,還有@GNOME、@KERNEL。獲取方式可以 為:git、svn、cvs、hg、bzr等。有關下載方法可參考$(INCLUDE_DIR)/download.mk和$(SCRIPT_DIR) /download.pl。
PKG_MD5SUM 表示源代码文件的效验码。用于核对软件包是否正确下载。
PKG_CAT 表示源代码文件的解压方法。包括zcat, bzcat, unzip等。
PKG_BUILD_DIR 表示软件包编译目录。它的父目录为$(BUILD_DIR)。如果不指定,默认为$(BUILD_DIR)/$( PKG_NAME)$( PKG_VERSION)。
  還有一些有關源代碼的定義。
PKG_SOURCE_SUBDIR
PKG_SOURCE_PROTO
PKG_SOURCE_MIRROR
PKG_MIRROR_MD5SUM
PKG_SOURCE_VERSION

3、编译包定义

用户程序和内核模块的定义不一样。用戶態軟件包使用Package,內核模塊使用KernelPackage。

3.1用户程序编译包定义

     用户程序的编译包以Package/开头,然后接着软件名,在Package定义中的软件名可以与软件包名不一样,而且可以多个定义。下面使用$(PKG_NAME)只是做一个标示,并非真正使用$(PKG_NAME)。
Package/$(PKG_NAME)
SECTION 表示包的类型,预留。
CATEGORY 表示分类,在menuconfig的菜单下将可以找到。
TITLE 用于软件包的简短描述
DESCRIPTION 用于软件包的详细描述,已放弃使用。如果使用DESCRIPTION將會提示“error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description”。
URL 表示软件包的下载位置。
MAINTAINER 表示维护者,选项。
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/Configure
在Automake中需要进行./configure,所以本配置方法主要针对需要配置的软件包而设计,一般自行开发的软件包可以不在这里说明。需要使用本定义的情况,可参考 dropbear。
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_BIN) $(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 软件包删除后处理方法,使用脚本语言

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)模 块名,每个模块名以空格符分隔。即可同时装载多个内核模块。
在开发过程最好不要使用自动装载,經過嚴格調試後再使用,可以減輕調試的工作量。

4、使用定义

完成前面定义后,必须使用eval函数实现各种定义。其格式为:
对于一般软件包 $(eval $(call Package,$(PKG_NAME)))
或对于内核模块 $(eval $(call KernelPackage,$(PKG_NAME)))
       如果一個軟件包有多個程序,例如:一個應用程序有自己的內核模塊,上面使用的PKG_NAME需要靈活變通。eval函數可能設計多個。也可以當成多個軟件包處理。

Helloword expample:
下面具体说下,如何编译一个helloword的软件包。
(1)首先,编写helloworld程序

/****************
* Helloworld.c
* The most simplistic C program ever written.
* An epileptic monkey on crack could write this code.
*****************/
#include <stdio.h>
#include <unistd.h>
int main(void)
{
    printf("Hell! O' world, why won't my code compile?\n\n");
    return 0;
}

编写Makefile文件
# build helloworld executable when user executes "make"
helloworld: helloworld.o
     $(CC) $(LDFLAGS) helloworld.o -o helloworld
helloworld.o: helloworld.c
     $(CC) $(CFLAGS) -c helloworld.c
# remove object files and executable when user executes "make clean"
clean:
    rm *.o helloworld

在 这两个文件的目录下,执行make 应该可以生成helloworld的可执行文件。执行helloworld后,能够打印出 “Hell! O' world, why won't my code compile?”。这一步,主要保证我们的源程序是可以正常编译的。下面我们 将其移植到OpenWRT上。
(2)将OpenWrt-SDK-brcm47xx-for-Linux-x86_64-gcc-4.3.3+cs_uClibc-0.9.30.1.tar.bz2解压
tar –xvf OpenWrt-SDK-brcm47xx-for-Linux-x86_64-gcc-4.3.3+cs_uClibc-0.9.30.1.tar.bz2
(3)进入SDK
cd OpenWrt-SDK-brcm47xx-for-Linux-x86_64-gcc-4.3.3+cs_uClibc-0.9.30.1
可以看到里面的目录结构跟我们之前source的目录结构基本相同,所需要编译的软件包,需要放置在package目录下
(4)在package目录下创建helloworld目录
     cd package
    mkdir helloworld
    cd helloworld

(5)创建src目录,拷贝 helloworld文件
    mkdir src
    cp /home/wrt/test/helloworld.c src
    cp /home/wrt/test/Makefile src

(6)在helloworld目录下创建Makefile文件
这个Makefile文件是给OpenWRT读的,而之前写的那个Makefile文件是针对helloworld给编译其读的。两个Makefile不在同一层目录下。
touch Makefile
vim Makefile
Makefile文件模板内容如下:(可以参考其他package 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:=helloworld
PKG_RELEASE:=1

# 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

# 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/helloworld
    SECTION:=utils
    CATEGORY:=Utilities
    TITLE:=Helloworld -- prints a snarky message
endef

# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above
define Package/helloworld/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 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/helloworld/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/
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,helloworld))
  也可以参考:http://wiki.openwrt.org/doc/devel/packages
(7)返回到SDK的根目录
执行make进行编译
编译过程会在build_dir目录下完成
编译结果会放在 bin/[yourtarget]/package目录下helloworld_1_bcm47xx.ipk
(8)上传helloworld_1_bcm47xx.ipk
使用sftp软件上传helloworld_1_bcm47xx.ipk至路由器
执行 opkg install helloworld_1_bcm47xx.ipk
输入hello然后按Tab键,发现openwrt中已经有helloworld可执行命令。

另外修改toolchain方式

 参考:http://blog.chinaunix.net/uid-26675482-id-4534627.html

一、交叉编译

1. 建立交叉编译环境 

编译环境手工也可以建立,不过要涉及到很多开发包的安装和编译,比较繁杂琐碎,因此,我们偷个懒,直接使用OpenWrt源码编译环境中的toolchain工具链。
通常我们对openwrt进行编译之后,在buildroot目录下会有一个名叫staging_dir的目录,针对当前平台的toolchain都在这个目录下,请务必及时做好备份保存。 
1.1增加toolchain的目录到PATH目录中
PATH=$PATH:/home/appdevp/openWrt/trunk/staging_dir/toolchain-i386_gcc-4.6-linaro_uClibc-0.9.33.2/bin/ 
1.2 增加staging_dir的目录到toolchain PATH 
export STAGING_DIR=/home/appdevp/openWrt/trunk/staging_dir/ 

2. 编译 

2.1 configure 
./configure–target=i486-openwrt-linux-uclibc 
2.2 make 
make CC=i486-openwrt-linux-uclibc-gcc LD=i486-openwrt-linux-uclibc-ld 

二、编译ipk包

1. 编译SDK

在buildroot目录下make menuconfig,然后选中SDK进行编译
编译完成后,对应生成的SDK会出现类似这样的目录:“openWrt/trunk/bin/x86”,进入SDK后,打印当前工作路径如下:
“/openWrt/trunk/bin/x86/OpenWrt-SDK-x86-for-redhat-x86_64-gcc-4.6-linaro_uClibc-0.9.33.2” 

2. 创建工程

在sdk的package目录下创建我们的工程“helloworld”:
新建目录中包含src目录,这个目录就是我们的源代码所在地,另外一个非常重要的文件Makefile,这个Makefile的组成与GNU的有所不同,有点类似于制作rpm包时的spec 文件。到后面会有更详细的介绍。具体参见上文例子。
 

3. 编译 

将当前目录返回到SDK:执行make进行编译。如果一切顺利,最后的结果会保存在SDK/bin/x86/packages目录下,名称为helloword_1_x86.ipk。 

4. 安装最新编译的包 

通过scp将该包拷贝到目的机器上,通过opkg包管理工具进行安装:  opkg install helloworld_1_x86.ipk 


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值