不管你使用过多少/多久其余的 Linux 发行版,初次接触 Gentoo 时,极有可能会以为它在软件包的安装方面很神奇。若要在 Gentoo 中安装一个软件包,一般要定义如何进行软件源代码包的下载、解包、打补丁、编译、安装以及合并。为了实现对软件包进行细微的定制,还须要定义一些有用的元数据(即 USE 旗标)、补丁文件以及一些操控软件包编译与安装的过程。Gentoo 是经过 GNU Bash shell 脚原本定义这一切,这种脚本就是所谓的 ebuild 文件。php
咱们在安装 Gentoo 时,一个必须的步骤是下载一个 Portage 树的镜像包,解包后一般安置于 /usr 目录(即 /usr/portage
),以后每次执行 emerge --sync
时,便会根据官方远程网站上的 Portage 树来更新你本地的 Portage 树。html
粗心大意的看,Portage 树有四层结点。根结点即是 /usr/portage
目录,第 2 层结点是软件包所属分类目录,第 3 层结点是软件包的名称目录,叶子结点则是 ebuild 文件以及其余辅助性文件或目录。以 gnome-shell-3.12.2.ebuild
文件为例,它在 Portage 树中的完整路径是 /usr/portage/gnome-base/gnome-shell/gnome-shell-3.12.2.ebuild
。shell
对于咱们指望的软件包,若是 Portage 树未提供针对它的 ebuild 文件,那么咱们须要本身动手丰衣足食。通常是不建议将咱们所写的 ebuild 文件放在 Portage 树中的,由于它们可能会在 emerge --sync
期间被冲刷(好比被官方的同名文件替换)。app
Portage 树支持一种被称为 Overlay 的技术。简单来讲,就是咱们能够另行创建一棵新的 Portage 树,这棵树的规模虽然比官方的 Portage 树小不少,可是 Portage 树的管理系统能够将这可新的 Portage 树与官方 Portage 树『合并』。若是新的 Portage 树中某些结点与官方的 Portage 树存在重叠,那么 Portage 树的管理系统会之前者覆盖后者,所以咱们新建的 Portage 树一般被直呼为『Overlay』。ide
假设在 /us/local
目录中建立本身的 Overlay,约定俗成的方式是:函数
# mkdir -p /usr/local/portage
须要将 Overlay 路径告知 Portage 管理系统,即在 /etc/make.conf
文件中添加如下代码:学习
PORTDIR_OVERLAY="/usr/local/portage"
为了让咱们的 Overlay 可以被 Portage 管理系统所接受,须要在 /usr/local/portage
中建立 metadata
子目录,并在该目录内添加内容为 masters = gentoo
的 layout.conf
文件[1],即:网站
# mkdir /usr/local/portage/metadata # echo "masters = gentoo" > /usr/local/portage/metadata/layout.conf
最后,还须要在 `/usr/local/portage
中建立 profiles
子目录,并在该目录内添加 repo_name
文件。咱们能够在这份文件中设置 Overlay 名称,只需将 Overlay 名称写入该文件便可。例如,我将个人 Overlay 命名为 garfileo
:ui
# echo "garfileo" > /usr/local/portage/profiles/repo_name
从此,就在这个 Overlay 中学习 ebuild 文件的编写。spa
下面经过写一个很是简单的 ebuild 文件来获取一些直观的认识。假设在 app-misc
这个分类中有一个名为 hello-world
的软件包,如今咱们要为这个软件包的 1.0 版的安装写一份 ebuild 文件。
注意:软件包的分类名并非随意的,它必需要与
/usr/portage
中的某个子目录名一致。
首先在 Overlay 中创建软件包所在的分支:
# mkdir -p /usr/local/portage/app-misc/hello-world
可从 /usr/portage/header.txt
文件中得到 ebuild 文件默认的文件头,即:
# Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $
只不过是一些 Bash 脚本注释形式的文件描述信息而已,但它们是必须的。能够直接将 /usr/portage/header.txt
文件复制为 hello-world-1.0.ebuild
文件,这样即可得到一个含有上述内容的空 ebuild 文件。ebuild 文件的名称必须符合 Portage 所承认的格式,即:软件包名称-版本号.ebuild
。这一点很重要。
# cp /usr/portage/header.txt /usr/local/portage/app-misc/hello-world/hello-world-1.0.ebuild
下面,为这份 ebuild 文件增长如下内容:
SLOT="0"
这样,咱们便创建了一份最为简单的 ebuild 文件。接下来就是在这份文件上签个字……也就是为之生成一份签名文件,表示这个 ebuild 的是咱们作的,出了事咱们负责。
# cd /usr/local/portage/app-misc/hello-world # ebuild ./hello-world-1.0.ebuild manifest
若签名成功,会在 ebuild 文件同一目录中生成一份名为 Manifest
的文件。未来发布这份 ebuild 文件时,须要将数字签名文件一块儿发出,这样他人即可以验证这份 ebuild 是否是咱们作的。由于很是有可能咱们在向朋友们发送 ebuild 文件的过程当中会被坏人拦截,而后篡改 ebuild 文件。因为 ebuild 是可被系统执行的脚本,所以颇有可能变成『病毒』。所以,ebuild 文件的数字签名很是有必要。不过,这里为了简单起见,没有涉及如何用本身的密钥实现对 ebuild 的签名,所得 Manifest
文件仅仅是为了让 ebuild 可以被 Portage 管理系统所承认。
下面,继续向这份 ebuild 加入一些内容,使之变为:
# Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ EAPI="5" SLOT="0" DESCRIPTION="A classical example to use when starting on something new." HOMEPAGE="http://wiki.gentoo.org/index.php?title=Basic_guide_to_write_Gentoo_Ebuilds" LICENSE="MIT" KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86"
基本上就是在原来那份最简单的 ebuild 文件的基础上增长了几个变量:
EAPI
:Portage 系统已经为咱们编写了许多有用的 Bash 函数,将 EAPI
的值设为 5
表示咱们要用目前最新的 Bash 函数。这个变量必需要在 ebuild 文件头以后进行设定。
DESCRIPTION
:这个变量存储了 hello-world
这个软件包的简介信息。
HOMEPAGE
:定义了 hello-world
这个软件包的项目主页。
LICENSE
:定义了 hello-world
这个软件包所使用的许可证,例如 LGPL,GPL V2,GPL V3,MIT 等。
KEYWORDS
:若是你指望 hello-world
这个软件包可以安装在你的机器上,那么 KEYWORDS
变量的值必需要包含你在 /etc/make.conf
中所设定的 ACCEPT_KEYWORDS
值。
一旦改动了 ebuild 文件内容,那么必须从新生成 Manifest
文件:
# ebuild ./hello-world-1.0.ebuild manifest
如今,即可以使用 emerge
命令安装这个目前依然是子虚乌有的软件包了。
虽然到如今为止,仍是什么也没有作出来,可是看着 emerge
神奇的发现了我写的 ebuild
,心底仍是蔓生了一些幸福。
简单的说,就是 emerge
这个 Python 脚本会调用 ebuild.sh
这个 Bash 脚本,让后者去执行 ebuild 文件定义的软件包的下载、编译及安装过程。
ebuild.sh
所操控的软件包安装过程是在一个沙箱(Sandbox)中进行的。这一过程结束后,emerge
脚本须要将沙箱中的成果转移到真实世界,即 /
目录。
在一个遥远的地方,真的存在着 hello-world 的源码包。咱们只要经过 ebuild 文件将这个源码包的位置告诉 ebuild.sh
脚本,ebuild.sh
便会不远万里将其擒来。因此,咱们须要在 hello-world-1.0.ebuild
文件中添加如下内容:
SRC_URI="http://dev.gentoo.org/~tomwij/files/wiki/hello-world-1.0.tar.gz"
SRC_URI
这个变量即是存储源码包的下载地址的。
在从新生成 Manifest
时,ebuild.sh
便会自动将源码包下载到 /usr/portage/distfiles
目录,并为这个源码包也生成一个数字签名存储在 Manifest
文件中。
既然有了 hello-world
的源码包,那么下一步就该思考如何在 ebuild 文件中定义这个源码包的编译过程了。不过,解开刚才下载的 hello-world-1.0.tar.gz
包看一下,发现包里只有一份 Bash 脚本 hello-world
,其内容为:
#!/bin/sh echo "Hello world!"
因此,这个源码包就不必编译了,直接安装到系统中便可。从而,咱们在 ebuild 文件中得到了第一次编写 ebuild 函数的机会。在现有的 hello-world-1.0.ebuile
的文件中继续添加如下内容:
src_install() { dobin hello-world }
src_install
是 ebuild.sh
脚本可以识别并执行的函数名。也就是说,从 ebuild.sh
脚本的角度来看,你若想让我替你将软件包安装至系统中,那么你必须得按照个人习惯来。个人习惯就是在你提供给个人 ebuild 文件中寻找 src_install
这个函数,若是有这个函数,我就执行它,不然我就什么也不作。这就是 ebuild.sh
与 ebuild 文件之间达成的一个约定。
如今咱们在 ebuild 文件中向 ebuild.sh
提供了 src_install
这个函数。这个函数只包含一条命令:dobin hello-world
。这个命令的意思是为 hello-world
这个脚本设置可执行权限,而后将其安装至系统默认的可执行文件目录中,即 /usr/bin
目录。
src_install
只是 ebuild.sh
与 ebuild 文件之间众多约定函数中的一个而已,而且这些约定函数是顺次被 ebuild.sh
执行的,以下图所示:
这里存在一个问题,hello-world
这个 Bash 脚本是包含在 hello-world-1.0.tar.gz
这个包内的,而咱们只在 hello-world-1.0.ebuild
文件中定义了 src_install
函数,那么 hello-world-1.0.tar.gz
什么时候被解包的呢?这个问题的答案是,Portage 管理系统中已经为这些约定的函数定义了默认行为。好比,用于为源码包解包的 src_unpack
函数,其默认的定义是:
src_unpack() { if [ "${A}" != "" ]; then unpack ${A} fi }
若是在 ebuild 文件中没有从新定义 src_unpack
函数,那么 ebuild.sh
便会按照上面图示的管线调用默认的 src_unpack
函数。因此 hello-world
脚本得以从 hello-world-1.0.tar.gz
中解出。
对如今的 hello-world-1.0.ebuild
再次生成 Manifest
,而后就能够用它将 hello-world
脚本安装至 /usr/bin
目录中了。
这就是咱们用本身写的 ebuild 安装的第一个『软件包』。
因为 ebuild 文件本质上是 Bash 脚本。若是对 Bash 不熟悉,能够经过 Daniel Robbins 写的三篇教程学习一下:
须要特别关注 Part 3,由于在这一篇里,Daniel Robbins 高屋建瓴的描绘出了 Portage 系统初创时期的关键思想。