初探 ebuild

不管你使用過多少/多久其餘的 Linux 發行版,初次接觸 Gentoo 時,極有可能會以爲它在軟件包的安裝方面很神奇。若要在 Gentoo 中安裝一個軟件包,一般要定義如何進行軟件源代碼包的下載、解包、打補丁、編譯、安裝以及合併。爲了實現對軟件包進行細微的定製,還須要定義一些有用的元數據(即 USE 旗標)、補丁文件以及一些操控軟件包編譯與安裝的過程。Gentoo 是經過 GNU Bash shell 腳原本定義這一切,這種腳本就是所謂的 ebuild 文件。php

ebuild 在哪裏?

咱們在安裝 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.ebuildshell

對於咱們指望的軟件包,若是 Portage 樹未提供針對它的 ebuild 文件,那麼咱們須要本身動手豐衣足食。通常是不建議將咱們所寫的 ebuild 文件放在 Portage 樹中的,由於它們可能會在 emerge --sync 期間被沖刷(好比被官方的同名文件替換)。app

Portage 樹支持一種被稱爲 Overlay 的技術。簡單來講,就是咱們能夠另行創建一棵新的 Portage 樹,這棵樹的規模雖然比官方的 Portage 樹小不少,可是 Portage 樹的管理系統能夠將這可新的 Portage 樹與官方 Portage 樹『合併』。若是新的 Portage 樹中某些結點與官方的 Portage 樹存在重疊,那麼 Portage 樹的管理系統會之前者覆蓋後者,所以咱們新建的 Portage 樹一般被直呼爲『Overlay』。ide

創建本身的 Overlay

假設在 /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 = gentoolayout.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 命名爲 garfileoui

# echo "garfileo" > /usr/local/portage/profiles/repo_name

從此,就在這個 Overlay 中學習 ebuild 文件的編寫。spa

Hello World!

下面經過寫一個很是簡單的 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 命令安裝這個目前依然是子虛烏有的軟件包了。

安裝子虛烏有的 hello-world 包

雖然到如今爲止,仍是什麼也沒有作出來,可是看着 emerge 神奇的發現了我寫的 ebuild,心底仍是蔓生了一些幸福。

emerge 與 ebuild 有什麼聯繫?

簡單的說,就是 emerge 這個 Python 腳本會調用 ebuild.sh 這個 Bash 腳本,讓後者去執行 ebuild 文件定義的軟件包的下載、編譯及安裝過程。

emerge 與 ebuild 文件之間的聯繫

ebuild.sh 所操控的軟件包安裝過程是在一個沙箱(Sandbox)中進行的。這一過程結束後,emerge 腳本須要將沙箱中的成果轉移到真實世界,即 / 目錄。

真實的 Hello World!

在一個遙遠的地方,真的存在着 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_installebuild.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 執行的,以下圖所示:

被順次執行的 ebuild 函數

這裏存在一個問題,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 系統初創時期的關鍵思想。

相關資料

相關文章
相關標籤/搜索