# File lib/ffi/library.rb, line 34
  def attach_function(mname, a3, a4, a5=nil)
    cname, arg_types, ret_type = a5 ? [ a3, a4, a5 ] : [ mname.to_s, a3, a4 ]
    libraries = defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
    convention = defined?(@ffi_convention) ? @ffi_convention : :default

    # 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] = convention
    options[:type_map] = @ffi_typedefs if defined?(@ffi_typedefs)
    # Try to locate the function in any of the libraries
    invokers = []
    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, 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 "@@\#{mname} = invoker\ndef self.\#{mname}(\#{params})\n@@\#{mname}.\#{call}(\#{params})\nend\ndef \#{mname}(\#{params})\n@@\#{mname}.\#{call}(\#{params})\nend\n"
    end
    invoker
  end