C++でautomake

概要

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;
}