Automakeでライブラリを作ることにチャレンジ1年生

# 要点

- Autotoolは基本的に`autoconf`と`automake`と`libtools`。ただし、libtoolsはそんなに使われない?
- autoconfはコンパイルするとき、環境依存になりやすい関数の差分を吸収する設定などを行う
- automakeはmakefileを簡単に作ってくれるツール
- libtoolsはライブラリを作るときに使用するツール。ライブラリはOSによって作られる拡張子などが変わるのでこのツールが使われる

# ショートカット

1. 何をコンパイルするかというautomake用の入力ファイル`Makefile.am`を作る
 1. 最初に何を生成するかを示す`prefix_PRIMARY = (生成ファイル名)`を書く
     - prefix: インストール先(bindir, sbindir, libexecdir, pkglibexecdir, noinstなどprefixとの相対パスで決まる。詳しくは[コチラ](https://www.gnu.org/software/automake/manual/html_node/Standard-Directory-Variables.html))
     - PRIMARY: 何を生成するか(PROGRAMS:普通のプログラム、LIBRARIES: ライブラリ, LTLIBRARIES: Libtools用の設定ファイル、HEADERS: 公開ヘッダ、DATA: データ、MANS, TEXINFOS: ドキュメント[など](https://www.gnu.org/software/automake/manual/html_node/Uniform.html)) 
  2. 生成するファイルは何からできているかを`生成ファイル名_SOURCES = ソース一覧`を書く
     - ただし、ここで`.`は`_`で置き換える。例えば、libtest.soならlibtest_so_SOURCESのように書く
     - 同様にコンパイル時のオプションは`生成ファイル名_CFLAGS = オプション`、`生成ファイル_LDFLAGS = オプション`のように書く
2. `autoreconf --install`を実行する
 1. 色々指示が出るのでconfigure.acを直す
 2. 例えば、libtoolsを作る場合は
     - LT_INITを書く
     - AM_PROG_ARを書く
     - AC_CONFIG_MACRO_DIRS([m4])を書く
     - 他にMakefile.amにACLOCAL_AMFLAGSに-l m4を書く
 3. さらに動的ライブラリを作りたい場合Makefile.amの`生成ファイル_LDFLAGS`次を追加する
     - -module
     - -export-dynamic
     - -shared 
     - -rpath $(libdir)
3. `automake`を実行する

あとは`configure; make`すれば完成ですが、ライブラリファイル(.a, .soなど)は.libディレクトリ配下に作成されます

# 動機
以前の[記事](https://qiita.com/impepc/items/75d7e4c76e942664e1e1)でAutotoolsから目を逸らしたのですが、なんとなくやっておかねばならない気がしてきたので、チャレンジしてみます。

AutotoolsはGNU Build Systemとも言って、ソースをいろんな環境でコンパイルできるようにするツールのセットのようです。[Wikipedia](https://en.wikipedia.org/wiki/GNU_Build_System)

ツール自体はつぎの3つから成り立っており、これらを組み合わせてconfigureやmakefileを作成するようです。

- autoconf
- automake
- libtools

しかし、[日本語Wikipedia](https://ja.wikipedia.org/wiki/Autotools)を見る限り、スゲェ難しそうです。
確かに環境依存しないコンパイルは大変ですが、どうして3つもツールが必要なのかとか色々考えてしまいます。

結局プログラマである自分は何を書けばいいのか、なぜ書かねばならないのか、その点を中心的に見ていこうと思います。

# Step by Step

パッと見た感じ、

まずは次のステップをするようです。

1. autoscanを実行し、configure.acを作る
2. 1.を基にaclocalを実行し、aclocal.m4を作る
3. 1.を基にautoheaderを実行し、config.h.inを作る

・・・と進めて行くようです。が、[チュートリアル](https://www.lrde.epita.fr/~adl/autotools.html)を見てみるとautoreconfなるコマンドがあり、

> ‘autoreconf’ Run all tools in the right order.

[Autotools Tutorial](https://www.lrde.epita.fr/~adl/dl/autotools.pdf)

と書かれているのでとりあえず、コレをしてみます。

```shell-session

$ autoreconf --install
autoreconf: 'configure.ac' or 'configure.in' is required
```

チッ・・・

## autoscanで環境をスキャンする

とりあえず、autoscanをしてみましょう。
マニュアルによると

>      Examine  source  files  in  the directory tree rooted at SRCDIR, or the
>      current directory if none is given.  Search the source files for common
>      portability  problems,  check for incompleteness of `configure.ac', and
>      create a file `configure.scan' which is  a  preliminary  `configure.ac'
>      for that package.

from http://manpages.ubuntu.com/manpages/yakkety/man1/autoscan.1.html


とりあえず実行すればいいのかな?

configure.scanが作られました。

`mv configure.scan configure.ac` だけして再度`autoreconf --install`を実行。

- autom4te.cache
- autoscan.log
- config.h.in
- configure
- configure.ac

が作られました。あとは、makefile.amを作るのが必要みたいですね。これだけは勉強しないと・・・

## makefile.amを作る

チュートリアルとこの[サイト](http://capm-network.com/?tag=Makefile.amの編集)に従って

```Makefile.am
SUBDIRS = src
```

```Makefile.am
noinst_LTLIBRARIES = libcheap_csv_reader.la
libcheap_csv_reader_la_SOURCES = record_read.c
```
で、再度`autoreconf --install`実行。特に何も言われなかったのでautomakeを実行。

```shell-session

configure.ac: error: no proper invocation of AM_INIT_AUTOMAKE was found.
configure.ac: You should verify that configure.ac invokes AM_INIT_AUTOMAKE,
configure.ac: that aclocal.m4 is present in the top-level directory,
configure.ac: and that aclocal.m4 was recently regenerated (using aclocal)
automake: error: no 'Makefile.am' found for any configure output
automake: Did you forget AC_CONFIG_FILES([Makefile]) in configure.ac?
```

ダメ？とりあえず`AC_CONFIG_FILES[(Makefile src/Makefile)]`と。チュートリアルにあった`AM_INIT_AUTOMAKE([foreign -Wall -Werror])`を追加して再度実行。

```shell-session

configure.ac:11: installing './compile'
configure.ac:6: installing './install-sh'
configure.ac:6: installing './missing'
src/Makefile.am:1: error: Libtool library used but 'LIBTOOL' is undefined
src/Makefile.am:1:   The usual way to define 'LIBTOOL' is to add 'LT_INIT'
src/Makefile.am:1:   to 'configure.ac' and run 'aclocal' and 'autoconf' again.
src/Makefile.am:1:   If 'LT_INIT' is in 'configure.ac', make sure
src/Makefile.am:1:   its definition is in aclocal's search path.
automake: warnings are treated as errors
/usr/local/Cellar/automake/1.15.1/share/automake-1.15/am/ltlibrary.am: warning: 'libcheap_csv_reader.la': linking libtool libraries using a non-POSIX
/usr/local/Cellar/automake/1.15.1/share/automake-1.15/am/ltlibrary.am: archiver requires 'AM_PROG_AR' in 'configure.ac'
src/Makefile.am:1:   while processing Libtool library 'libcheap_csv_reader.la'
src/Makefile.am: installing './depcomp'
autoreconf: automake failed with exit status: 1
```

おお、いっぱい出てきた。
とりあえず、1つ1つ潰していきましょう。

## libtoolsの設定を修正する

configure.acにLT_INITを追加します。また、AM_PROG_ARも必要らしいので追記します。

再度`autoreconf --install`実行。

```shell-session

glibtoolize: putting auxiliary files in '.'.
glibtoolize: copying file './ltmain.sh'
glibtoolize: Consider adding 'AC_CONFIG_MACRO_DIRS([m4])' to configure.ac,
glibtoolize: and rerunning glibtoolize and aclocal.
glibtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
configure.ac:9: installing './ar-lib'
configure.ac:10: installing './config.guess'
configure.ac:10: installing './config.sub'
```

AC_CONFIG_MACRO_DIRS([m4])を追加してみるのを考えて見てと言われたので、追加します。
また、Makefile.amにACLOCAL_AMFLAGSに-l m4を追加してみてと言われたので追加です。

```shell-session

$ autoreconf --install
aclocal: warning: couldn't open directory 'm4': No such file or directory
glibtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
glibtoolize: copying file 'm4/libtool.m4'
glibtoolize: copying file 'm4/ltoptions.m4'
glibtoolize: copying file 'm4/ltsugar.m4'
glibtoolize: copying file 'm4/ltversion.m4'
glibtoolize: copying file 'm4/lt~obsolete.m4'
```

m4がないと怒られましたが、glibtoolizeが勝手に追加してくれたみたいです。

で、`automake`を実行しても何も起きませんでした。
この時点で大量にファイルが作られておりますが、とりあえず、動くか試して見ましょう。

## configureで動くか確認

```shell-session

$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
(以下略)
```

おお、いつものアレが出てきました・・・

で、`make`をするとsrcの下にlibcheap_csv_reader.laができています。lib_cheap_csv_reader.loもできています。
・・・ただ、どちらも単なるテキストファイルなんですよね・・・
.aファイルはないのか・・・とfindをかけてみるとsrc配下の`.lib`という隠しフォルダに隠されていました。これをリンクすればいいわけですね。

## 動的ライブラリを作るには?

さて、ここで、動的ライブラリが作りたいなと思ってしまいました。

libtoolの[マニュアル](https://linuxjm.osdn.jp/html/gnumaniak/man1/libtool.1.html)を見てみると次のオプションが役に立ちそうです


>-module ダイナミックロードできるライブラリを作成する。 モジュール名は `lib' で始まる必要はないが、 名前の衝突を避けるため `libname' と `name' はパッケージの中で 同時に使用すべきではない。

> -export-dynamic OUTPUT-FILE のシンボルを dlsym(3) を使って解決できるようにする。

>-static OUTPUT-FILE がプログラムの場合、 アンインストールされた共有 libtool ライブラリはリンクしない。 OUTPUT-FILE がライブラリの場合、 静的ライブラリを作成するのみである。
```

これで、実行・・・あれ？作られない。

色々試行錯誤しているうちに次のオプションが必要なことが判明。

```
-shared
-rpath $(libdir)
```
sharedは`cc`のオプションですね。rpathは・・・動的ライブラリに必要なオプションらしいでのすが、動的のクセに自分のパスを知らないといけないのか・・・

ちなみに、`-module`オプションを外すとdylibファイルが作成されました。


# 参考
- [Autotools Tutorial](http://events.linuxfoundation.org/sites/events/files/slides/petazzoni-autotools-tutorial.pdf)
- [automake](http://web.sfc.wide.ad.jp/~sagawa/gnujdoc/automake-1.8/automake-ja_toc.html#SEC_Contents)
- [Makefile.amの編集 / Capm Network](http://capm-network.com/?tag=Makefile.amの編集)
- [即席GNU (autoconf & automake)](http://www.jaist.ac.jp/~kiyoshiy/memo/autoconf.html)
- [Automakeでmakeする / C++で開発](http://www.02.246.ne.jp/~torutk/cxx/automake/automake.html)
- [Autotoolsを使ったライブラリの管理 / Hacking to the Gate](https://sites.google.com/site/programmirovanienotes/home/wxwidgets_autotools)
- [The magic behind configure, make, make install / Giant Robots](https://robots.thoughtbot.com/the-magic-behind-configure-make-make-install)
- [Autotools ( automake, autoconf, libtool ) 使い方まとめ - たまにゃんのメモ帳](http://tamaobject.hatenablog.com/entry/2013/08/01/165119)
- [Autotoolsについてのメモ](http://loto.sourceforge.net/feram/Autotools-memo.ja.html)
- [Autotools(Wikipedia)](https://ja.wikipedia.org/wiki/Autotools)
- [Automake](GNU)(https://www.gnu.org/software/automake/)