FFI::Library

Constants

CURRENT_PROCESS
LIBC

Public Class Methods

extended(mod) click to toggle source
    # File lib/ffi/library.rb, line 37
37:     def self.extended(mod)
38:       raise RuntimeError.new("must only be extended by module") unless mod.kind_of?(Module)
39:     end

Public Instance Methods

attach_function(mname, a3, a4, a5=nil) click to toggle source

Attach C function name to this module.

If you want to provide an alternate name for the module function, supply it after the name, otherwise the C function name will be used.#

After the name, the C function argument types are provided as an Array.

The C function return type is provided last.

     # File lib/ffi/library.rb, line 93
 93:     def attach_function(mname, a3, a4, a5=nil)
 94:       cname, arg_types, ret_type = a5 ? [ a3, a4, a5 ] : [ mname.to_s, a3, a4 ]
 95: 
 96:       # Convert :foo to the native type
 97:       arg_types.map! { |e| find_type(e) }
 98:       has_callback = arg_types.any? {|t| t.kind_of?(FFI::CallbackInfo)}
 99:       options = Hash.new
100:       options[:convention] = defined?(@ffi_convention) ? @ffi_convention : :default
101:       options[:type_map] = @ffi_typedefs if defined?(@ffi_typedefs)
102:       options[:enums] = @ffi_enums if defined?(@ffi_enums)
103: 
104:       # Try to locate the function in any of the libraries
105:       invokers = []
106:       ffi_libraries.each do |lib|
107:         begin
108:           invokers << FFI.create_invoker(lib, cname.to_s, arg_types, find_type(ret_type), options)
109:         rescue LoadError => ex
110:         end if invokers.empty?
111:       end
112:       invoker = invokers.compact.shift
113:       raise FFI::NotFoundError.new(cname.to_s, ffi_libraries.map { |lib| lib.name }) unless invoker
114: 
115:       # Setup the parameter list for the module function as (a1, a2)
116:       arity = arg_types.length
117:       params = (1..arity).map {|i| "a#{i}" }.join(",")
118: 
119:       # Always use rest args for functions with callback parameters
120:       if has_callback || invoker.kind_of?(FFI::VariadicInvoker)
121:         params = "*args, &block"
122:       end
123:       call = arity <= 3 && !has_callback && !invoker.kind_of?(FFI::VariadicInvoker)? "call#{arity}" : "call"
124: 
125:       #
126:       # Attach the invoker to this module as 'mname'.
127:       #
128:       if !has_callback && !invoker.kind_of?(FFI::VariadicInvoker)
129:         invoker.attach(self, mname.to_s)
130:       else
131:         self.module_eval           @@#{mname} = invoker          def self.#{mname}(#{params})            @@#{mname}.#{call}(#{params})          end          def #{mname}(#{params})            @@#{mname}.#{call}(#{params})          end
132:       end
133:       invoker
134:     end
attach_variable(mname, a1, a2 = nil) click to toggle source
     # File lib/ffi/library.rb, line 143
143:     def attach_variable(mname, a1, a2 = nil)
144:       cname, type = a2 ? [ a1, a2 ] : [ mname.to_s, a1 ]
145:       address = nil
146:       ffi_libraries.each do |lib|
147:         begin
148:           address = lib.find_variable(cname.to_s)
149:           break unless address.nil?
150:         rescue LoadError
151:         end
152:       end
153: 
154:       raise FFI::NotFoundError.new(cname, ffi_libraries) if address.nil? || address.null?
155:       if type.is_a?(Class) && type < FFI::Struct
156:         # If it is a global struct, just attach directly to the pointer
157:         s = type.new(address)
158:         self.module_eval           @@ffi_gvar_#{mname} = s          def self.#{mname}            @@ffi_gvar_#{mname}          end, __FILE__, __LINE__
159: 
160:       else
161:         sc = Class.new(FFI::Struct)
162:         sc.layout :gvar, find_type(type)
163:         s = sc.new(address)
164:         #
165:         # Attach to this module as mname/mname=
166:         #
167:         self.module_eval           @@ffi_gvar_#{mname} = s          def self.#{mname}            @@ffi_gvar_#{mname}[:gvar]          end          def self.#{mname}=(value)            @@ffi_gvar_#{mname}[:gvar] = value          end, __FILE__, __LINE__
168: 
169:       end
170: 
171:       address
172:     end
callback(*args) click to toggle source
     # File lib/ffi/library.rb, line 187
187:     def callback(*args)
188:       raise ArgumentError, "wrong number of arguments" if args.length < 2 || args.length > 3
189:       name, params, ret = if args.length == 3
190:         args
191:       else
192:         [ nil, args[0], args[1] ]
193:       end
194: 
195:       options = Hash.new
196:       options[:convention] = defined?(@ffi_convention) ? @ffi_convention : :default
197:       options[:enums] = @ffi_enums if defined?(@ffi_enums)
198:       cb = FFI::CallbackInfo.new(find_type(ret), params.map { |e| find_type(e) }, options)
199: 
200:       # Add to the symbol -> type map (unless there was no name)
201:       unless name.nil?
202:         @ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
203:         @ffi_callbacks[name] = cb
204:       end
205: 
206:       cb
207:     end
enum(*args) click to toggle source
     # File lib/ffi/library.rb, line 226
226:     def enum(*args)
227:       #
228:       # enum can be called as:
229:       # enum :zero, :one, :two  # unnamed enum
230:       # enum [ :zero, :one, :two ] # equivalent to above
231:       # enum :foo, [ :zero, :one, :two ] create an enum named :foo
232:       #
233:       name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array)
234:         [ args[0], args[1] ]
235:       elsif args[0].kind_of?(Array)
236:         [ nil, args[0] ]
237:       else
238:         [ nil, args ]
239:       end
240:       @ffi_enums = FFI::Enums.new unless defined?(@ffi_enums)
241:       @ffi_enums << (e = FFI::Enum.new(values, name))
242: 
243:       # If called as enum :foo, [ :zero, :one, :two ], add a typedef alias
244:       typedef(e, name) if name
245:       e
246:     end
enum_type(name) click to toggle source
     # File lib/ffi/library.rb, line 248
248:     def enum_type(name)
249:       @ffi_enums.find(name) if defined?(@ffi_enums)
250:     end
enum_value(symbol) click to toggle source
     # File lib/ffi/library.rb, line 252
252:     def enum_value(symbol)
253:       @ffi_enums.__map_symbol(symbol)
254:     end
ffi_convention(convention) click to toggle source
    # File lib/ffi/library.rb, line 73
73:     def ffi_convention(convention)
74:       @ffi_convention = convention
75:     end
ffi_lib(*names) click to toggle source
    # File lib/ffi/library.rb, line 41
41:     def ffi_lib(*names)
42: 
43:       ffi_libs = names.map do |name|
44:         if name == FFI::CURRENT_PROCESS
45:           FFI::DynamicLibrary.open(nil, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_LOCAL)
46:         else
47:           libnames = (name.is_a?(::Array) ? name : [ name ]).map { |n| [ n, FFI.map_library_name(n) ].uniq }.flatten.compact
48:           lib = nil
49:           errors = {}
50: 
51:           libnames.each do |libname|
52:             begin
53:               lib = FFI::DynamicLibrary.open(libname, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_LOCAL)
54:               break if lib
55:             rescue Exception => ex
56:               errors[libname] = ex
57:             end
58:           end
59: 
60:           if lib.nil?
61:             raise LoadError.new(errors.values.join('. '))
62:           end
63: 
64:           # return the found lib
65:           lib
66:         end
67:       end
68: 
69:       @ffi_libs = ffi_libs
70:     end
ffi_libraries() click to toggle source
    # File lib/ffi/library.rb, line 78
78:     def ffi_libraries
79:       raise LoadError.new("no library specified") if !defined?(@ffi_libs) || @ffi_libs.empty?
80:       @ffi_libs
81:     end
find_type(name) click to toggle source
     # File lib/ffi/library.rb, line 256
256:     def find_type(name)
257:       code = if defined?(@ffi_typedefs) && @ffi_typedefs.has_key?(name)
258:         @ffi_typedefs[name]
259:       elsif defined?(@ffi_callbacks) && @ffi_callbacks.has_key?(name)
260:         @ffi_callbacks[name]
261:       elsif name.is_a?(Class) && name < FFI::Struct
262:         FFI::NativeType::POINTER
263:       elsif name.kind_of?(FFI::Type)
264:         name
265:       end
266:       if code.nil? || code.kind_of?(Symbol)
267:         FFI.find_type(name)
268:       else
269:         code
270:       end
271:     end
typedef(current, add, info=nil) click to toggle source
     # File lib/ffi/library.rb, line 209
209:     def typedef(current, add, info=nil)
210:       @ffi_typedefs = Hash.new unless defined?(@ffi_typedefs)
211:       code = if current.kind_of?(FFI::Type)
212:         current
213:       elsif current == :enum
214:         if add.kind_of?(Array)
215:           self.enum(add)
216:         else
217:           self.enum(info, add)
218:         end
219:       else
220:         @ffi_typedefs[current] || FFI.find_type(current)
221:       end
222: 
223:       @ffi_typedefs[add] = code
224:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.