改源码的话,在feeds/luci/collections/luci文件夹下面Makefile文件里面,找到LUCI_DEPENDS这一项,替换luci-theme-bootstrap为你想要的主题,里填入luci-theme-material,然后重新更新安装feeds,在make menuconfig里面就默认选中你要的主题了,也会默认启用。
修改编译出来的文件名
vi include/image.mk
找到
IMG_PREFIX:=openwrt-$(if $(CONFIG_VERSION_FILENAMES),$(VERSION_NUMBER)-)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))
修改为
IMG_PREFIX:=$(shell date +%Y%m%d-%H%M%S)-openwrt-$(if $(CONFIG_VERSION_FILENAMES),$(VERSION_NUMBER)-)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))
或者
sed -i 's/IMG_PREFIX:=openwrt/IMG_PREFIX:=$(shell date +%Y%m%d-%H%M%S)-openwrt/g' include/image.mk
先说个坑,烧了固件之后,WAN口改变,并不是左边独立出来的第一个,我的变成了最右边的那个。所以,如果通过uboot烧固件,怎么都不成功的话,多试试其它网口。硬件部分在图片的基础上略有改动,这个板子有两个串口(就图上的两个),我的板子把串口2卸了,装了个数码管,可以实时统计WIFI设备的连接数量。
好了,我接下来就说说我自己的研究过程心得。
OpenWrt的准备工作我就不详细介绍了,我直接说说我自己的环境吧,还有中途我遇到的一些坑。我会给一些参考链接,不明白的可以参考别人写的比较详细的内容。
1、Linux环境 (Ubunut 16.04)
推荐Ubuntu16.04,我就是使用的Ubuntu16.04,搭配的VMware虚拟机。本来我自己的主机是Kali2016.1_x64,一开始想直接用Kali编译,结果变异过程特别艰难,头文件好多函数名不一样,修改了4、5个头文件,还是编译没出固件,所以不推荐使用Kali,其它的没用过,看了网上的回馈Ubuntu12.04应该也还可以。
2、安装依赖库
apt-get install g++apt-get install libncurses5-devapt-get install zlib1g-devapt-get install bisonapt-get install flexapt-get install unzipapt-get install autoconfapt-get install gawkapt-get install makeapt-get install gettextapt-get install gccapt-get install binutilsapt-get install patchapt-get install bzip2apt-get install libz-devapt-get install asciidocapt-get install subversionapt-get install libssl-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
或者
apt-get install g++ libncurses5-dev zlib1g-dev bison flex unzip autoconf gawk make gettext gcc binutils patch bzip2 libz-dev asciidoc subversion libssl-dev
1
网上很多都少了安装libssl-dev这个库,也可能是Ubuntu16.04的需要手动安装一下,这里需要注意一点。
3、下载OpenWrt项目
我下载的是 Trunk版
自己想要什么版本,可以直接上官方找找,链接: http://git.openwrt.org/
在Linux系统里直接git下来就好了
$ git clone git://git.openwrt.org/openwrt.git
1
4、更新软件包
进入openwrt项目的目录执行下面两条命令
$ ./scripts/feeds update –a$ ./scripts/feeds install –a.
1
2
5、配置编译配置文件
首先需要生成配置文件,是一个在openwrt根目录下的隐藏文件“.config”
$ make defconfig
1
这条命令会检查编译环境,如果安装包没安装好,这一步会有提示,然后自行安装就Ok
接下来就可以开始定制自己想要的标准功能了
$ make menuconfig
1
这条命令是在控制台生成的图形化配置窗口,进入之后就能配置自己的固件了,对应固件的硬件信息,标准软件包,一目了然。熟悉之后,配置完成,保存,会自动在OpenWrt目录配置隐藏的”.config”文件。接下来就可以编译了。
6、编译
简单介绍几个常用编译参数以及效果
$ make // 直接编译,全都使用默认参数$ make -j8 // -j表示启动多线程编译,8表示8条线程$ make V=s // 编译过程打印输出变异过程,如果编译失败,使用这条命令,可以看到出错详细信息,最好和 -j1联用$ make package/xxx // 指定编译软件包,最终生成*.ipk,在bin/目录,编译完成拷贝到路由器使用 opkg install *.ipk进行安装
1
2
3
4
生成的文件,在OpenWrt的bin/目录下,虽然我的板子用的是MT7688,但在实际编译时我配置的目标是MT7628。在目录下会生成很多个*.bin文件,烧录的时候,烧录openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin
第一次接触,这里还有一个点需要注意
在编译完成之后,如果发现没有生成想要的openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin这个文件。
可能是因为生成的包大小超过了,比如说我想直接在路由器里进行开发,选择编译了,编译出来的包有20+M,但我的路由器是根本装不下的,OpenWrt项目会自动判断,就算生成了这个包,你也无法安装,是无效的,就不会生成这个*.bin文件。所以在自定义配置的时候,还是根据需求自己选择必须的功能就好。如果真的就想生成这么大的固件,这个问题我想应该也是可以突破的,不过我还没有研究。
既然是做二次开发,那我们总不能写个程序编译了一个一个路由器里把程序拷贝进去,我们就需要把程序一起编译进固件,烧完路由器,程序也就自然安装好了。
关于如何把自己写的代码编译到固件里其实也很简单。
这里先推荐两篇文章
OpenWRT Makefile框架以及Kernel和firmware生成过程分析
http://www.cnblogs.com/sammei/p/3968916.html
OpenWrt上用C来写一个Helloworld http://scateu.me/2016/12/03/openwrt-helloworld.html
通过上两篇文章,我再把我汲取到的知识简要的分享一下,不懂的可以在博客留言
首先,生成*.ipk包的源文件都是存在于package目录下的
配置.config编译配置文件的时候,会扫描所有目录的makefile文件,那么我们只需要按照OpenWrt给我们的规则来配置makefile文件就行Ok.
我以一个helloword的例子讲述一下这个过程。
在package目录下创建一个helloworld文件夹
openwrt/package/helloworld├── Makefile// 暂且称为root_Makefiel└── src├── helloworld.c└── Makefile// 暂且成为src_Makefile
1
2
3
4
5
在root_Makefile写入内容 (这里的root_Makefile表示的是外部的Makefile,注意看上一段的注释)
include $(TOPDIR)/rules.mkPKG_NAME:=helloworldPKG_RELEASE:=1PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)include $(INCLUDE_DIR)/package.mk# 这里的宏配置的是在 make menuconfig 中的选项define Package/helloworldSECTION:=utilsCATEGORY:=UtilitiesTITLE:=Helloworldendefdefine Build/Preparemkdir -p $(PKG_BUILD_DIR)$(CP) ./src/* $(PKG_BUILD_DIR)/endefdefine Package/helloworld/install$(INSTALL_DIR) $(1)/bin$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/endef$(eval $(call BuildPackage,helloworld))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
然后在src/helloworld.c里写一个标准教科书版本的 helloword
#include int main(){printf("hello world\");return 0; }
1
2
3
4
5
6
7
再写一下编译程序的src_Makefile
helloworld: helloworld.o$(CC) $(LDFLAGS) helloworld.o -o helloworldhelloworld.o: helloworld.c$(CC) $(CFLAGS) -c helloworld.cclean:rm *.o helloworld
1
2
3
4
5
6
7
OK.这样就可以编译了
启动OpenWrt的编译配置
~$ make menuconfig
1
我们刚写好的程序,在选项Utilities->helloworld,选中,保存,退出
执行make,就能直接把程序编译到固件里
测试程序也可以先把程序编译成*.ipk包,然后放到路由器里opkg install helloworld.ipk先安装测试一下,再编译固件。
自启动脚本的编译也可以按照上面的思路来进行,最后添加到启动项的时候,只需要在外部Makefile里添加把脚本拷贝到系统目录/etc/init.d/的命令就可以,虽然我小测无果,但我相信这个思路肯定没问题。
我这里说另一种更直接粗暴简单的方法。
将脚本文件放到这个目录下,并且添加可执行权限。
package/base-files/
1
这是编译固件的一个基础文件目录,就是说,所有固件中都会包含这个文件夹里的内容。
我就用我的数码管实时显示WIFI用户数量的脚本来说。
我的程序目录结构是这样的
/├── etc│└──count_number└── usr└── share└──count_number└──count_number.sh
1
2
3
4
5
6
7
就只有两个文件
/usr/share/count_number/count_number.sh是我获取WIFI客户连接数量并输出到数码管的脚本实现
/etc/init.d/count_number 是开机启动脚本,实际上的开机启动脚本存在于/etc/rc.d目录下,这个目录我们不用管,他会自动帮我们拷贝/etc/init.d/目录下的文件过去
/etc/init.d/count_number 脚本代码
#!/bin/sh /etc/rc.common# Copyright (C) 2017 www.wangsansan.comSTART=50start() {/usr/share/count_number/count_number.sh &}
1
2
3
4
5
6
7
8
OK,把文件按照目录结构放到package/base-files/文件夹下,并添加可执行权限
这样就完成了。
编译,就直接把脚本编译进固件里了。
好的,固件定制结束了,那就定制一下web页面,先登陆到路由器web页面看看
上图蓝色部分包含超链接、版权支持信息文字和版本信息
看到图,第一个思路,找到Luci的安装目录,再从所有文件中搜索上面那串文字,
如果第一次玩OpenWRT不知道Luci安装目录,可以先找到index.html文件,因为Luci使用的是Lua脚本跑的,所以找到之后,cat查看或者用vim打开index.html,就能找到Luci安装目录。当然,也可以直接在根目录“/”执行查找命令,不过时间会比较漫长。
一般来说Luci的安装目录都是 “/usr/lib/lua/luci”
执行下面的命令。
root@OpenWrt:~# cd /usr/lib/lua/luciroot@OpenWrt:/usr/lib/lua/luci# find ./ -name "*" | xargs grep -Hn "Powered by"
1
2
解释一下参数含义,find 命令就不说了
xargs 将stdout输出流测内容传到stdin当作下一条命令的参数
grep
-H //打印文件名
-n //打印行号
返回结果
root@OpenWrt:/usr/lib/lua/luci# find ./ -name "*" | xargs grep -Hn "Powered by"./view/themes/bootstrap/footer.htm:17:Powered by () / root@OpenWrt:/usr/lib/lua/luci#
1
2
3
找到那么,vim 打开文件 “./view/themes/bootstrap/footer.htm”
修改第17行,对比原文,分析一下这行html代码什么意思
## 原文 ##Powered by LuCI Master (git-17.246.24307-3e1ae70) / OpenWrt Designated Driver r49395## HTML 标签,方便观看,分成三行 ##Powered by () /
1
2
3
4
5
6
7
8
一眼看过去,嗯,用眼睛翻译一下
Powered by () / 变量1 = "LuCI Master"变量2 = "git-17.246.24307-3e1ae70"变量3 = "OpenWrt Designated Driver r49395"且 不包含超链接。
1
2
3
4
5
6
既然知道怎么回事,改起来方法就很多了。
1、可以直接修改变量内容;
2、直接修改此处的html内容;
为了方便,我就直接修改html吧,超链接跳转到我的博客地址,并且居中显示
Powered by WangSansan
1
看看结果
好了,底部部分完成。
LOGO部分,不知道是图片还是纯文字,页面上右键查看源代码,或者直接把页面另存到桌面
查看html,18行
OpenWrt
1
可以看到是文字Logo,如果是图片或许还方便一些,直接把logo替换就行,既然是文字,那就找找在哪儿修改
页面底部布局的文件是 “view/themes/bootstrap/footer.htm”
修改完成后退出vim,查看同级目录,包含一个文件 header.htm
vim打开,分析一下。就是这份文件。
162行和184行,修改一下,要加Logo也可以加一个Logo
- LuCI.........
1
2
3
4
5
修改后的代码
WangSansan - LuCI.........WangSansan
1
2
3
4
5
修改后大概这样子
本来想把web功能部分与静态页面修改放到一起写,静态页面的修改,只研究了半个小时就能搞定了,本以为加功能嘛,大概浏览了一下,无非就是一堆Lua代码,增删改也就一会儿的事,研究了才发现除了Lua代码,还有目录结构和包含关系,这部分相对于纯静态页面的修改,还是稍有难度,所以单独分节,好了,接着上面的步骤来说。
静态内容的修改,没什么难度,既然我们是二次开发,那我们就尝试增加点新功能。
先登陆进去
常规的路由器功能,该有的都有。
接下来就可以开始定制属于我们自己的路由器界面了。
不建议直接对原油配置文件的内容进行修改
我们先把LuCi的配置文件是怎么工作的搞明白,在一步一步进行我们的二次开发工作。
LuCI采用了MVC三层架构,使用Lua脚本开发,在/usr/lib/lua/luci目录下,分别对应、、三个文件夹,做开发的同学,对MVC架构应该就比较熟悉了,模型(model)-视图(view)-控制器(controller),Luci采用的Lua进行开发,我们不需要定义自己的视图框架的话基本不需要对view层进行修改,基本上只需要修改model层就可以完成我们功能的添加。
Luci运行时,会扫描controller目录下的所有*.lua文件,进行功能入口的注册并展示在Web页面
当我们在Web页面点击各功能入口时,Luci会执行model目录下的对应入口功能模型
首先进入controller目录,创建一个文件wangsansan.lua
写入内容
module("luci.controller.wangsansan", package.seeall)function index()entry({"admin", "wangsansan_url"},cbi("admin_wangsansan/test"),_("Test"))end
1
2
3
4
5
6
7
访问一下,可以看到我们已经添加了一个名为“Test”的入口
并且点击之后的url跳转路径是 http://192.168.1.1/cgi-bin/luci/admin/wangsansan_url
entry({"admin", "wangsansan_url"},cbi("admin_wangsansan/test"), _("Test"))
1
这条语句我折行了,看不懂的话,把它合并到一行来看就行了
第2个参数表示调用的路径,就下面这行内容
cbi("admin_wangsansan/test")
1
cbi() 这个函数会检索到model目录下,那这一行就是说,目标文件路径为model/cbi/admin_wangsansan/test.lua
不过这个时候我们点击Test会报错,因为我们还没有配置CBI模块
首先创建配置文件
# echo "config wangsansan" > /etc/config/wangsansan
1
接下来配置CBI模块,创建文件model/cbi/admin_wangsansan/test.lua
写入下面的内容
local fs = require "nixio.fs"local sys = require "luci.sys"local m, sm = Map("wangsansan", "wangsansan_title", "wangsansan_explain")s = m:section(TypedSection, "wangsansan")s.anonymous=truereturn m
1
2
3
4
5
6
7
8
9
10
好了,点击Test栏目,访问一下
好了,可以看到和我们配置的信息是一样的。
自己纯手动建立过一遍,就能弄明白怎么回事,我们可以开始自己定制我们想要的界面了
提供参考连接:
LuCi API
https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/documentation/api/index.html
Openwrt Luci界面开发http://blog.csdn.net/lichao_ustc/article/details/42739563
为你的luci添加自助高级配置界面http://www.right.com.cn/forum/thread-183560-1-1.html
Openwrt开发与Luci介绍http://www.jianshu.com/p/bfb93c4e8dc9
折腾几天的成果,可能有些坑爬出来之后,就忘了,如果大家有遇到其它坑,可以在博客下留言,如果恰好我懂,我会回复。