开发者社区> 异步社区> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

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

简介:
+关注继续查看

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

2.2 编译脚本分析

2.2.1 顶层目录概述

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


screenshot

目录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所示。


screenshot

2.2.2 编译脚本

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


screenshot


screenshot

2.2.3 下载工具

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

Syntax: ./download.pl <target dir> <filename> <md5sum> [<mirror> ...]

为下载之后的保存位置,下载代码通常均保存在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 <command> [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从代码仓库地址下载代码数据。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
5.4 芯片SDK开发:算法工程的调试和使用|学习笔记
快速学习5.4 芯片SDK开发:算法工程的调试和使用
0 0
Unity开发者必备的C#脚本技巧
我是一名Unity开发爱好者,自己总结了一些Unity的脚本编辑技巧
0 0
YoC开发测试工具介绍一:YoC铁三角
YoC铁三角是指在YoC协作开发中的三个开发实体的简称,通过彼此的相互协作,为开发者提供组件化软硬件云端一体的解决方案。
0 0
安卓应用安全指南 4.6.1 处理文件 示例代码
安卓应用安全指南 4.6.1 处理文件 示例代码 原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.0 如上所述,文件原则上应该是私有的。
990 0
9个最好用的在线编译/调试工具
电脑没有C/C++的开发环境了,只能找找在线的编译器。。IDEone不错。。。 本文要推荐9个最好用的在线编译器,以下顺序不按排名先后: 1、ideone 可以在线编译、调试C/C++,JAVA,PHP,Python,Perl,以及其他40多种编程语言。
772 0
+关注
异步社区
异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。
文章
问答
文章排行榜
最热
最新
相关电子书
更多
混合应用平台构建实战
立即下载
荷鲁斯 移动端第三方库安全检查引擎介绍
立即下载
小程序 云开发
立即下载