    # File lib/ffi/library.rb, line 93
        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 "@@\#{mname} = invoker\ndef self.\#{mname}(\#{params})\n@@\#{mname}.\#{call}(\#{params})\nend\ndef \#{mname}(\#{params})\n@@\#{mname}.\#{call}(\#{params})\nend\n"
          end
          invoker
        end