CentOS用のRPMをビルドしてyumでインストールできるようにしてみた（例：CentOS 6.7用のgit-2.6.2パッケージの自作）


みんな大好き[CentOS](https://www.centos.org/)。
最近は[Ubuntu](http://www.ubuntu.com/)のシェアも増えているみたいですが、無料で使えるRedHat系ディストリビューションとして、まだまだ他に移行する気がしない！って人も多いんじゃないでしょうか。

CentOSといえば、有名なリポジトリとして[epel](https://fedoraproject.org/wiki/EPEL/ja)、[RepoForge](http://repoforge.org/)、[remi](http://rpms.famillecollet.com/)、[ius](https://ius.io/)などなどありますが、

* CentOSを使い続けたい
* できるだけ最新のソフトウェアを利用したい
* ソースからビルドして`/usr/local/bin`などにインストールする運用は避けたい

・・・といったポリシーをお持ちの方なら、一度は利用したことはあるかと思います。
しかし、いろんなリポジトリを併用しすぎると **パッケージの依存関係がなんかヘン** になったり、 **同じソフトウェアなのに微妙にパッケージ名が違う** という事態に陥って、混乱しがちですよね（私だけ？）。

だったらいっそ **独自のリポジトリを持とう！** ということで、そのために必要な知識を私の **独断と偏見で** ザックリと説明しつつ、一連の作業の流れをまとめてみようと思います。

* **要するに、以下、自己責任でお願いします。**
* 詳細な説明を省いている箇所もありますが御了承ください。

## はじめに：3行まとめ

* SRPMやspecファイルからパッケージ(*.rpm)作成
* パッケージをWebにアップロード
* createrepoコマンドとyum設定ファイルでリポジトリとして認識させる

## SRPMやspecファイルからパッケージ作成

RPMを作成するために、まずは必要なパッケージをインストールします。

```
$ sudo yum install -y rpm-build rpmdevtools
```

rpm-buildパッケージは、RPM作成には欠かせない`rpmbuild`コマンドを提供します。
rpmdevtoolsパッケージは、RPM作成のためのディレクトリツリーや`.rpmmacros`ファイルをセットアップしてくれる`rpmdev-setuptree`コマンドを提供します。

これらがインストールできたところで、以下、 **最新バージョンのRPMを作成する方法** を、例を挙げて説明します。

## 例：CentOS 6.7におけるGitパッケージ

2015/10/22現在、CentOS 6.7において、公式パッケージとして公開されている[Git](https://git-scm.com/)の最新バージョンは **1.7.1** です。
対して、実際のGitの最新バージョンは **2.6.2** ですので、できれば最新バージョンを利用したい！と思ったとします。
つまり、 **CentOS 6.7用のgit-2.6.2パッケージを自作したい！** ということですね。

### RawhideのSRPMを拝借する

CentOSは、Red Hat Enterprise Linux（以下 RHEL）のクローンOSとして知られていますが、RHELと同様に、最新の（メジャーバージョンが上がった）パッケージは提供されない傾向にあります。
対して、同じRHEL系の[Fedora](https://getfedora.org/ja/)は比較的新しいパッケージを随時取り入れているディストリビューションで、特に[Rawhide](https://fedoraproject.org/wiki/Releases/Rawhide)は最新のパッケージを提供し続けています。
SRPMも公開されているので、これを用いてCentOS向けにリビルドしていくことにします。

**（かなり邪道ですが、ツッコミはナシの方向で。本来は、インストールしたいソフトウェアがどのようにビルドされるのかを良く研究・把握したうえで、独自にspecファイルを自作し、リビルドすべきです。）**

Rawhideが提供するSRPMは下記から取得できます。
https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/source/SRPMS

現時点のRawhideにおけるgitパッケージのSRPMは下記の通りです。
https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/source/SRPMS/g/git-2.6.2-1.fc24.src.rpm

ちょうどいい具合に最新バージョンのようですね！

### 下準備

まず始めに、先ほどインストールした`rpmdev-setuptree`コマンドを実行します。

```
$ rpmdev-setuptree
```

`~/rpmbuild`以下に必要なディレクトリが作成され、`~/.rpmmacros`設定ファイルが配置されます。

```
$ ls -R rpmbuild
rpmbuild:
BUILD  RPMS  SOURCES  SPECS  SRPMS

rpmbuild/BUILD:

rpmbuild/RPMS:

rpmbuild/SOURCES:

rpmbuild/SPECS:

rpmbuild/SRPMS:
```

```~/.rpmmacros
%_topdir      %(echo $HOME)/rpmbuild
%_smp_mflags  -j3
%__arch_install_post   /usr/lib/rpm/check-rpaths   /usr/lib/rpm/check-buildroot
```

説明は省きますが、不要なdebuginfoパッケージが作成されないよう、`~/.rpmmacros`ファイルに次の1行を追加します。

```
%debug_package %{nil}
```

これで`rpmbuild`コマンドを用いるための下準備が整いました。

### SRPMファイルの展開

SRPMファイルは、RPMファイルのビルドに必要な **specファイル** と、ソフトウェアの **ソース、パッチ類** などが含まれたファイルです。
これらを展開するために、`curl`コマンドを用いてSRPMファイルをダウンロードし、`rpm`コマンドを用いて`~/rpmbuild`以下に配置します。

```
$ curl -LO https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/source/SRPMS/g/git-2.6.2-1.fc24.src.rpm
$ rpm -ivh git-2.6.2-1.fc24.src.rpm
```

これで`~/rpmbuild/SOURCES`にソースやパッチ類、`~/rpmbuild/SPECS`にspecファイルが配置されます。

### ビルドに必要なパッケージのインストール

では、`rpmbuild`コマンドでビルド・・・と行きたいところですが、ビルドに必要なパッケージが足りないようです。

```
$ rpmbuild -ba ~/rpmbuild/SPECS/git.spec
エラー: ビルド依存性の失敗:
	asciidoc >= 8.4.1 は git-2.6.2-1.el6.x86_64 に必要とされています
	xmlto は git-2.6.2-1.el6.x86_64 に必要とされています
	desktop-file-utils は git-2.6.2-1.el6.x86_64 に必要とされています
	emacs は git-2.6.2-1.el6.x86_64 に必要とされています
	expat-devel は git-2.6.2-1.el6.x86_64 に必要とされています
	gettext は git-2.6.2-1.el6.x86_64 に必要とされています
	libcurl-devel は git-2.6.2-1.el6.x86_64 に必要とされています
	pcre-devel は git-2.6.2-1.el6.x86_64 に必要とされています
	openssl-devel は git-2.6.2-1.el6.x86_64 に必要とされています
	zlib-devel >= 1.2 は git-2.6.2-1.el6.x86_64 に必要とされています
	pkgconfig(bash-completion) は git-2.6.2-1.el6.x86_64 に必要とされています
	perl(Error) は git-2.6.2-1.el6.x86_64 に必要とされています
	perl(ExtUtils::MakeMaker) は git-2.6.2-1.el6.x86_64 に必要とされています
```

### yum-builddepコマンドが便利！

こういうときに便利なコマンドが`yum-builddep`コマンドです。
yum-utilsパッケージにて提供されていますのでインストールします。

```
$ sudo yum install -y yum-utils
```

インストールできたら、`yum-builddep`コマンドを用いるために、specファイルからSRPMファイルを作成します。

```
$ rpmbuild -bs ~/rpmbuild/SPECS/git.spec
書き込み完了: /home/*****/rpmbuild/SRPMS/git-2.6.2-1.el6.src.rpm
```

では、`yum-builddep`コマンドを用いて、必要なパッケージを一括インストールします。

```
$ sudo yum-builddep -y ~/rpmbuild/SRPMS/git-2.6.2-1.el6.src.rpm
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: www.ftp.ne.jp
 * extras: www.ftp.ne.jp
 * updates: www.ftp.ne.jp
Getting requirements for git-2.6.2-1.el6.src
 --> asciidoc-8.4.5-4.1.el6.noarch
 --> xmlto-0.0.23-3.el6.x86_64
 --> desktop-file-utils-0.15-9.el6.x86_64
 --> 1:emacs-23.1-28.el6.x86_64
 --> expat-devel-2.0.1-11.el6_2.x86_64
 --> gettext-0.17-18.el6.x86_64
 --> libcurl-devel-7.19.7-46.el6.x86_64
 --> pcre-devel-7.8-7.el6.x86_64
 --> openssl-devel-1.0.1e-42.el6.x86_64
 --> zlib-devel-1.2.3-29.el6.x86_64
Error: pkgconfig(bash-completion) のパッケージが見つかりません
```

### 「Error: pkgconfig(bash-completion) のパッケージが見つかりません」

まだ足りないパッケージがあるようです。
bash-completionパッケージは、CentOS 6.7の公式リポジトリには存在しないので、同じ要領でこちらもビルドします。
同様にRawhideのSRPMを拝借してインストールすることにします。

```
$ curl -LO https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/source/SRPMS/b/bash-completion-2.1-8.20150513git1950590.fc23.src.rpm
$ rpm -ivh bash-completion-2.1-8.20150513git1950590.fc23.src.rpm
$ rpmbuild -bs ~/rpmbuild/SPECS/bash-completion.spec
$ sudo yum-builddep -y ~/rpmbuild/SRPMS/bash-completion-2.1-8.20150513git1950590.el6.src.rpm
$ rpmbuild --rebuild ~/rpmbuild/SRPMS/bash-completion-2.1-8.20150513git1950590.el6.src.rpm
```

不足パッケージもなく、bash-completionのRPMパッケージがビルドできました！
忘れずにインストールしておきます。

```
$ sudo yum install -y ~/rpmbuild/RPMS/noarch/bash-completion-2.1-8.20150513git1950590.el6.noarch.rpm
```

さて、気を取り直して、これで先ほどの`yum-builddep`コマンドが正常に実行できるはずです。

```
$ sudo yum-builddep -y ~/rpmbuild/SRPMS/git-2.6.2-1.el6.src.rpm
```

上手く行ったら、ようやくgitパッケージのビルドです！

```
$ rpmbuild --rebuild ~/rpmbuild/SRPMS/git-2.6.2-1.el6.src.rpm

〜(略)〜

RPM ビルドエラー:
    インストール済み(ただし未伸張)ファイルが見つかりました:
   /usr/share/doc/git-2.6.2/git-subtree.html
```

### 「エラー: インストール済み(ただし未伸張)ファイルが見つかりました」

このように、他のディストリビューションからSRPMを借りてきた場合、そのままビルドできない場合が多いですが、経験上、Fedoraは同じRHEL系なので、まだ互換性は高い方だと思います。
例えば今回の「git-2.6.2-1.fc24.src.rpm」は、名前が示す通り「Fedora 24」に準拠したSRPMと推測されます。

* 要するに、状況に応じて最適なspecファイルを用意しましょう、ということです。
* ソフトウェアによっては、配布物にspecファイルが同梱されているものもあるので、ありがたく利用しましょう。

今回のケースでは「インストール済み(ただし未伸張)ファイルが見つかりました」というエラーが表示されます。
これは簡単に言うと、 **ビルドしたファイル群のうち、パッケージされていないファイルがあるよ（取りこぼしがあるよ）** という意味です。
こういった場合には、`--define="__check_files %{nil}"`というオプションを用いて、チェック処理を抑制する事ができます。

```
$ rpmbuild --rebuild --define="__check_files %{nil}" ~/rpmbuild/SRPMS/git-2.6.2-1.el6.src.rpm
```

### ビルドは成功したものの・・・

これでようやくgit-2.6.2パッケージのビルドに成功しました！
`~/rpmbuild/RPMS/x86_64`と`~/rpmbuild/RPMS/noarch`ディレクトリ配下にRPMファイルが生成されます。
これらをひとつずつインストールすると、依存関係のせいで上手く行かないので、下記のように一度にファイルを指定してインストールします。

```
$ find ~/rpmbuild/RPMS -name "*.rpm" -exec sudo yum install -y {} +
```

しかし・・・ここでまたエラー。

```
エラー: パッケージ: git-svn-2.6.2-1.el6.x86_64 (/git-svn-2.6.2-1.el6.x86_64)
             要求: perl-Digest-MD5
 問題を回避するために --skip-broken を用いることができません
 これらを試行できます: rpm -Va --nofiles --nodigest
```

ここで着目すべきは

```
             要求: perl-Digest-MD5
```

の部分です。気を取り直して、`~/rpmbuild/SPECS/git.spec`の中身を注意深く追っていくことにしましょう。

```
$ grep -n 'perl-Digest-MD5' ~/rpmbuild/SPECS/git.spec
224:Requires:       perl-Digest-MD5
715:- git-svn - added requires for perl-Digest-MD5 (#1218176)
```

というわけで、224行目が怪しいのですが、「perl-Digest-MD5」は、「PerlのDigest::MD5モジュール」のパッケージ名を表しています。
また、「Requires:」とあるので、これはgitに必要なパッケージであることを示しています。
以上の手がかりを元にもう少し見ていきましょう。

```
$ grep -n 'Requires:' ~/rpmbuild/SPECS/git.spec | grep perl
97:Requires:       perl(Error)
99:Requires:       perl(Term::ReadKey)
101:Requires:       perl-Git = %{version}-%{release}
142:Requires:       perl-Git = %{version}-%{release}
144:Requires:       perl(Term::ReadKey)
224:Requires:       perl-Digest-MD5
226:Requires:       perl(Term::ReadKey)
239:Requires:	perl-DBD-SQLite
249:Requires:       git = %{version}-%{release}, perl-Git = %{version}-%{release}
250:Requires:       perl(Authen::SASL)
251:Requires:       perl(Net::SMTP::SSL)
283:BuildRequires:  perl(Error), perl(ExtUtils::MakeMaker)
284:Requires:       perl(Error)
285:Requires:       perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
297:Requires:       perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
```

同じPerlモジュールでも、2種類の指定方法があるようですね。
ハイフンで単語を繋げる形式と、カッコとコロンで区切られた形式の2種類に大別できるようです。
説明は省きますが、前者は **RPMパッケージ名** 、後者は **Perlモジュール名** を示しています。

先ほどのエラーが示す通り、「perl-Digest-MD5なんてパッケージはCentOS 6.7には無いよ」ということなのですが、実は、 **Rawhideでは「perl-Digest-MD5」という個別のパッケージが存在する** のに対し、 **CentOS 6.7では、「perl」パッケージに含まれます。**

以上を踏まえると、224行目を

```git.spec
224:Requires:       perl(Digest::MD5)
```

このように修正すれば良いということになります。
同じRHEL系といえども、ディストリビューションやバージョンの違いで微妙な差異があるため、前提となる標準パッケージの違いや、それらの依存関係については十分留意する必要があります。

### ようやくインストールまで成功！

`~/rpmbuild/SPECS/git.spec`を修正したら、もう一度SRPMの作成からやり直しです。

```
$ rpmbuild -bs ~/rpmbuild/SPECS/git.spec
$ sudo yum-builddep -y ~/rpmbuild/SRPMS/git-2.6.2-1.el6.src.rpm
$ rpmbuild --rebuild --define="__check_files %{nil}" ~/rpmbuild/SRPMS/git-2.6.2-1.el6.src.rpm
$ find ~/rpmbuild/RPMS -name "*.rpm" -exec sudo yum install -y {} +
```

これでようやくインストールも成功です！
きちんとパッケージされているかどうか、インストール後の動作確認も忘れずに。

## パッケージをWebにアップロード

期待通りのパッケージが作成できたら、Webから閲覧できる領域にRPMファイルをアップロードします。
64ビット版のCentOSなら、`*.x86_64.rpm`と`*.noarch.rpm`の2種類のRPMが作成されますので、これらを同一ディレクトリにアップロードします。

ちなみに`x86_64`は、「64ビット版IntelCPUアーキテクチャ」を意味し、`noarch`は「CPUアーキテクチャに依存しないパッケージ」を意味します。
32ビット版のCentOSなら、`*.noarch.rpm`の他に`*.i686.rpm`や`*.i386.rpm`などが生成されます。

`*.src.rpm`はアップロードしなくて構いません。

## createrepoコマンドとyum設定ファイルでリポジトリとして認識させる

RPMファイルが無事作成できたので、`yum`から利用できるようにするための準備に取りかかります。
サーバ側で`createrepo`コマンドを実行し、クライアント側で設定ファイルを用意します。

### createrepoコマンド

```
$ man createrepo
```

```
NAME
       createrepo - Create repomd (xml-rpm-metadata) repository

SYNOPSIS
       createrepo [options] <directory>

DESCRIPTION
       createrepo  is a program that creates a repomd (xml-based rpm metadata)
       repository from a set of rpms.

〜(略)〜
```

**createrepo = RPMファイルをもとにリポジトリのメタデータを作成するコマンド** です。

例えば[ここ](http://ftp.riken.jp/Linux/centos/6/os/x86_64/)（理研のミラーサイト）もyumリポジトリですが、構造を良く見ると、`repodata`というディレクトリがあり、ここにメタデータが格納されています。
`createrpo`コマンドは、この`repodata`ディレクトリ（とその中身）を作成する事ができます。
`yum`コマンドは、このメタデータを読み取ることによって、リポジトリに登録されているRPMパッケージを認識しています。

`createrepo`は **RPMファイル単体ではなく、RPMを配置したディレクトリ全体に作用するコマンド** ですので、対象とするディレクトリの内容に変更があれば、その都度メタデータの更新が必要となります。

当然サーバ側での作業が必要となりますので、サーバ側で`createrepo`が実行できない場合は、ローカルに同様の環境を用意して`repodata`ごと上書きアップロードします。

### createrepoのインストール

`createrepo`は同名のcreaterepoパッケージにて提供されます。

```
$ sudo yum install -y createrepo
```

使い方は上記の`man createrepo`の通りです。

### yum設定ファイルの作成

さて、いよいよクライアント側でyumを利用するため、yumに上記のWeb領域を認識させます。
yumがWeb領域をリポジトリとして認識するために、`/etc/yum.repos.d`配下に`*.repo`ファイルを配置します。
下記に`*.repo`ファイルの内容例を示します。

```
$ cat /etc/yum.repos.d/example.repo
[example]
name=My packages
baseurl=http://example.com/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
```

`$releasever`はCentOS 6.xなら「6」、CentOS 7.xなら「7」が適用されます。
`$basearch`は64ビット版なら「x86_64」、32ビット版なら「i386」が適用されます。

今回はGPG署名の説明は端折ったので、`gpgcheck=0`としていますが、署名されたパッケージの場合は`gpgcheck=1`とし、公開鍵のアップロードが必要です。

## おわりに

以上のような手順で、実際に[epel](https://fedoraproject.org/wiki/EPEL/ja)や[remi](http://rpms.famillecollet.com/)と同じようなことが実現できます。
上記の`*.repo`のみをインストールするためだけのパッケージを用意すれば、導入も容易になり便利です。
また、リポジトリ用のページを生成したい場合は`repoview`というコマンドを利用することもできるようですので調べてみてください（誰かまとめてくださいｗ）。