不管你使用過多少/多久其餘的 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 系統初創時期的關鍵思想。