module FFI::Library

def attach_function(mname, a3, a4, a5=nil)

def attach_function(mname, a3, a4, a5=nil)
  cname, arg_types, ret_type = a5 ? [ a3, a4, a5 ] : [ mname.to_s, a3, a4 ]
  # Convert :foo to the native type
  arg_types.map! { |e| find_type(e) }
  has_callback = arg_types.any? {|t| t.kind_of?(FFI::CallbackInfo)}
  options = Hash.new
  options[:convention] = defined?(@ffi_convention) ? @ffi_convention : :default
  options[:type_map] = @ffi_typedefs if defined?(@ffi_typedefs)
  options[:enums] = @ffi_enums if defined?(@ffi_enums)
  # Try to locate the function in any of the libraries
  invokers = []
  ffi_libraries.each do |lib|
    begin
      invokers << FFI.create_invoker(lib, cname.to_s, arg_types, find_type(ret_type), options)
    rescue LoadError => ex
    end if invokers.empty?
  end
  invoker = invokers.compact.shift
  raise FFI::NotFoundError.new(cname.to_s, ffi_libraries.map { |lib| lib.name }) unless invoker
  # Setup the parameter list for the module function as (a1, a2)
  arity = arg_types.length
  params = (1..arity).map {|i| "a#{i}" }.join(",")
  # Always use rest args for functions with callback parameters
  if has_callback || invoker.kind_of?(FFI::VariadicInvoker)
    params = "*args, &block"
  end
  call = arity <= 3 && !has_callback && !invoker.kind_of?(FFI::VariadicInvoker)? "call#{arity}" : "call"
  #
  # Attach the invoker to this module as 'mname'.
  #
  if !has_callback && !invoker.kind_of?(FFI::VariadicInvoker)
    invoker.attach(self, mname.to_s)
  else
    self.module_eval <<-code
      @@#{mname} = invoker
      def self.#{mname}(#{params})
        @@#{mname}.#{call}(#{params})
      end
      def #{mname}(#{params})
        @@#{mname}.#{call}(#{params})
      end
    code
  end
  invoker
end