# File lib/inline.rb, line 315
    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)

        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 @mod.name.split("::").map { |n|
            "    c = rb_const_get_at(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
            File::compare(old_src_name, src_name, $DEBUG) 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).map { |name|
            dir = 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(' ')

          cmd = "#{Config::CONFIG['LDSHARED']} #{flags} #{Config::CONFIG['CCDLFLAGS']} #{Config::CONFIG['CFLAGS']} -I #{hdrdir} -I #{Config::CONFIG['includedir']} -o \"#{so_name}\" \"#{File.expand_path(src_name)}\" #{libs}" + crap_for_windoze
          cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG

          $stderr.puts "Building #{so_name} with '#{cmd}'" if $DEBUG
          result = `#{cmd}`
          $stderr.puts "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}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
          end

          if WINDOZE then
            Dir.chdir Inline.directory do
              cmd = "mt /manifest lib.so.manifest /outputresource:so.dll;#2"
              $stderr.puts "Embedding manifest with '#{cmd}'" if $DEBUG
              result = `#{cmd}`
              $stderr.puts "Output:\n#{result}" if $DEBUG
              if $? != 0 then
                raise CompilationError, "error executing #{cmd}: #{$?}"
              end
            end
          end

          $stderr.puts "Built successfully" if $DEBUG
        end

      else
        $stderr.puts "#{so_name} is up to date" if $DEBUG
      end # unless (file is out of date)
    end