《智能路由器开发指南》——2.2 编译脚本分析

简介:

本节书摘来异步社区《智能路由器开发指南》一书中的第2章,第2.2节,作者:张永智 ,李章明,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.2 编译脚本分析

2.2.1 顶层目录概述
OpenWrt代码有8个固定的顶层目录及6个编译时创建的临时目录,顶层的固定目录含义如表2-3所示。

cc0cecf8d39c33f68bdc44ebc9eb2eeb145e855e

目录config是编译配置文件目录,是OpenWrt 15.05的新增目录,是将一些编译选项配置文件分类放在这里,包含全局编译设置、开发人员编译设置、目标文件格式设置和内核编译设置等4部分。

目录include和scripts包含各种脚本和Makefile。目录target是指目标嵌入式设备,针对不同的平台有不同的特性代码。针对这些平台特性,“target/linux”目录下按照平台进行目录划分,里面包括了针对各种平台标准内核的补丁及特殊配置等。目录tools和toolchain包含了一些通用命令,用来生成固件、编译器和C语言链接库。目录docs在编译时不需要,用于存放开发文档。目录package则用于存放各种必要的软件包。

编译生成结果会储存在以下3个目录下:“build_dir/host”是一个临时目录,用来储存不依赖于目标平台的工具;“build_dir/toolchain-”用来储存依赖于指定平台的编译工具链;“staging_dir/toolchain-”是编译工具链的最终安装位置。通常我们不需要改动编译链目录下的任何东西,除非要更新编译工具版本等。

在OpenWrt固件中,几乎所有东西都是软件包(package),可以编译为以“.ipk”结尾的安装包,这样就可以很方便地安装、升级和卸载了。注意,扩展软件包不是在主分支中维护的,但是可以使用软件包编译扩展机制(feeds)来进行扩展安装。这些包能够扩展基本系统的功能,只需要将它们链接进入主干。之后,这些软件包将会显示在编译配置菜单中。

编译工具链、目标平台的软件包等需要下载的文件都放在dl目录下。目标平台和软件包两部分都需要“build_dir/”作为编译的临时目录,并且会将目录staging_dir作为编译的临时安装目录,最终的生成文件保存在目录bin下。

目录feeds用于保存扩展软件包,可以使用软件包编译扩展机制来进行扩展安装。这些包能够扩展基本系统的功能,只需要将它们链接进入编译主目录的package目录下。之后,这些软件包将会显示在配置菜单中。编译后生成6个临时目录,其含义如表2-4所示。

2791866b58e66adf9d47ed9c8a4dc901d5df83f8

2.2.2 编译脚本

目录scripts为编译工具脚本文件,例如patch-kernel.sh封装了patch命令,在编译时,首先将patches目录下的所有补丁文件打上,并且判断如果打补丁失败将退出编译过程。download.pl为下载源代码的工具脚本,封装下载工具wget的选项以及设置从哪里下载。表2-5所示为典型编译脚本功能。目录include用于保存各种makefile文件。

63b33b762977e15e3d93968cc9eb8db470092034

2.2.3 下载工具

OpenWrt在构建时首先下载代码,就是使用scripts/download.pl脚本进行下载,使用方法如下:

Syntax: ./download.pl [ ...]
为下载之后的保存位置,下载代码通常均保存在dl目录下。

待下载的文件名。

下载内容的MD5,用于校验下载文件是否正确。

为可选的参数,是下载文件的镜像地址,可以有多个地址,优先选择第一个,如果下载失败则顺序选择后面的地址。

该程序由Perl语言开发出来,代码并不复杂。代码首先进行初始条件检查,判断参数是否足够,至少需要3个参数分别为下载文件保存位置、下载文件名及下载内容MD5值。 接着从命令行参数中顺序读取数据,并赋值给局部变量,最后判断md5sum或md5工具是否存在,如果不存在提示工具不存在后退出。

紧接着调用localmirrors()函数读取本地的源码镜像地址,我们可以在企业内部创建自己的代码镜像服务器,然后将镜像地址放在“scripts/localmirrors”文件中,这样我们就不用每次编译时都从互联网上去下载了。例如我这里修改如下:

zhang@zhang-laptop:~/cc/scripts$ cat localmirrors 
http://192.168.1.106:8080/openwrt/
http://mirror.bjtu.edu.cn/gnu/```
紧接着遍历命令行并将代码中的镜像地址加到备选镜像中。最后使用while循环进行下载,如果下载完成就对下载文件的MD5进行对比,如果MD5值一致则退出循环,否则进入下一个镜像地址进行下载。下载成功后调用cleanup()函数来清理临时变量。

这个下载功能最重要的接口是我们可以通过“scripts/localmirrors”文件自定义软件包下载地址,方便开发人员进行设置。

最近有很多iPhone/Android编译工具爆出后门问题,就是因为使用其他第三方镜像地址文件来下载编译工具,但没有对下载的软件内容进行MD5值对比,从而导致编译的应用程序感染后门。OpenWrt的下载检查机制从源头上解决了这类问题。在我开发OpenWrt时也发现了下载的一些内容被感染的问题,但检查机制丢弃了不正确的内容,从下一个的镜像网站上继续下载。

####2.2.4 patch-kernel.sh脚本
OpenWrt的代码包中大多均有patches目录。下载代码包完成后进行打补丁,采用的就是patck-kernel.sh脚本。脚本的第一个参数为编译代码目录,第二个为补丁目录,调用脚本形式举例如下。

../scripts/patch-kernel.sh iproute2-3.3.0 ../package/iproute2/patches/`
执行流程如下。

(1)首先进行参数赋值,第一个参数为代码目录,第二个参数为补丁目录。

(2)第二步判定代码目录和补丁目录是否存在,如果不存在则提示错误并退出。

(3)遍历补丁文件,根据后缀判断补丁文件类型。

(4)调用patch命令应用补丁。

(5)检查补丁应用是否正确,如果存在“*.rej”文件表示出现错误,返回“1”并退出。

(6)最后检查如果存在应用补丁后的备份文件,则删除备份文件。

2.2.5 编译扩展机制feeds

传统的Linux操作系统在编译某一个软件的时候,会检查其依赖软件及头文件是否存在,如果没有安装,则会报缺少头文件或缺少链接库等错误,编译将退出。这种机制使得开发者在编译一个软件之前,需要查找该软件所需的依赖库及头文件,并手动去安装这些软件。有时候碰到比较娇贵的软件时,嵌套式的安装依赖文件,会使得开发者头昏脑胀。OpenWrt通过引入feeds机制,很好地解决了这个问题。

feeds是OpenWrt开发所需要的软件包套件的工具及更新地址集合,这些软件包通过一个统一的接口地址进行访问。这样用户可以不用关心扩展包的存储位置,可以减少扩展软件包和核心代码部分的耦合。它由两部分组成,即扩展包位置配置文件feeds.conf.default和脚本工具feeds。目前在配置文件中保存最重要的扩展软件包集合有以下4个。

‘LuCI’OpenWrt默认的Web浏览器图形用户接口。
‘routing’一些额外的基础路由器特性软件,包含动态路由Quagga等。
‘telephony’IP电话相关的软件包,例如freeswitch和Asterisk等。
‘management’TR069等各种管理软件包。
当我们下载了OpenWrt对应源码之后,进行如下操作:

$> ./scripts/feeds update –a
$> ./scripts/feeds install -a```
上述操作,就是利用feeds提供的接口将OpenWrt所需的全部扩展软件包进行下载并安装。在更新时,需要能够访问互联网。在下载之前可以通过查看“feeds.conf.default”文件,来检查哪些文件需要包含在编译环境中。feeds工具用法如下。

zhang@zhang-VirtualBox:~/cc$ ./scripts/feeds
Usage: ./scripts/feeds [options]

Commands:

list [options]: List feeds, their content and revisions (if installed)
Options:
    -n :              List of feed names.
    -s :              List of feed names and their URL.
    -r <feedname>:  List packages of specified feed.
    -d <delimiter>: Use specified delimiter to distinguish rows (default: spaces)

install [options] <package>: Install a package
Options:
    -a :   Install all packages from all feeds or from the specified feed using the -p option.
    -p <feedname>: Prefer this feed when installing packages.
    -d <y|m|n>:    Set default for newly installed packages.
    -f :    Install will be forced even if the package exists in core OpenWrt (override)

search [options] <substring>: Search for a package
Options:
    -r <feedname>: Only search in this feed

uninstall -a|<package>: Uninstall a package
Options:
    -a :           Uninstalls all packages.

update -a|<feedname(s)>: Update packages and lists of feeds in feeds.conf .
Options:
  -a : Update all feeds listed within feeds.conf. Otherwise the specified feeds will be updated.
  -i :  Recreate the index only. No feed update from repository is performed.

clean:   Remove downloaded/generated files.
update:下载在feeds.conf或feeds.conf.default文件中的软件包列表并创建索引。-a表示更新所有的软件包。只有更新后才能进行后面的操作。

list:从创建的索引文件“feed.index”中读取列表并显示。只有进行更新之后才能查看列表。

install:安装软件包以及它所依赖的软件包,从feeds目录安装到package目录,即在“package/feeds”目录创建软件包的软链接。只有安装之后,在后面执行“make menuconfig”时,才可以对相关软件包是否编译进行选择。

例如安装luci-app-firewall:

zhang@zhang-laptop:~/openwrt$ ./scripts/feeds install luci-app-firewall
Installing package 'luci-app-firewall' from luci
Installing package 'luci-base' from luci
Installing package 'luci-lib-nixio' from luci
Installing package 'luci-lib-ip' from luci`
search:按照给定的字符串来查找软件包,需要传入一个字符串参数。

uninstall:卸载软件包,但它没有处理依赖关系,仅仅删除本软件包的软链接。

clean:删除update命令下载和生成的索引文件,但不会删除install创建的链接。

feeds代码处理过程是这样的:这个命令首先读取并解析feeds.conf配置文件,然后执行相应的命令,例如install时,将安装应用程序包和它所有直接或间接依赖的所有软件包。安装时将创建一个符号链接,从packages/feeds/$feed_name/$package_name指向feeds/$feed_name/$package_name, 这样在“make menuconfig”时,feeds的软件包就可以被处理到,就可以选择编译了。例如luci-app-firewall指向feeds/luci/applications/luci- app-firewall:

zhang@zhang-laptop:~/openwrt$ ls package/feeds/luci/luci-app-firewall -alht
lrwxrwxrwx 1 zhang zhang 50 2015-07-04 15:17 package/feeds/luci/luci- app-firewall -> ../../../feeds/luci/applications/luci-app-firewall```
用一句话来说,编译扩展安装过程就是将feeds目录下的软件包链接到packages/feeds对应目录下。可使用的feeds列表配置为feeds.conf或者feeds.conf.default。优先选择feeds.conf文件,这个文件包含了扩展安装源列表,每一行由3部分组成,包含feed方法、feed 名字和feed源。下面是一个扩展安装源配置文件的例子。

src-git luci https://github.com/openwrt/luci.git;for-15.05
src-git routing https://github.com/openwrt-routing/packages.git;for- 15.05
src-git telephony https://github.com/openwrt/telephony.git;for-15.05
src-gitmanagement https://github.com/openwrt-management/packages.git; for-15.05`
我们可以修改该文件使编译时从自己指定的位置进行下载。主要支持feed方法的类型有以下3种。

src-cpy通过从数据源路径复制数据。
src-git通过使用Git从代码仓库地址下载代码数据。
src-svn通过使用SVN从代码仓库地址下载代码数据。

相关文章
|
30天前
|
算法 安全 Java
【C/C++ 实用工具】静态代码检测工具和平台的一览
【C/C++ 实用工具】静态代码检测工具和平台的一览
21 0
|
3月前
|
JSON 开发工具 数据格式
基于Python开发的火车票分析助手(源码+可执行程序+程序配置说明书+程序使用说明书)
基于Python开发的火车票分析助手(源码+可执行程序+程序配置说明书+程序使用说明书)
|
3月前
|
人工智能 JSON 开发工具
基于Python开发的AI智能联系人管理程序(源码+可执行程序+程序配置说明书+程序使用说明书)
基于Python开发的AI智能联系人管理程序(源码+可执行程序+程序配置说明书+程序使用说明书)
|
3月前
|
JSON 定位技术 开发工具
基于Python开发的高德地图+58租房系统(源码+可执行程序+程序配置说明书+程序使用说明书)
基于Python开发的高德地图+58租房系统(源码+可执行程序+程序配置说明书+程序使用说明书)
|
3月前
|
数据可视化 数据挖掘 Python
基于Python开发的Excel数据分析系统(源码+可执行程序+程序配置说明书+程序使用说明书)
基于Python开发的Excel数据分析系统(源码+可执行程序+程序配置说明书+程序使用说明书)
|
8月前
|
安全 C++
ANSYS逆向分析功能介绍
逆向求解背景介绍、操作步骤、结果输出和解读
ANSYS逆向分析功能介绍
|
11月前
|
传感器 物联网 项目管理
【毕设参考】“摸鱼”神器,用 ESP32 + HaaS Python DIY一款全功能鱼缸 控温、过滤、换水一键执行
【毕设参考】“摸鱼”神器,用 ESP32 + HaaS Python DIY一款全功能鱼缸 控温、过滤、换水一键执行
176 0
|
11月前
|
传感器 监控 网络协议
【毕设参考】ESP32 + HaaS Python打造可以统计流量的自动感应门系统
【毕设参考】ESP32 + HaaS Python打造可以统计流量的自动感应门系统
153 0
|
存储 JSON 分布式计算
商圈库_功能_环境代码编写 | 学习笔记
快速学习商圈库_功能_环境代码编写。
92 0
商圈库_功能_环境代码编写 | 学习笔记