概要
automakeを使ってc++のmakefileを自動生成してみた。 automakeの使い方習得がメインなので、ソースコードは最小限になってます。
環境構築
まずbrew経由でautomakeのインストール。
$ brew install automake
コンパイラはg++を使う。
$ which g++ /usr/bin/g++
ルートディレクトリを作成し(以下/とする)、構成は以下の通り。
└── src └── foo ├── main.cpp ├── myclass.cpp └── myclass.hpp
ファイルの準備
ユーザ側ではルートディレクトリでconfigure.acを1つ、各フォルダ下でMakefile.amを準備する必要がある。 今回の場合は/configure.ac, /Makefile.am, foo/Makefile.am, foo/src/Makefile.am の4つのファイルが必要。
configure.ac
ルートでautoscanの実行。 そうするとconfigure.acの元となるconfigure.scan(とautoscan.log)が作成される。
/ $ autoscan
/ $ ls
Makefile.am autoscan.log configure.scan src/
configure.scanをconfigure.acに名前変更し、中身を適宜編集。
/ $ mv configure.scan configure.ac
/ $ vi configure.ac
色々オプションがあるようだが、今回の手順では少なくとも以下2点の対応が必要。
- AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])のパラメータ設定
- AM_INIT_AUTOMAKEはautomakeのオプション追加
AM_INIT_AUTOMAKEはautomakeのオプションを指定することができ、ここではforeignオプションを指定。 後述するように、autmakeにinstallオプションを付けて実行すると、実行時に必要なファイルを自動生成してくれるが、 foreignを指定することで、NEWS, COPYING, AUTHORS, ChangeLog, READMEの自動生成を防ぐ。 詳しくはAutotools Mythbusterを参照。
# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.71]) AC_INIT([foo], [0.1], [foo@bar.com]) AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_SRCDIR([src/foo/myclass.hpp]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CXX # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_CONFIG_FILES([Makefile src/Makefile src/foo/Makefile]) AC_OUTPUT
automakeは上記以外にも色々マクロがある。詳しくは例えばこちら。
Makefile.am
ここでは最低限の書き方のみ触れる。 詳細はこちら。
/Makefile.am
SUBDIRS = src
/src/Makefile.am
SUBDIRS にサブディレクトリ一覧を指定。
SUBDIRS = foo
/src/foo/Makefile.am
bin_PROGRAMSに実行ファイル名、foo_SOURCESに実行ファイル生成に必要なファイル一覧を羅列。
bin_PROGRAMS = exe exe_SOURCES = myclass.cpp myclass.hpp main.cpp
ここまでユーザ側の準備は完了。
├── Makefile.am └── src ├── Makefile.am └── foo ├── Makefile.am ├── main.cpp ├── myclass.cpp └── myclass.hpp
automakeの実行
3ファイルの準備ができたらあとはautoreconfを実行するのみ autoreconfを使ってconfigu.hとsrc/Makefile, src/foo/Makefileを生成。installオプションを付けると、必要なファイルを自動生成してくれる。
/ $ autoreconf --install configure.ac:6: installing './install-sh' configure.ac:6: installing './missing' src/foo/Makefile.am: installing './depcomp' / $ ls Makefile.am Makefile.in aclocal.m4 autom4te.cache/ autoscan.log config.h.in configure* configure.ac depcomp* install-sh* missing* src/
./configureを実行し、Makefileを作成。
/ $ ./configure
最後にmakeしてあげて、プログラムの実行
/ $ make / $ ./src/foo/exe Doing something! ok
参考
ソースコード
- /src/foo/main.cpp
#include <iostream> #include <exception> #include "myclass.hpp" int main(int, char* []) { try { N::myclass mc; mc.do_something(); std::cout << "ok" << std::endl; return 0; } catch (std::exception& e) { std::cerr << e.what() << std::endl; return 1; } catch (...) { std::cerr << "unknown error" << std::endl; return 1; } }
- /src/foo/myclass.hpp
// myclass.h #ifndef foo_myclass_hpp #define foo_myclass_hpp namespace N { class myclass { public: void do_something(); }; } #endif
- /src/foo/myclass.cpp
// header in standard library #include <iostream> // header in local directory #include "myclass.hpp" using namespace N; void myclass::do_something(){ std::cout << "Doing something!" << std::endl; }