def build
      so_name = self.so_name
      so_exists = File.file? so_name
      unless so_exists and File.mtime(rb_file) < File.mtime(so_name) then

        unless File.directory? Inline.directory then
          warn "NOTE: creating #{Inline.directory} for RubyInline" if $DEBUG
          Dir.mkdir Inline.directory, 0700
        end

        src_name = "#{Inline.directory}/#{module_name}.c"
        old_src_name = "#{src_name}.old"
        should_compare = File.write_with_backup(src_name) do |io|
          if @include_ruby_first
            @inc.unshift "#include \"ruby.h\""
          else
            @inc.push "#include \"ruby.h\""
          end

          io.puts
          io.puts @inc.join("\n")
          io.puts
          io.puts @src.join("\n\n")
          io.puts
          io.puts
          io.puts "#ifdef __cplusplus"
          io.puts "extern \"C\" {"
          io.puts "#endif"
          io.puts "  __declspec(dllexport)" if WINDOZE
          io.puts "  void Init_#{module_name}() {"
          io.puts "    VALUE c = rb_cObject;"

          # TODO: use rb_class2path
          # io.puts "    VALUE c = rb_path2class(#{@mod.name.inspect});"
          io.puts @mod.name.split("::").map { |n|
            "    c = rb_const_get(c,rb_intern(\"#{n}\"));"
          }.join("\n")

          @sig.keys.sort.each do |name|
            arity, singleton, method_name = @sig[name]
            if singleton then
              io.print "    rb_define_singleton_method(c, \"#{method_name}\", "
            else
              io.print "    rb_define_method(c, \"#{method_name}\", "
            end
            io.puts  "(VALUE(*)(ANYARGS))#{name}, #{arity});"
          end
          io.puts @init_extra.join("\n") unless @init_extra.empty?

          io.puts
          io.puts "  }"
          io.puts "#ifdef __cplusplus"
          io.puts "}"
          io.puts "#endif"
          io.puts
        end

        # recompile only if the files are different
        recompile = true
        if so_exists and should_compare and
            FileUtils.compare_file(old_src_name, src_name) then
          recompile = false

          # Updates the timestamps on all the generated/compiled files.
          # Prevents us from entering this conditional unless the source
          # file changes again.
          t = Time.now
          File.utime(t, t, src_name, old_src_name, so_name)
        end

        if recompile then

          hdrdir = %w(srcdir archdir rubyhdrdir).map { |name|
            Config::CONFIG[name]
          }.find { |dir|
            dir and File.exist? File.join(dir, "/ruby.h")
          } or abort "ERROR: Can't find header dir for ruby. Exiting..."

          flags = @flags.join(' ')
          libs  = @libs.join(' ')

          config_hdrdir = if RUBY_VERSION > '1.9' then
                            "-I #{File.join hdrdir, RbConfig::CONFIG['arch']}"
                          else
                            nil
                          end

          cmd = [ Config::CONFIG['LDSHARED'],
                  flags,
                  Config::CONFIG['CCDLFLAGS'],
                  Config::CONFIG['CFLAGS'],
                  '-I', hdrdir,
                  config_hdrdir,
                  '-I', Config::CONFIG['includedir'],
                  "-L#{Config::CONFIG['libdir']}",
                  '-o', so_name.inspect,
                  File.expand_path(src_name).inspect,
                  libs,
                  crap_for_windoze ].join(' ')

          # TODO: remove after osx 10.5.2
          cmd += ' -flat_namespace -undefined suppress' if
            RUBY_PLATFORM =~ /darwin9\.[01]/
          cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG

          warn "Building #{so_name} with '#{cmd}'" if $DEBUG
          result = `#{cmd}`
          warn "Output:\n#{result}" if $DEBUG
          if $? != 0 then
            bad_src_name = src_name + ".bad"
            File.rename src_name, bad_src_name
            raise CompilationError, "error executing #{cmd.inspect}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
          end

          # NOTE: manifest embedding is only required when using VC8 ruby
          # build or compiler.
          # Errors from this point should be ignored if Config::CONFIG['arch']
          # (RUBY_PLATFORM) matches 'i386-mswin32_80'
          if WINDOZE and RUBY_PLATFORM =~ /_80$/ then
            Dir.chdir Inline.directory do
              cmd = "mt /manifest lib.so.manifest /outputresource:so.dll;#2"
              warn "Embedding manifest with '#{cmd}'" if $DEBUG
              result = `#{cmd}`
              warn "Output:\n#{result}" if $DEBUG
              if $? != 0 then
                raise CompilationError, "error executing #{cmd}: #{$?}"
              end
            end
          end

          warn "Built successfully" if $DEBUG
        end

      else
        warn "#{so_name} is up to date" if $DEBUG
      end # unless (file is out of date)
    end
def build
      so_name = self.so_name
      so_exists = File.file? so_name
      unless so_exists and File.mtime(rb_file) < File.mtime(so_name) then

        unless File.directory? Inline.directory then
          warn "NOTE: creating #{Inline.directory} for RubyInline" if $DEBUG
          Dir.mkdir Inline.directory, 0700
        end

        src_name = "#{Inline.directory}/#{module_name}.c"
        old_src_name = "#{src_name}.old"
        should_compare = File.write_with_backup(src_name) do |io|
          if @include_ruby_first
            @inc.unshift "#include \"ruby.h\""
          else
            @inc.push "#include \"ruby.h\""
          end

          io.puts
          io.puts @inc.join("\n")
          io.puts
          io.puts @src.join("\n\n")
          io.puts
          io.puts
          io.puts "#ifdef __cplusplus"
          io.puts "extern \"C\" {"
          io.puts "#endif"
          io.puts "  __declspec(dllexport)" if WINDOZE
          io.puts "  void Init_#{module_name}() {"
          io.puts "    VALUE c = rb_cObject;"

          # TODO: use rb_class2path
          # io.puts "    VALUE c = rb_path2class(#{@mod.name.inspect});"
          io.puts @mod.name.split("::").map { |n|
            "    c = rb_const_get(c,rb_intern(\"#{n}\"));"
          }.join("\n")

          @sig.keys.sort.each do |name|
            arity, singleton, method_name = @sig[name]
            if singleton then
              io.print "    rb_define_singleton_method(c, \"#{method_name}\", "
            else
              io.print "    rb_define_method(c, \"#{method_name}\", "
            end
            io.puts  "(VALUE(*)(ANYARGS))#{name}, #{arity});"
          end
          io.puts @init_extra.join("\n") unless @init_extra.empty?

          io.puts
          io.puts "  }"
          io.puts "#ifdef __cplusplus"
          io.puts "}"
          io.puts "#endif"
          io.puts
        end

        # recompile only if the files are different
        recompile = true
        if so_exists and should_compare and
            FileUtils.compare_file(old_src_name, src_name) then
          recompile = false

          # Updates the timestamps on all the generated/compiled files.
          # Prevents us from entering this conditional unless the source
          # file changes again.
          t = Time.now
          File.utime(t, t, src_name, old_src_name, so_name)
        end

        if recompile then

          hdrdir = %w(srcdir archdir rubyhdrdir).map { |name|
            Config::CONFIG[name]
          }.find { |dir|
            dir and File.exist? File.join(dir, "/ruby.h")
          } or abort "ERROR: Can't find header dir for ruby. Exiting..."

          flags = @flags.join(' ')
          libs  = @libs.join(' ')

          config_hdrdir = if RUBY_VERSION > '1.9' then
                            "-I #{File.join hdrdir, RbConfig::CONFIG['arch']}"
                          else
                            nil
                          end

          cmd = [ Config::CONFIG['LDSHARED'],
                  flags,
                  Config::CONFIG['CCDLFLAGS'],
                  Config::CONFIG['CFLAGS'],
                  '-I', hdrdir,
                  config_hdrdir,
                  '-I', Config::CONFIG['includedir'],
                  "-L#{Config::CONFIG['libdir']}",
                  '-o', so_name.inspect,
                  File.expand_path(src_name).inspect,
                  libs,
                  crap_for_windoze ].join(' ')

          # TODO: remove after osx 10.5.2
          cmd += ' -flat_namespace -undefined suppress' if
            RUBY_PLATFORM =~ /darwin9\.[01]/
          cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG

          warn "Building #{so_name} with '#{cmd}'" if $DEBUG
          result = `#{cmd}`
          warn "Output:\n#{result}" if $DEBUG
          if $? != 0 then
            bad_src_name = src_name + ".bad"
            File.rename src_name, bad_src_name
            raise CompilationError, "error executing #{cmd.inspect}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
          end

          # NOTE: manifest embedding is only required when using VC8 ruby
          # build or compiler.
          # Errors from this point should be ignored if Config::CONFIG['arch']
          # (RUBY_PLATFORM) matches 'i386-mswin32_80'
          if WINDOZE and RUBY_PLATFORM =~ /_80$/ then
            Dir.chdir Inline.directory do
              cmd = "mt /manifest lib.so.manifest /outputresource:so.dll;#2"
              warn "Embedding manifest with '#{cmd}'" if $DEBUG
              result = `#{cmd}`
              warn "Output:\n#{result}" if $DEBUG
              if $? != 0 then
                raise CompilationError, "error executing #{cmd}: #{$?}"
              end
            end
          end

          warn "Built successfully" if $DEBUG
        end

      else
        warn "#{so_name} is up to date" if $DEBUG
      end # unless (file is out of date)
    end
Builds the source file, if needed, and attempts to compile it.