Skip to content

Instantly share code, notes, and snippets.

@hisui
Created December 30, 2013 19:18
Show Gist options
  • Save hisui/8186640 to your computer and use it in GitHub Desktop.
Save hisui/8186640 to your computer and use it in GitHub Desktop.
Rakefile for building C/C++ project.
# coding: utf-8
require "ostruct"
require "fileutils"
require "pp"
require "rake/loaders/makefile"
extend FileUtils
Rake.application.options.instance_eval {
#trace = false
#trace_rules = nil
}
### 定数定義 ###
# 各種パスの設定
DEP_ROOT = "build/makedepend" # 依存関係リスト(.mf)を入れる
OBJ_ROOT = "build/obj" # CXXのオブジェクトファイルの出力先
SRC_ROOT = "src" # ソースフォルダー
# 各種ツールのコマンド
CXX = "g++" # C++ コンパイラー
LINK = "g++ -g" # リンカー
MAKEDEPEND = "g++ -MM -std=c++0x" # 依存関係リストを作るコマンド
# コンパイラーのオプション
CXXFLAGS = %w{ -Wall -g -lpthread -std=c++11 -stdlib=stdc++ }
# インポートするライブラリ
LIB = %w{}
# ヘッダー検索パス
INCLUDES = %w{}
# オブジェクトファイルは単一のディレクトリに出力されるので、パスのスラッシュの代わりに使う文字列
PATH_SEPARATOR = "___"
### 依存関係 ###
# すべてのcppファイルを集める
CXXFILES = {}
Dir[SRC_ROOT + "/**/*.cpp"].each {|filename|
if filename.index(PATH_SEPARATOR)
raise "ファイル名にPATH_SEPARATOR(#{PATH_SEPARATOR})が含まれています:#{filename}"
end
name = filename[SRC_ROOT.size+1..-1].gsub(/[\\\/]/, PATH_SEPARATOR).sub(/\.cpp$/, "")
raise "bug?? (x_x)" if CXXFILES.key? name
raise "bug?? (x_x)" if filename.index(SRC_ROOT+"/") != 0
CXXFILES[name] = OpenStruct.new({
obj: "#{OBJ_ROOT}/#{name}.o",
src: filename,
exe: nil
})
}
# エントリーポイントを含むobjファイルを実行ファイルとして出力する
EXECUTABLES = %w{ main }
EXECUTABLES.each {|name|
CXXFILES[name].exe = name +".exe"
}
### タスク ###
# デフォルトのタスク: 全ての実行ファイルを作成
exe_files = CXXFILES.values.select(&:exe).map(&:exe)
task :default => exe_files
# デバッグ用にビルド
task :debug => exe_files do |t|
CXXFLAGS.push("-g")
end
# リリース用にビルド
task :release => exe_files do |t|
CXXFLAGS.push("-O2")
end
# rakeした結果出てきたファイルを全て削除
task :clean do
$stderr.print "OK? [y/n]:"
$stderr.flush
if $stdin.gets =~/y/
rm Dir[DEP_ROOT + "/*.mf" ]
rm Dir[OBJ_ROOT + "/*.o" ]
rm Dir["." + "/*.exe"]
end
exit
end
### 依存関係 ###
# cpp, hファイルを処理
CXXFILES.each {|name, sub|
# cppファイルのコンパイル
file sub.obj => sub.src do |t|
options = []
options << CXXFLAGS.join(" ")
options << INCLUDES.map {|e| "-I#{e}" }.join(" ")
sh %Q{#{CXX} #{options.join " "} -c -o #{sub.obj} #{sub.src}}
end
# .obj -> .h の依存関係を作成
file( ( mf = "#{DEP_ROOT}/#{name}.depends.mf" ) => sub.src )do |t|
sh %Q{#{MAKEDEPEND} -MT "#{sub.obj}" "#{sub.src}" > #{mf}}
#
# rakeは "./foo/../bar" と "./bar" が同一のパスであると認識出来ないっぽいので
# ここで **makedepend によって出力された** このようなパスを修正する
#
# ※注意: パスは空白で区切られていると仮定するので、パス自体に空白が入ってる場合はNG
#
content = File.read mf
content.gsub!(/\S+(?!:)/) {|path|
1 while path.sub!( %r{[^/]+/\.\./}, "" )
path
}
open(mf, "w") {|io| io.print content }
end
import mf
}
# 実行ファイルの作成
obj_files = CXXFILES.values.reject(&:exe).map(&:obj)
CXXFILES.values.select(&:exe).each {|sub|
file sub.exe => obj_files + [sub.obj] do |t|
sh %Q{#{LINK} -o #{sub.exe} #{t.prerequisites.join " "} #{LIB.join " "}}
end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment