PK
パーネルカニック研究所
今日もどこかでkernel panic。
root@pk-lab:~#

make installとは何か

連載ナビ

この連載は「Linuxを使えるようになる」ではなく、「Linuxがどう動いているのか」を理解するための実践シリーズです。

今回は Linuxを理解する 〜 LFSで学ぶLinux内部構造 〜 の Part 4 / 第3回として、仕組みのつながりを意識しながら学びます。

—

make installは「ビルド成果物を所定の場所へコピーする」だけの工程

./configure && make && make install の最後の一手、make install。名前から何か特別な「インストール処理」を想像しがちですが、結論はシンプルです。make installとは、ビルドディレクトリにできあがった成果物(実行ファイル・ライブラリ・manページなど)を、configureの --prefix で決めた場所へコピーする、Makefileの install という名前のターゲットを実行しているだけです。

つまり技術的には前回の make と何も変わりません。make が既定のターゲット(ビルド)を実行するのに対し、make install は install ターゲット(配置)を実行する。中身はほぼ install コマンド(コピーと同時に権限設定ができる cp の親戚)や mkdir の羅列です。

「作る場所」と「使う場所」を分けないと、システムが壊れるから

なぜビルドと配置をわざわざ別工程にするのでしょうか。理由は2つあります。

1つ目は、ビルドは失敗しうる作業であり、失敗する可能性のある作業を稼働中のシステムディレクトリで直接やるべきではないからです。ビルドディレクトリの中なら、何度失敗しても rm -rf してやり直せます。配置は「ビルドが成功した」と確認できた後の、最後の一歩に分離されています。

2つ目は、権限の境界がちょうどここにあるからです。ビルドは一般ユーザーの権限でできますが、既定のインストール先 /usr/local への書き込みにはroot権限が必要です。だから定番の形はこうなります。


./configure && make        # ここまでは一般ユーザー
sudo make install          # 書き込み権限が必要なのはこの一歩だけ

sudo を付けずに実行したときに出る install: cannot create regular file '/usr/local/bin/hello': Permission denied は、この権限の境界線を踏んだというサインです。逆に言えば、--prefix=$HOME/local のように自分が書き込める場所を指定していれば、sudo は一切不要です。

GNU helloで、配置の瞬間を観察する

前々回から使っているGNU helloで、実際に何がどこへ置かれるかを見ます。


cd ~/hello-2.12.1          # configure --prefix=$HOME/local 済みの前提
make
make install
find ~/local -type f | head -n 20

make install の出力には /usr/bin/install -c hello '/home/あなた/local/bin' のような行が流れ、findの結果はおおよそ次のようになります。


/home/あなた/local/bin/hello           # 実行ファイル
/home/あなた/local/share/man/man1/hello.1   # manページ
/home/あなた/local/share/info/hello.info    # infoドキュメント
/home/あなた/local/share/locale/ja/LC_MESSAGES/hello.mo  # 翻訳データ

注目してほしいのは、bin・share/man・share/locale という配置先の構造が、Part 2で学んだFHS(ファイルシステム階層標準)のミニチュアになっていることです。--prefix はこの階層全体をどこに生やすかを決めていたのだ、ということがここで腑に落ちます。~/local/bin/hello を直接実行すれば、配置されたものがそのまま動くことも確認できます。

DESTDIRを知ると、パッケージ管理の正体が見える

もう1つ、LFSや実務で重要な変数が DESTDIR です。


make DESTDIR=/tmp/pkg install
find /tmp/pkg | head -n 40

こうすると、成果物は本来の場所ではなく /tmp/pkg/home/あなた/local/bin/hello のように、指定ディレクトリの下に「本来のパス構造ごと」コピーされます。--prefix が「実行時にどこにいる前提でビルドするか」を決めるのに対し、DESTDIR は「コピー先の根っこを一時的にずらす」だけ、という役割分担です。

これが何の役に立つのか。実はdebやrpmといったパッケージは、まさにこの方法で作られています。DESTDIRで空のディレクトリにインストールさせれば「このパッケージが配置するファイルの完全な一覧」が手に入り、それをアーカイブ化したものがパッケージの実体です。逆に、素の make install には深刻な弱点があります。どこに何をコピーしたかの記録が残らず、make uninstall を用意していないプロジェクトも多いため、一度入れたものを正確に取り除くのが難しいのです。apt や dnf が偉大なのは、この「ファイル一覧の記録と削除」を肩代わりしてくれているからだ——と、make installを一度手でやると実感できます。

コピーの一歩を制する者が、システムの中身を説明できる

make installはビルド成果物を --prefix の場所へコピーするだけの工程であり、sudo が要るのは配置先の権限のせい、DESTDIR を使えば安全に検証もパッケージ化もできる——これが今回の結論です。

LFSではこの make install を約90回繰り返して /usr/bin や /usr/lib を自分の手で埋めていくので、「自分のシステムにあるファイルは、全部どのパッケージの何なのか」を説明できる状態になります。さて、配置されたバイナリの多くは、単体では動かず共有ライブラリ(.so)に依存しています。次回は、この依存の仕組みそのものである「静的リンクと動的リンク」を掘り下げます。

図解テキスト


build dir (作る場所)                    prefix (使う場所)
  hello, hello.1, ...  --make install-->  ~/local/bin/hello
                                          ~/local/share/man/man1/hello.1
                                          ...

DESTDIR指定時:
  make DESTDIR=/tmp/pkg install
    -> /tmp/pkg/ の下に prefix 以下の構造を丸ごと再現
    -> この一覧をアーカイブ化したものが deb/rpm パッケージの実体

この回で実行するコマンド

上から順番に実行すれば、この回の内容を体験できます。

まずはそのままコピペして実行し、次に1行ずつ意味を確認してください。


cd ~/hello-2.12.1
make
make install
find ~/local -type f | head -n 20
~/local/bin/hello
make DESTDIR=/tmp/pkg install
find /tmp/pkg | head -n 40

ハンズオン手順

1. ターミナルを開いて、上のコマンドを1行ずつ実行する

2. make install の出力から install -c を含む行を1つ選び、何をどこへコピーしたか読む

3. find ~/local と find /tmp/pkg の出力を見比べ、DESTDIRが何をずらしたのか説明してみる

4. エラーが出たら、そのエラーメッセージをそのまま残す(特に Permission denied は権限の境界のサイン)

チェックポイント

  • コマンドが最後まで実行できた
  • --prefix と DESTDIR の役割の違いを一言で説明できる
  • sudo make install の sudo が何のために必要か言える
  • 次の回に進む前に、分からない単語を1つ調べた

今回理解できたこと

  • installはコピー工程でありビルド工程とは別(installターゲットの実行にすぎない)
  • sudoが要るのは配置先ディレクトリの書き込み権限のため
  • DESTDIRで安全に検証でき、パッケージ作成もこの仕組みの応用
  • 素のmake installは配置記録が残らない。それを解決するのがパッケージ管理