网站服务器购买,博学云网站建设,德州网站建设价格,亦庄网站建设价格背景 之前在做路由器工作时#xff0c;搞过一段时间openwrt#xff0c;最近看到之前写的笔记。整理一下#xff0c;希望能帮助一些朋友入坑。
熟悉openwrt openwrt之前并没有接触过#xff0c;其目录结构和linux也有所不同。先大致了解一下openwrt文件系统中各个目录的作用…背景 之前在做路由器工作时搞过一段时间openwrt最近看到之前写的笔记。整理一下希望能帮助一些朋友入坑。
熟悉openwrt openwrt之前并没有接触过其目录结构和linux也有所不同。先大致了解一下openwrt文件系统中各个目录的作用;
原始目录
scripts 存放了一些脚本使用了bash,Python,perf等多种脚本语言编译过程中用于第三方软件包管理的feeds文件也是在这个目录中当中在编译过程中使用的脚本也统一放在这个目录中。
tools 编译是主机需要使用一些工具软件tools里面包含了获取和编译这些工具的命令软件包里面有Makefile文件有的还包含了patch每个Makefile当中都有一句$(eval $(call HostBuild))这表明编译这个工具是为了在主机上使用的
config 存放着整个系统的配置文件其中包括Config-build.in Config-devel.in Config-images.in Config-kernel.in
docs 包含了整个宿主机的文件源码的介绍, 里面还有Makefile为目标系统生成docs.使用make -C docs/可以为目标系统生成文档
toolchain 包含了 kernel 头文件C库binutils, debugger等。
target openwrt的源码可以编译出各个平台适用的二进制文件个平台在这个目录里面定义了firmware和Kernel的编译过程。
package 存放了openwrt系统中适用的软件包,包含针对各个软件包的Makefile。openwrt定义了一套Makefile模板.各软件参照这个模板定义了自己的信息如软件包的版本、下载地址、编译方式、安装地址等。在二次开发过程中,这个文件夹我们会经常打交道.
事实上,通过
./scripts/feed update -a和
./scripts/feed install -a的软件包也会存放在这个目录之中.
include openwrt的Makefile都存放在这里。文件名为 *.mk 。这里的文件上是在Makefile里被include的,类似于库文件.这些文件定义了编译过程.
其他 主要目录就是前面提及的8个,剩下的是单个文件。
Makefile在顶层目录执行make命令的入口文件
rules.mk定义了Makefile中使用的一些通用变量和函数
Config.in在include/toplevel.mk中我们可以看到,这是和make menuconfig相关联的文件.
feeds.conf.default是下载第三方一些软件包时所使用的地址
LICENSE README即软件许可证和软件基本说明.其中README描述了编译软件的基本过程和依赖文件. 以上大致就是openwrt的原始目录其中需要我们关注的就是package目录我们添加应用时就需要在里面修改。
生成目录
feeds openwrt的附加软件包管理器的扩展包索引目录.有点绕,简单来说就是下载管理软件包的.默认的feeds下载有packages、management、luci、routing、telephony。如要下载其他的软件包需打开源码根目录下面的feeds.conf.default文件去掉相应软件包前面的#号然后更新源:
./scripts/feeds update -a
安装下载好的包:
./scripts/feeds install -a
build_dir 在前面的原始目录中,我们提到了host工具,toolchain工具还有目标文件.openwrt将在这个目录中展开各个软件包,进行编译.所以这个文件夹中包含3个子文件夹:
host 在该文件夹中编译主机使用的工具软件
toolchain-XXX 在该文件夹中编译交叉工具链
target-XXX 在此编译目标平台的目标文件,包括各个软件包和内核文件.
bin 保存编译完成后的二进制文件,包括:完整的bin文件,所有的ipk文件.
dl 在编译过程中使用的很多软件,刚开始下载源码并没有包含,而是在编译过程中从其他服务器下载的,这里是统一的保存目录
staging_dir 用于保存在build_dir目录中编译完成的软件.所以这里也和build_dir有同样的子目录结构。比如,在target-XXX文件夹中保存了目标平台编译好的头文件,库文件.在我们开发自己的ipk文件时,编译过程中,预处理头文件,链接动态库,静态库都是到这个子文件夹中。
tmp 从名字来看,是临时文件夹.在编译过程中,有大量中间临时文件需要保存,都是在这里.
logs 这个文件夹,有时可以看到,有时没有.这是因为这个文件夹保存的是,编译过程中出错的信息,只有当编译出错了才会出现.我们可以从这里获取信息,从而分析我们的软件编译为什么没有完成.
OpenWrt添加模块(package) OpenWrt是一个比较完善的嵌入式Linux开发平台在无线路由器应用上已有100多个软件包。人们可以在其基础上增加软件包以扩大其应用范围。 OpenWrt在增加软件方面极其方便按照OpenWrt的约定就可以很简单完成。加入的软件包可以是网上下载的开源软件或自行开发的软件。加入软件包需要在package目录下创建一个目录。然后创建一个Makefile与OpenWrt建立联系Makefile需要遵循OpenWrt的约定。另外可以创建一个patchs目录保存patch文件对下载的源代码进行修改。
创建Makefile 由于本文所建立的模块是基于luci的所以在OpenWrt的“package/feeds/luci”目录下建立“szloogson”目录,并创建Makefile文件。该文件的如下 # # Copyright (C) 2010-2014 Davied Huang Wich apple_guet126.com # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # include $(TOPDIR)/rules.mk PKG_NAME:luci-app-szloogson PKG_VERSION1.0 PKG_RELEASE:1 PKG_BUILD_DIR:$(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk define Package/luci-app-szloogson SECTION:luci CATEGORY:LuCI SUBMENU:3. Applications TITLE:shenzhou loogson for LuCI PKGARCH:all endef define Package/luci-app-njitclient/description This package contains LuCI configuration pages for shenzhou loogson. 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) \ CC$(TARGET_CC) \ CROSS_COMPILE$(TARGET_CROSS) \ ARCH$(ARCH) endef define Package/luci-app-szloogson/install #install shell $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/loogson.init $(1)/etc/init.d/loogson #install config $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./files/loogson.config $(1)/etc/config/loogson #install execute bin $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/gsc3280_led $(1)/usr/sbin/gsc3280_led #install luci mkdir -p $(1)/usr/lib/lua/luci/controller/admin $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller $(INSTALL_DATA) ./src/luci/controller/admin/loogson.lua $(1)/usr/lib/lua/luci/controller/admin/loogson.lua mkdir -p $(1)/usr/lib/lua/luci/model/cbi/admin_loogson $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi $(INSTALL_DATA) ./src/luci/model/cbi/admin_loogson/* $(1)/usr/lib/lua/luci/model/cbi/admin_loogson/ endef $(eval $(call BuildPackage,luci-app-szloogson)
说明
第8行“$(TOPDIR)/rules.mk”一般在Makefile的开头定义一些包的基本信息。 软件包的信息均以“PKG_”开头其意思和作用如下 PKG_NAME软件包名称将在menuconfig和ipkg可以看到。 PKG_VERSION软件版本号。 PKG_RELEASEMakefile的版本号 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 2.2.2、第17行“include $(INCLUDE_DIR)/package.mk” “include $(INCLUDE_DIR)/package.mk”一般在软件包的基本信息完成后再引入他定义了用户态软件包的规则。 编译包分为用户态和内核模块用户态软件包使用Package内核模块使用KernelPackage。“$(INCLUDE_DIR)/kernel.mk”文件对于软件包为内核时不可缺少“$(INCLUDE_DIR)/package.mk”应用在用户态。接下来讲述用户态软件包。用户程序的编译包以“Package/”开头然后接着软件名在Package定义中的软件名可以与软件包名不一样而且可以多个定义。
第19行”define Package/luci-app-szloogson,包的名称为”luci-app-szloogson“。 接下来定义的包括 SECTION包的类型预留。 CATEGORY分类在menuconfig的菜单下将可以找到。 SUBMENU包在make menuconfig的位置此处即在”LuCi/3. Applications“下。 TITLE用于软件包的简短描述将显示在”make menuconfig“中。 DESCRIPTION用于软件包的详细描述已放弃使用。如果使用DESCRIPTION将会提示“error DESCRIPTION: is obsolete, use Package/PKG_NAME/description”。 URL软件包的下载位置。 MAINTAINER维护者选项。 DEPENDS与其他软件的依赖。即如编译或安装需要其他软件时需要说明。如果存在多个依赖则每个依赖需用空格分开。依赖前使用号表示默认显示即对象没有选中时也会显示使用则默认为不显示即当依赖对象选中后才显示。
第27行”define Package/luci-app-szloogson/description“ 软件包的详细描述取代前面提到的DESCRIPTION详细描述。此处定义的信息将显示在”make menuconfig“中。
第31行”define Build/Prepare“ 编译准备方法对于网上下载的软件包不需要再描述。对于非网上下载或自行开发的软件包必须说明编译准备方法。本文所用的准备方法就是首先创建软件包目录然后将源码拷贝到刚刚创建的目录中。按OpenWrt的习惯一般把自己设计的程序全部放在src目录下。
第36行define Build/Configure” Build/Configure在Automake中需要进行“./configure”所以本配置方法主要针对需要配置的软件包而设计一般自行开发的软件包可以不在这里说明。本文设计的package由自己写makefile所以此处没有定义。
第39行”define Build/Compile“ 编译方法没有特别说明的可以不予以定义。如果不定义将使用默认的编译方法Build/Compile/Default。 自行开发的软件包可以考虑使用下面的定义 点击(此处)折叠或打开 define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) \ $(TARGET_CONFIGURE_OPTS) CFLAGS$(TARGET_CFLAGS) -I$(LINUX_DIR)/include endef 本文此处指定了交叉编译器和体系结构。
第46行”define Package/luci-app-szloogson/install“ 软件包的安装方法包括一系列拷贝编译好的文件到指定位置。调用时会带一个参数就是嵌入系统的镜像文件系统目录因此$(1)表示嵌入系统的镜像目录。一般可以采用下面的方法 点击(此处)折叠或打开 define Package/luci-app-szloogson/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/gsc3280_led $(1)/usr/sbin/ endef INSTALL_DIR、INSTALL_BIN在”$(TOPDIR)/rules.mk“文件中定义所以本Makefile必须引入$(TOPDIR)/rules.mk文件。 INSTALL_DIR :install -d -m0755创建所属用户可读写、执行其他用户可读可执行的目录。 INSTALL_BIN:install -m0755编译好的文件到镜像文件目录。 安装文件放在files子目录下不要与源代码文件目录“src”混在一起以提高可读性。 如果用户态软件在boot时要自动运行则需要在安装方法说明中增加自动运行的脚本文件安装和配置文件安装方法。 例如 点击(此处)折叠或打开 define Package/luci-app-szloogson/install #install shell $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/loogson.init $(1)/etc/init.d/loogson #install config $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./files/loogson.config $(1)/etc/config/loogson endef 使用清晰的文件扩展名更方便安装识别文件。 Package/$(PKG_NAME)/preinst 软件包安装前处理方法使用脚本语言因此定义的第一行需要下面的格式 #!/bin/sh调用时带入的参数为嵌入式系统的镜像目录。 Package/$(PKG_NAME)/postinst软件包安装后处理方法使用脚本语言。 Package/$(PKG_NAME)/prerm软件包删除前处理方法使用脚本语言 Package/$(PKG_NAME)/postrm软件包删除后处理方法使用脚本语言 程序接下来安装luci文件。
第66行”$(eval $(call BuildPackage,luci-app-szloogson))“ 完成前面定义后必须使用eval函数实现各种定义。其格式为 对于一般软件包$(eval $(call Package,$(PKG_NAME))) 或对于内核模块$(eval $(call KernelPackage,$(PKG_NAME))) 如果一个软件包有多个程序例如一个应用程序有自己的内核模块上面使用的“PKG_NAME”需要灵活变通。eval函数可能设计多个。也可以当成多个软件包处理。
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)模块名每个模块名以空格符分隔。即可同时装载多个内核模块。 在开发过程最好不要使用自动装载需经过严格调试后再使用可以减轻调试的工作量。 用户态的软件包中没有内核模块的“AUTOLOAD”参数。如果软件需要在boot时自动运行则需要在“/etc/init.d”增加相应的脚本文件。 脚本文件需要START参数说明在boot时的优先级如果在boot启动后再启动则需要STOP参数。如果STOP参数存在其值必须大于START。由“/etc/rc.d/S10boot”知道装载内核模块的优先级为10需要使用自己设计的内核模块的程序其START的值必须大于10。同样由“/etc/rc.d/S40network”知道使用网络通信的程序其START的值必须大于40。
3. 脚本文件 脚本文件需要start()和stop()两个函数start()是执行程序stop()是关闭程序。关闭程序一般需要执行killall命令。 在(一)中我们讨论了点击“应用”后执行的脚本文件在“/etc/init.d/loogson”目录下程序如下
点击(此处)折叠或打开 #!/bin/sh /etc/rc.common # (C) 2014 openwrt.org # add by Davied Huang apple_guet126.com START50 LED_BIN/usr/sbin/gsc3280_led control_board() { local ledstatus, lednum; config_get_bool ledstatus $1 ledstatus config_get lednum $1 lednum echo ${lednum} ${ledstatus} ${LED_BIN} ${lednum} ${ledstatus} } start() { config_load loogson config_foreach control_board controlboard } stop() { config_load loogson #config_foreach stop_instance controlboard }
说明
在“start”函数中首先使用“config_load”函数加载“/etc/config/”目录下的loogson配置文件。“config_foreach”遍历/etc/init.d/loogson配置文件中的Section并且执行control_board函数。在control_board函数中使用“config_get_bool”获得操作LED的开关状态config_get获得操作第几个LED。config_load、“config_foreach”、“config_get”和“config_get_bool”等函数由其他脚本提供可以直接使用。最后执行可执行文件后面加上可执行文件需要的参数。该可执行文件的源码为 #includestdio.h #includeunistd.h #includefcntl.h #includeasm/ioctl.h int main(int argc,char *argv[]) { int fd; if (argc ! 3) { printf(wrong cmd!\n); } fd open(/dev/led, O_RDWR); if(fd -1){ printf(open led failed!\n); } ioctl(fd, argv[1], argv[2]); close(fd); return 0; }