RakeでC++をビルドする

ちょっとC++ソースコード書きたいときにVisual Studio立ち上げるのが億劫になったので、Vimでさくっと書ける環境を整えてます。

ただ、ビルドするのにmakefileを書きたくなかったので色々調べてたら、RakeでC++をビルドできるみたいなので書いてみました。

環境

Rakefile

一番単純なものはネットで検索すると出てくるんですが、少し物足りなかったので機能を追加しました。

  • ビルド, リビルド, クリーンを実装
  • 中間生成物(オブジェクトファイルなど)はビルド用ディレクトリに格納
  • 依存情報ファイル(.mf)を使ってヘッダファイルの依存関係に対応

rakefile for C++ source build.

解説

使い方は最初にRakefile内の定数を編集して、

CPPFLAGS = %w[]   # コンパイルオプション
LDFLAGS  = %w[]   # リンクオプション
INC_DIRS = []     # インクルードディレクトリ
LIB_DIRS = []     # ライブラリディレクトリ
TARGET   = "app"  # 生成する実行ファイル名

SRC_ROOT = "."    # ソースファイルが格納されているディレクトリ

LIBS = FileList[] # ライブラリファイル

ビルドするときは、

$ rake

生成したファイルを削除したいときは、

$ rake clean   # オブジェクトファイルなどの中間生成物のみ削除する
$ rake clobber # 実行ファイルとビルド用ディレクトリも削除する

リビルドしたいときは、

$ rake rebuild

という感じです。

今回はヘッダーファイルを含めた依存関係を扱いたかったのでその情報を"gcc -MM"でファイルに出力してるんですが、そのファイルの情報を使うときに問題が出て苦労しました。

Rakeにはimportというメソッドがあってこれで出力したファイルを読み込めるんですが、どうもソースファイルとオブジェクトファイルが同じディレクトリにないとうまく動かないようです。
でも今回はオブジェクトファイルなんかのビルド用中間ファイルは別ディレクトリに出力したかったので、自前でファイルを読み込んで依存関係を設定してます。

その設定はオブジェクトファイルの依存ファイルをdependenciesメソッドを呼び出して(154行目)動的に行っています。
dependenciesメソッドでは、

  1. file(depfile).invokeで、対象のオブジェクトファイルと対応する依存情報ファイルとの間に依存関係を設定して解決する。(95行目)
  2. load_depfileメソッドを呼び出して対象のオブジェクトファイルが依存しているファイル名のリストを取得する。(97行目)

という処理をしていて、1で依存情報ファイルを更新する必要があるときはそのファイルのルール(160行目)が呼び出されてファイルが更新される、という仕組みです。

わかると難しくないんですが、Rubyはほとんど書いたことがない上にRakeの仕組みを勉強しつつやってたら1週間くらいかかりました。 おかげでだいぶRubyにもRakeに慣れたんですが、まだまだ腕が足りないですね。がんばります。

参考