ノリでシェル(dash)のソースコードを読んでみた（1日目）〜sourceからインストール〜

#なぜ？
僕には、Linux、OSをもっとよく知りたいという漠然とした欲求があります
いや、じゃあカーネルのコード読めよって話ですがまずは身近な所から始めようと思った所存でございます。

bashとかzshとかは、ソースコードがあまりにも大きすぎるので、小さめのdashでshellがどういう風に作られているかを見ていきたいと思います。


#はじめに

##前提のスキル(というか僕の経験)
- Linuxの基礎スキル
    - OpenStack構築やWEBサービス開発で基礎的なLinuxスキルはきっとあるのでしょう
- 何かしらのプログラミング言語経験
    - WEBサービスをスクラッチで書いた経験(４年以上前ですが。。)
    - PythonのOSSへのバグパッチ提供

ただ上記を見ていただいて分かるように、C言語を使ってバリバリ商用コードを書いていたわけではないので、文法などは適宜調べながら読んでいきます。完走できるか分かりませんが、きっと大丈夫でしょう

##バージョン and ソースコード

バージョンは、0.5.9.1を読むことにします。
ソースコードは、適当にここから取ってきました

```
$curl -O http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.9.1.tar.gz
$tar xzvf dash-0.5.9.1.tar.gz
```
というわけで、ソースコードが手に入ったので読み進めていきます


## ディレクトリー構造

```
ukinau$ ls dash-0.5.9.1
COPYING      Makefile.am  aclocal.m4   configure    depcomp      missing
ChangeLog    Makefile.in  config.h.in  configure.ac install-sh   src
```

ChangeLogやCOPYINGは、明確なので説明を省きますがその他のMakefile.amやaclocal.m4について、目的を調べます。普段pythonやrubyなどで開発をしてる人には、これらはあまり馴染みのないものだと思います。


| file        | what for           |
| ------------- |:-------------:| 
| **Makefile.am**      | Makefileの雛型のMakefile.inを生成するためのファイル    |
| **configure.ac** | configureの雛形      |
| **src** |     dashのソースコード  |
| Makefile.in | automakeによって生成される、Makefile.amからMakefile.inを生成。      |
| depcomp | automake --add-missing が用意してくれることのあるスクリプト。ファイルの依存関係を自動的に調べてくれる     |
| missing | automake --add-missing が用意してくれるスクリプト。忘れ物を教えてくれる。   |
| install-sh |   automake --add-missing が用意してくれるスクリプト。make installのときに使われることがある。    |
| config.h.in | autoheaderによって生成される      |
| aclocal.m4 | aclocalによって生成される     |
| configure | configure.acを元にautoconfが生成する     |

調べてみると、boldした文字以外のファイルは、autotoolsによって生成される中間ファイルであることがわかります。ですので、１度全部削除して１からビルドして見ましょう。（なんで、中間ファイルがそのままtarballに入っていたんだろう。。。）

# dashをソースからインストールしてみる

## ディレクトリ構造

ここからダウンロードしたdashディレクトリから、色々中間ファイルを削除して
http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.9.1.tar.gz

下記のようなファイルだけにする

```
ukinau$ rm -fr aclocal.m4 configure depcomp missing Makefile.in config.h.in install-sh
ukinau$ ls
COPYING      ChangeLog    Makefile.am  configure.ac src
```

## 1. aclocal

```
ukinau$ aclocal
ukianu$ ls
COPYING        ChangeLog      Makefile.am    aclocal.m4     autom4te.cache configure.ac   src
```
aclocal.m4とautom4te.cacheが生成された。

### aclocalとは
ここで少し脱線、「aclocalとはなんだろうか」調べて見た
https://stackoverflow.com/questions/1970926/whats-the-point-of-aclocal
https://cpplover.blogspot.jp/2013/07/gnuautotools.html
https://www.lrde.epita.fr/~adl/dl/autotools.pdf (まだ読んでない...)


どうやら上記サイトに詳しい説明が載っている
Autoconfには、Macroという概念があり複雑な処理を１つの定義にまとめている。
ただ、Autoconfが読み込めるMacroの定義ファイルは１つと決まっているので、
Macroが定義されているファイルをかき集めて、aclocal.m4という１つのファイルにしている。
でaclocalがそのファイルをconfigure.acを元に生成してくれる

## 2. autoconf

```
ukinau$ autoconf
ukinau$ ls
COPYING        ChangeLog      Makefile.am    aclocal.m4     autom4te.cache configure      configure.ac   src
```
configureというファイルが生成された

### autoconfとは

configure.acを元にconfigureを生成するソフトウェア
configure.acは、autoscanでsrc配下のCプログラムから自動生成することもできますが、今回のdashのケースでは、すでに定義済みのconfigure.acが用意されてますのでそれを元にしています。


## 3. autoheader

```
ukinau$ autoheader
ukinau$ ls
COPYING          Makefile.am      config.h.in      configure.ac     src
ChangeLog        autom4te.cache   configure        
```
config.h.inというファイルが生成された

### autoheaderとは

http://markuskimius.wikidot.com/programming:tut:autotools:3
https://www.gnu.org/software/autoconf/manual/autoconf-2.66/html_node/autoheader-Invocation.html

autoheaderは、configure.acを元にconfig.h.inというファイルを生成する
config.h.inは、config.hの元になるファイルである。
環境情報を元に定数の値を操作するような定義ファイルがconfig.h.inであり、configureによってconfig.hになる。
config.hが必要なモチベーションは、[ここ](http://markuskimius.wikidot.com/programming:tut:autotools:3)のサイトが非常にわかりやすい
 

## 4. automake

```
ukinau$ automake --add-missing
configure.ac:8: installing './compile'
configure.ac:2: installing './install-sh'
configure.ac:2: installing './missing'
src/Makefile.am:21: warning: source file 'bltin/printf.c' is in a subdirectory,
src/Makefile.am:21: but option 'subdir-objects' is disabled
automake: warning: possible forward-incompatibility.
automake: At least a source file is in a subdirectory, but the 'subdir-objects'
automake: automake option hasn't been enabled.  For now, the corresponding output
automake: object file(s) will be placed in the top-level directory.  However,
automake: this behaviour will change in future Automake versions: they will
automake: unconditionally cause object files to be placed in the same subdirectory
automake: of the corresponding sources.
automake: You are advised to start using 'subdir-objects' option throughout your
automake: project, to avoid future incompatibilities.
src/Makefile.am:21: warning: source file 'bltin/test.c' is in a subdirectory,
src/Makefile.am:21: but option 'subdir-objects' is disabled
src/Makefile.am:21: warning: source file 'bltin/times.c' is in a subdirectory,
src/Makefile.am:21: but option 'subdir-objects' is disabled
src/Makefile.am: installing './depcomp'
ukinau$ ls
COPYING        Makefile.am    aclocal.m4     compile        configure      depcomp        missing
ChangeLog      Makefile.in    autom4te.cache config.h.in    configure.ac   install-sh     src
```

compile, depcomp, missing, install-sh, Makefile.inが生成された
しかし、compile, depcomp, missing, install-shはautomakeパッケージに含まれるシェルスクリプトのシンボリックリンクである。これらは --add-missing をつけることで生成される

```
ukinau$ ls -l | grep -e depcomp -e install-sh -e missing -e compile
lrwxr-xr-x   1 ukinau  staff      61  3 Dec 20:42 compile -> /usr/local/Cellar/automake/1.15.1/share/automake-1.15/compile
lrwxr-xr-x   1 ukinau  staff      61  3 Dec 20:42 depcomp -> /usr/local/Cellar/automake/1.15.1/share/automake-1.15/depcomp
lrwxr-xr-x   1 ukinau  staff      64  3 Dec 20:42 install-sh -> /usr/local/Cellar/automake/1.15.1/share/automake-1.15/install-sh
lrwxr-xr-x   1 ukinau  staff      61  3 Dec 20:42 missing -> /usr/local/Cellar/automake/1.15.1/share/automake-1.15/missing
```

Makefile.inはMakefileの元になるファイルである


## 5. configure

configureは、「config.h.in, Makefile.in」を 「config.h, Makefile」に変換してくれる

```
ukinau$ ./configure
ukinau$ ls
COPYING        Makefile.am    autom4te.cache config.h.in    configure      install-sh     stamp-h1
ChangeLog      Makefile.in    compile        config.log     configure.ac   missing
Makefile       aclocal.m4     config.h       config.status  depcomp        src
```
内部では、config.statusを生成後、config.statusを実行することで「config.h, Makefile」を生成している

## 6. make

```
ukinau$ make
ukinau$ ls -l src | grep -e '^...x'
drwxr-xr-x  6 ukinau  staff     204 23 Sep  2016 bltin
-rwxr-xr-x  1 ukinau  staff  141588  3 Dec 21:05 dash
-rwxr-xr-x  1 ukinau  staff   15864  3 Dec 21:05 mkinit
drwxr-xr-x  3 ukinau  staff     102  3 Dec 21:05 mkinit.dSYM
-rwxr-xr-x  1 ukinau  staff   14192  3 Dec 21:05 mknodes
drwxr-xr-x  3 ukinau  staff     102  3 Dec 21:05 mknodes.dSYM
-rwxr-xr-x  1 ukinau  staff    9444  3 Dec 21:05 mksignames
drwxr-xr-x  3 ukinau  staff     102  3 Dec 21:05 mksignames.dSYM
-rwxr-xr-x  1 ukinau  staff   13680  3 Dec 21:05 mksyntax
drwxr-xr-x  3 ukinau  staff     102  3 Dec 21:05 mksyntax.dSYM
```
実行可能ファイルがいくつかsrcディレクトリ配下に作成されていることがわかります。

## buildしたdashをloginシェルにしてみる

ログインshellに指定するために、/etc/shells にdash実行ファイルを追加

```
ukinau$ echo /Users/ukinau/dash-0.5.9.1/src/dash >> /etc/shells
```
これをしないとnon-standard shellと言われて変更できません

```
ukinau$ sudo chsh -s /Users/ukinau/dash-0.5.9.1/src/dash ukinau
ukinau$ su ukinau
$
```
とビルドしたdashがログインシェルに設定できるとこまで確認しました
ここまでできたので、もし拡張したりしたらビルドし直すことによって自分だけのshellが作れそうです。
まぁそんなことはしないのですが。遊びでもできることが大事です。

## 考察

なんだか薄っぺらい情報しか載せていませんが、なんとなくどういうプロセスでインストールされるのかわかった気がするので、ちょっと整理します。

configure.acとMakefile.amが大元になっており、ゴールは、Makefileを作ること。
configure.acには、どのような条件でどのような定数を指定するかみたいな定義が羅列されておりマクロが大量に使われている。
マクロは、automakeパッケージに含まれているものも使われている。しかし、前述のようにデフォルトで使えないマクロもあるので、aclocalを使って、それらのマクロ定義ファイルのマクロをaclocal.m4にコピーすることで、autoconfで使えるようになる。
上述で作ったaclocal.m4のマクロを利用して、autoconfでconfigureスクリプトを生成する。
configureスクリプトは、*.inのファイルから*というファイルを生成する。環境(XXがインストールされているかなど)に応じた変数の置換がベースである。
autoheaderは、config.hの元になるconfig.inを生成するconfig.hは、プリプロセッサに処理されるの定数の定義ファイルである(モチベーションについては[ここ](http://markuskimius.wikidot.com/programming:tut:autotools:3)をみると良い)。
もちろん環境に応じて、それらの定数の値を変更したいので、configureを利用してconfig.hを生成したい。config.h.inは、configure.acでAC_DEFINE.*マクロで定義されている置換ルールが抜粋されて作られている。で最後に、automakeを利用してMakefile.inを生成する。
ここで、configure.inとMakefile.inが揃ったので、configureスクリプトで変数置換を実施して、Makefileを作る。

こうすることで、私の環境に適応したMakefileとconfig.hができて、プログラムのビルドができるようになった。

あまり深く追いすぎてもアレなので、autotoolsはどんな目的でざっくりどんなプロセスを踏むのかを見ていきました。次の投稿から実際にソースコードを読み進めたいと思います。

#参考にしたサイト

記事中に基本的には書いてありますが特に参考になるなーと思ったものを下記に記しておきます。(もちろん全部参考になりました、ありがとうございます)

* [GNU開発ツール](http://www.hpcs.cs.tsukuba.ac.jp/~tatebe/lecture/h21/proenv/01GNU.pdf)
* config.hのモチベーション[Chapter 3: Let's make "Hello, world!" portable](http://markuskimius.wikidot.com/programming:tut:autotools:3)
* Autotoolsの全体像[Autotoolsについてのメモ](http://loto.sourceforge.net/feram/Autotools-memo.ja.html#LABEL-2)
* Configure.acの文法について[autoconfで「configure」をつくろう](http://www.geocities.jp/urano343/dir4/autoconf.html)
* Autotoolsの詳細について[autotools.pdf](https://www.lrde.epita.fr/~adl/dl/autotools.pdf)
* [Autotoolsの簡単な使い方](http://d.hatena.ne.jp/i_s/20091028/1256728117)