Rakefileでg++コンパイルするとき、ヘッダファイルの依存関係をインポートしてみる

Rakefileは便利なのでg++コンパイルMakefileの代替になればと思い、いろいろ模索中です。
ひとまず、簡単なメイクは作れるようになってきたところです。
で、問題が1つ浮上。
これまでMakefileでやっていたヘッダファイルの依存関係を定義していましたが、Rakefileでどう記述すればよいかわかりません。
ネットをいろいろ漁ってみたのですが、なかなか解が見つからず。。


とりあえず、自力で考えてなんとなくうまくいったっぽいRakefileをメモします。
あまり、Rakefileのドキュメント見ずに書いたのでちょっぴり不安ですが。。

CXX    = "g++"
CFLAGS = "-O2 -Wall -I./"
LIBS   = "-lm"

TARGET = "run.x"

srcs = FileList["*.cpp"]
objs = srcs.ext('o')
deps = srcs.ext('d')

task :default => :all
task :all => TARGET

require 'rake/clean'
CLEAN.include objs
CLEAN.include deps
CLOBBER.include TARGET
task :clean_all => :clobber


file TARGET => objs do |t|
  sh "#{CXX} -o #{t.name} #{t.prerequisites.join(' ')} #{LIBS}"
end

rule '.o' => ['%n.cpp', "%n.d"] do |t|
  sh "#{CXX} #{CFLAGS} -c #{t.source}"
end

srcs.each do |src|
  dep = src.sub(/\.(c|cpp)$/,".d")
  file dep => src do |t|
    tmp = `#{CXX} -MM #{CFLAGS} #{src}`
    obj,arg = tmp.gsub(/\\\n /,"").split(":")
    str = "file " + obj.inspect + " => [" + arg.split(' ').map{|m| m.inspect }.join(",") + "]"
    File.open(t.name,"w") {|f| f.write str}
  end
  import dep
end


肝となるのは、以下の記述です。

srcs.each do |src|
  dep = src.sub(/\.(c|cpp)$/,".d")
  file dep => src do |t|
    tmp = `#{CXX} -MM #{CFLAGS} #{src}`
    obj,arg = tmp.gsub(/\\\n /,"").split(":")
    str = "file " + obj.inspect + " => [" + arg.split(' ').map{|m| m.inspect }.join(",") + "]"
    File.open(t.name,"w") {|f| f.write str}
  end
  import dep
end

処理の流れは、

  • "g++ -MM"で依存関係データを取得
  • それを、"file obj => [srcs]"の形式に置換
  • その文字列を、".d"ファイルに書き込む
  • 最後に"import"で".d"をインポートする

そして、".o"を生成するruleに"%n.d"を追加。

eachを使って処理できるのがrubyっぽいかも。
あっているのかなぁ。自信なし。