makefile を自動生成するスクリプト書いてみた

makefile.in 必須w

#!c:/bin/ruby/bin/ruby
# -*- encoding: shift_jis
# mkconf.rb

require 'optparse'


opt     = OptionParser.new
opt.version = "0.0.1"
OPTS    = {}

DEFAULT_PREFIX      = "./bin"
DEFAULT_INCLUDEDIR  = "./include"
DEFAULT_SRCDIR      = "./src"

DEFAULT_CC          = "g++"

DEFAULT_TARGET      = Dir.pwd.split( /\// ).pop
DEFAULT_TARGET_EXT  = "exe"


opt.on( "--prefix=PREFIX", "出力ファイルの場所を指定します。" ) do |prefix|
  OPTS[:prefix]     = prefix
end

opt.on( "--includedir=INCLUDEDIR", "ヘッダファイルが存在するディレクトリを指定します。" ) do |includedir|
  OPTS[:includedir] = includedir
end

opt.on( "--srcdir=SRCDIR", "ソースが存在するディレクトリを指定します。" ) do |srcdir|
  OPTS[:srcdir]     = srcdir
end

opt.on( "-o OUTPATH", "--out=OUTPATH", "メイクファイルの位置を指定します。" ) do |outpath|
  OPTS[:outpath]    = outpath
end

opt.on( "--print-list", "ソースファイルのリストを出力して終了します。" ) do |print_list|
  OPTS[:print_list]    = print_list
end

opt.parse!( ARGV )


if OPTS.has_key? :srcdir then
  srcs  = `msys-find #{OPTS[:srcdir]} -name "*.cpp"`.split( /\n/ )
else
  srcs  = `msys-find #{DEFAULT_SRCDIR} -name "*.cpp"`.split( /\n/ )
end
if OPTS.has_key? :print_list then
  srcs.each do |src|
    puts src
  end

  exit
end

template    = ""
File.open( "makefile.in", "r" ) do |output|
  template  = output.read
end

if OPTS.has_key? :prefix then
  template.gsub!( /@prefix@/, OPTS[:prefix] )
else
  template.gsub!( /@prefix@/, DEFAULT_PREFIX )
end

if OPTS.has_key? :includedir then
  template.gsub!( /@includedir@/, OPTS[:includedir] )
  template.gsub!( /@includes@/, "-I\"#{OPTS[:includedir]}\"" )
else
  template.gsub!( /@includedir@/, DEFAULT_INCLUDEDIR )
  template.gsub!( /@includes@/, "-I\"#{DEFAULT_INCLUDEDIR}\"" )
end

if OPTS.has_key? :srcdir then
  template.gsub!( /@srcdir@/, OPTS[:srcdir] )
  re  = Regexp.compile( OPTS[:srcdir] )
else
  template.gsub!( /@srcdir@/, DEFAULT_SRCDIR )
  re  = Regexp.compile( DEFAULT_SRCDIR )
end

if OPTS.has_key? :target then
  template.gsub!( /@target@/, OPTS[:target] )
else
  template.gsub!( /@target@/, DEFAULT_TARGET )
end

if OPTS.has_key? :target_ext then
  template.gsub!( /@target_ext@/, OPTS[:target_ext] )
else
  template.gsub!( /@target_ext@/, DEFAULT_TARGET_EXT )
end

if OPTS.has_key? :cc then
  template.gsub!( /@cc@/, OPTS[:cc] )
else
  template.gsub!( /@cc@/, DEFAULT_CC )
end


srcs.collect! { |src| src.gsub( re, "$(srcdir)" ) }


def make_sourcefile_list(srcs)
  buffer = ""
  srcs.each_with_index do |item, i|
    buffer  += "src#{i} = #{item}\n"
  end
  return buffer
end


def make_objfile_list(srcs)
  buffer = ""
  srcs.each_with_index do |item, i|
    #item.gsub!( /\$\(srcdir\)/, "$(tmpdir)" ).gsub!( /\.cpp$/, ".o"  )
    obj = item.split( /\// ).pop.gsub( /\.cpp$/, ".o"  )
    p obj
    buffer  += "obj#{i} = $(tmpdir)/#{obj}\n"
  end
  objs    = []
  ([ "$(obj@n@)" ] * srcs.length).each_with_index do |obj, n|
    objs[n] = obj.gsub( /@n@/, n.to_s )
  end
  buffer    += "objs = #{objs.join( ' ' )}"

  return buffer
end


def make_phony_alls(srcs)
  buffer    = ""

  buffer    += [ ".PHONY: all",
                 "all: $(TARGET)", 
                 "",
                 "$(TARGET): $(objs)",
                 "\t$(LD) $(LFLAGS) -o $@ $^"
               ].join( "\n" )
  buffer    += "\n\n\n"

  recepis = [(["$(obj@i@): $(src@i@)", "\t$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@", "\n"]).join( "\n" )]*srcs.length
  recepis.each_with_index do |recepi, i|
    buffer += recepi.gsub( /@i@/, i.to_s )
  end

  return buffer
end

File.open( "makefile", "w" ) do |input|
  input.puts template

  input.puts

  input.puts make_sourcefile_list srcs
  input.puts
  input.puts make_objfile_list srcs
  input.puts
  input.puts make_phony_alls srcs
  input.puts
  input.puts [ ".PHONY: clean",  "clean:", "\t$(RM) -v $(TARGET) $(OBJS)" ].join( "\n" )
end