LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 774|回复: 3

Bash 实例:探讨 ebuild 系统

[复制链接]
发表于 2006-11-10 15:50:45 | 显示全部楼层 |阅读模式
Bash 实例:探讨 ebuild 系统


    Daniel Robbins
    总裁兼 CEO,Gentoo Technologies, Inc.

         Daniel Robbins 在其最后一篇 Bash 实例文章中详细讲述了 Gentoo Linux ebuild 系统,这个展示 bash 能力的极佳范例。循序渐进地,他为您展示如何实现 ebuild 系统,并触及很多方便的 bash 技术和设计策略。在本文末尾,您将很好地掌握制造完全基于 bash 的应用所涉及的技术,并开始为自己的自动构建系统编码。



进入 ebuild 系统
     我真是一直期待着这第三篇、也是最后一篇 Bash 实例文章,因为既然已经在 第 1 篇和 第 2 篇中讲述了 bash 编程基础,就可以集中讲述象 bash 应用开发和程序设计这样更高级的主题。在本文中,将通过我花了许多时间来编码和细化的项目,Gentoo Linux ebuild 系统,来给您大量实际的、现实世界的 bash 开发经验。

     我是 Gentoo Linux(目前还是 beta 版的下一代 Linux OS)的首席设计师。我的主要责任之一就是确保所有二进制包(类似于 RPM)都正确创建并一起使用。正如您可能知道的,标准 Linux 系统不是由一棵统一的源树组成(象 BSD),而实际上是由超过 25 个协同工作的核心包组成。这其中包括:
包         描述
linux         实际内核
util-linux         与 Linux 相关的杂项程序集合
e2fsprogs         与 ext2 文件系统相关的实用程序集合
glibc         GNU C 库

     每个包都位于各自的 tar 压缩包中,并由不同的独立开发人员或开发小组维护。要创建一个发行版,必须对每个包分别进行下载、编译和打包处理。每次要修复、升级或改进包时,都必须重复编译和打包步骤(并且,包确实更新得很快)。为了帮助消除创建和更新包所涉及的重复步骤,我创建了 ebuild 系统,该系统几乎全用 bash 编写。为了增加您的 bash 知识,我将循序渐进地为您演示如何实现该 ebuild 系统的解包和编译部分。在解释每一步时,还将讨论为什么要作出某些设计决定。在本文末尾,您不仅将极好地掌握大型 bash 编程项目,还实现了完整自动构建系统的很大一部分。

为什么选择 bash?
     Bash 是 Gentoo Linux ebuild 系统的基本组件。选择它做为 ebuild 的主要语言有几个原因。首先,其语法不复杂,并且为人们所熟悉,这特别适合于调用外部程序。自动构建系统是自动调用外部程序的“胶合代码”,而 bash 非常适合于这种类型的应用。第二,Bash 对函数的支持允许 ebuild 系统使用模块化、易于理解的代码。第三,ebuild 系统利用了 bash 对环境变量的支持,允许包维护人员和开发人员在运行时对其进行方便的在线配置。

构建过程回顾
     在讨论 ebuild 系统之前,让我们回顾一下编译和安装包都牵涉些什么。例如,让我们看一下 "sed" 包,这个作为所有 Linux 版本一部分的标准 GNU 文本流编辑实用程序。首先,下载源代码 tar 压缩包 (sed-3.02.tar.gz)(请参阅参考资料)。我们将把这个档案存储在 /usr/src/distfiles 中,将使用环境变量 "$DISTDIR" 来引用该目录。"$DISTDIR" 是所有原始源代码 tar 压缩包所在的目录,它是一个大型源代码库。

     下一步是创建名为 "work" 的临时目录,该目录存放已经解压的源代码。以后将使用 "$WORKDIR" 环境变量引用该目录。要做到这点,进入有写权限的目录,然后输入:
将 sed 解压缩到临时目录

$ mkdir work$ cd work$ tar xzf /usr/src/distfiles/sed-3.02.tar.gz

     然后,解压缩 tar 压缩包,创建一个包含所有源代码、名为 sed-3.02 的目录。以后将使用环境变量 "$SRCDIR" 引用 sed-3.02 目录。要编译程序,输入:

将 sed 解压缩到临时目录

$ cd sed-3.02$ ./configure --prefix=/usr
(autoconf 生成适当的 make 文件,这要花一些时间)$ make(从源代码编译包,也要花一点时间)

     因为在本文中只讲述解包和编译步骤,所以将略过 "make install" 步骤。如果要编写 bash 脚本来执行所有这些步骤,则代码可能类似于:

要执行解包/编译过程的样本 bash 脚本

#!/usr/bin/env bashif [ -d work ]then
# remove old work directory if it exists     
rm -rf workfimkdir workcd worktar
xzf /usr/src/distfiles/sed-3.02.tar.gzcd sed-3.02./configure --prefix=/usrmake
使代码通用
     虽然可以使用这个自动编译脚本,但它不是很灵活。基本上,bash 脚本只包含在命令行输入的所有命令列表。虽然可以使用这种解决方案,但是,最好做一个只通过更改几行就可以快速解包和编译任何包的适用脚本。这样,包维护人员将新包添加到发行版所需的工作就大为减少。让我们先尝试一下使用许多不同的环境变量来完成,使构建脚本更加适用:
新的、更通用的脚本

#!/usr/bin/env bash# P is the package nameP=sed-3.02
# A is the archive nameA=${P}.tar.gzexport
ORIGDIR=`pwd`export WORKDIR=${ORIGDIR}/workexport
SRCDIR=${WORKDIR}/${P}if [ -z "$DISTDIR" ]then     
# set DISTDIR to /usr/src/distfiles if not already set   
DISTDIR=/usr/src/distfilesfiexport DISTDIRif [ -d ${WORKDIR} ]then        
# remove old work directory if it exists     
rm -rf ${WORKDIR}
fimkdir ${WORKDIR}
cd ${WORKDIR}tar
xzf ${DISTDIR}/${A}cd ${SRCDIR}./configure --prefix=/usrmake

     已经向代码中添加了很多环境变量,但是,它基本上还是执行同一功能。但是,如果现在要要编译任何标准的 GNU 基于 autoconf 的源代码 tar 压缩包,只需简单地将该文件复制到一个新文件(用合适的名称来反映它所编译的新包名),然后将 "$A" 和 "$P" 的值更改成新值即可。所有其它环境变量都自动调整成正确设置,并且脚本按预想工作。虽然这很方便,但是代码还有改进余地。这段代码比我们开始创建的 "transcript" 脚本要长很多。既然任何编程项目的目标之一是减少用户复杂度,所以最好大幅度缩短代码,或者至少更好地组织代码。可以用一个巧妙的方法来做到这点 -- 将代码拆成两个单独文件。将该文件存为 "sed-3.02.ebuild":

sed-3.02.ebuild

#the sed ebuild file -- very simple!P=sed-3.02A=${P}.tar.gz   

     第一个文件不重要,只包含那些必须在每个包中配置的环境变量。下面是第二个文件,它包含操作的主要部分。将它存为 "ebuild",并使它成为可执行文件:

ebuild 脚本

#!/usr/bin/env bashif [ $# -ne 1 ]then     
echo "one argument expected."   
exit 1fiif [ -e "$1" ]then     
source $1else   
echo "ebuild file $1 not found."   
exit 1fiexport ORIGDIR=`pwd`export
WORKDIR=${ORIGDIR}/workexport SRCDIR=${WORKDIR}/${P}if [ -z "$DISTDIR" ]then     
# set DISTDIR to /usr/src/distfiles if not already set   
DISTDIR=/usr/src/distfilesfiexport DISTDIRif [ -d ${WORKDIR} ]then        
# remove old work directory if it exists     
rm -rf ${WORKDIR}
fimkdir ${WORKDIR}
cd ${WORKDIR}tar
xzf ${DISTDIR}/${A}cd ${SRCDIR}./configure --prefix=/usrmake

     既然已经将构建系统拆成两个文件,我敢打赌,您一定在想它的工作原理。基本上,要编译 sed,输入:

$ ./ebuild sed-3.02.ebuild

     当执行 "ebuild" 时,它首先试图 "source" 变量 "$1"。这是什么意思?还记得 前一篇文章所讲的吗:"$1" 是第一个命令行自变量 -- 在这里,是 "sed-3.02.ebuild"。在 bash 中,"source" 命令从文件中读入 bash 语句,然后执行它们,就好象它们直接出现在 "source" 命令所在的文件中一样。因此,"source ${1}" 导致 "ebuild" 脚本执行在 "sed-3.02.ebuild" 中定义 "$P" 和 "$A" 的命令。这种设计更改确实方便,因为如果要编译另一个程序,而不是 sed,可以简单地创建一个新的 .ebuild 文件,然后将其作为自变量传递给 "ebuild" 脚本。通过这种方式,.ebuild 文件最终非常简单,而将 ebuild 系统复杂的操作部分存在一处,即 "ebuild" 脚本中。通过这种方式,只需编辑 "ebuild" 脚本就可以升级或增强 ebuild 系统,同时将实现细节保留在 ebuild 文件之外。这里有一个 gzip 的样本 ebuild 文件:

gzip-1.2.4a.ebuild

#another really simple ebuild script!P=gzip-1.2.4aA=${P}.tar.gz

添加功能性
     好,我们正在取得进展。但是,我还想添加某些额外功能性。我希望 ebuild 脚本再接受一个命令行自变量:"compile"、"unpack" 或 "all"。这个命令行自变量告诉 ebuild 脚本要执行构建过程的哪一步。通过这种方式,可以告诉 ebuild 解包档案,但不进行编译(以便在开始编译之前查看源代码档案)。要做到这点,将添加一条 case 语句,该语句将测试 "$2",然后根据其值执行不同操作。代码如下:
发表于 2006-11-11 10:49:14 | 显示全部楼层
顶顶顶顶顶顶  (呵呵要六个字所以就顶6个)!
回复 支持 反对

使用道具 举报

发表于 2006-11-11 11:16:53 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2006-11-11 13:28:16 | 显示全部楼层
不是原创的,要声明啊
加强版权意识
否则不仅仅是人品问题,而是有可能上升到法律问题
不过还是谢谢楼主的分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表