1require 'dl' 2require 'dl/func.rb' 3require 'dl/struct.rb' 4require 'dl/cparser.rb' 5 6module DL 7 class CompositeHandler 8 def initialize(handlers) 9 @handlers = handlers 10 end 11 12 def handlers() 13 @handlers 14 end 15 16 def sym(symbol) 17 @handlers.each{|handle| 18 if( handle ) 19 begin 20 addr = handle.sym(symbol) 21 return addr 22 rescue DLError 23 end 24 end 25 } 26 return nil 27 end 28 29 def [](symbol) 30 sym(symbol) 31 end 32 end 33 34 # DL::Importer includes the means to dynamically load libraries and build 35 # modules around them including calling extern functions within the C 36 # library that has been loaded. 37 # 38 # == Example 39 # 40 # require 'dl' 41 # require 'dl/import' 42 # 43 # module LibSum 44 # extend DL::Importer 45 # dlload './libsum.so' 46 # extern 'double sum(double*, int)' 47 # extern 'double split(double)' 48 # end 49 # 50 module Importer 51 include DL 52 include CParser 53 extend Importer 54 55 def dlload(*libs) 56 handles = libs.collect{|lib| 57 case lib 58 when nil 59 nil 60 when Handle 61 lib 62 when Importer 63 lib.handlers 64 else 65 begin 66 DL.dlopen(lib) 67 rescue DLError 68 raise(DLError, "can't load #{lib}") 69 end 70 end 71 }.flatten() 72 @handler = CompositeHandler.new(handles) 73 @func_map = {} 74 @type_alias = {} 75 end 76 77 def typealias(alias_type, orig_type) 78 @type_alias[alias_type] = orig_type 79 end 80 81 def sizeof(ty) 82 @type_alias ||= nil 83 case ty 84 when String 85 ty = parse_ctype(ty, @type_alias).abs() 86 case ty 87 when TYPE_CHAR 88 return SIZEOF_CHAR 89 when TYPE_SHORT 90 return SIZEOF_SHORT 91 when TYPE_INT 92 return SIZEOF_INT 93 when TYPE_LONG 94 return SIZEOF_LONG 95 when TYPE_LONG_LONG 96 return SIZEOF_LONG_LON 97 when TYPE_FLOAT 98 return SIZEOF_FLOAT 99 when TYPE_DOUBLE 100 return SIZEOF_DOUBLE 101 when TYPE_VOIDP 102 return SIZEOF_VOIDP 103 else 104 raise(DLError, "unknown type: #{ty}") 105 end 106 when Class 107 if( ty.instance_methods().include?(:to_ptr) ) 108 return ty.size() 109 end 110 end 111 return CPtr[ty].size() 112 end 113 114 def parse_bind_options(opts) 115 h = {} 116 while( opt = opts.shift() ) 117 case opt 118 when :stdcall, :cdecl 119 h[:call_type] = opt 120 when :carried, :temp, :temporal, :bind 121 h[:callback_type] = opt 122 h[:carrier] = opts.shift() 123 else 124 h[opt] = true 125 end 126 end 127 h 128 end 129 private :parse_bind_options 130 131 def extern(signature, *opts) 132 @type_alias ||= nil 133 symname, ctype, argtype = parse_signature(signature, @type_alias) 134 opt = parse_bind_options(opts) 135 f = import_function(symname, ctype, argtype, opt[:call_type]) 136 name = symname.gsub(/@.+/,'') 137 @func_map[name] = f 138 # define_method(name){|*args,&block| f.call(*args,&block)} 139 begin 140 /^(.+?):(\d+)/ =~ caller.first 141 file, line = $1, $2.to_i 142 rescue 143 file, line = __FILE__, __LINE__+3 144 end 145 module_eval(<<-EOS, file, line) 146 def #{name}(*args, &block) 147 @func_map['#{name}'].call(*args,&block) 148 end 149 EOS 150 module_function(name) 151 f 152 end 153 154 def bind(signature, *opts, &blk) 155 @type_alias ||= nil 156 name, ctype, argtype = parse_signature(signature, @type_alias) 157 h = parse_bind_options(opts) 158 case h[:callback_type] 159 when :bind, nil 160 f = bind_function(name, ctype, argtype, h[:call_type], &blk) 161 when :temp, :temporal 162 f = create_temp_function(name, ctype, argtype, h[:call_type]) 163 when :carried 164 f = create_carried_function(name, ctype, argtype, h[:call_type], h[:carrier]) 165 else 166 raise(RuntimeError, "unknown callback type: #{h[:callback_type]}") 167 end 168 @func_map[name] = f 169 #define_method(name){|*args,&block| f.call(*args,&block)} 170 begin 171 /^(.+?):(\d+)/ =~ caller.first 172 file, line = $1, $2.to_i 173 rescue 174 file, line = __FILE__, __LINE__+3 175 end 176 module_eval(<<-EOS, file, line) 177 def #{name}(*args,&block) 178 @func_map['#{name}'].call(*args,&block) 179 end 180 EOS 181 module_function(name) 182 f 183 end 184 185 # Creates a class to wrap the C struct described by +signature+. 186 # 187 # MyStruct = struct ['int i', 'char c'] 188 def struct(signature) 189 @type_alias ||= nil 190 tys, mems = parse_struct_signature(signature, @type_alias) 191 DL::CStructBuilder.create(CStruct, tys, mems) 192 end 193 194 # Creates a class to wrap the C union described by +signature+. 195 # 196 # MyUnion = union ['int i', 'char c'] 197 def union(signature) 198 @type_alias ||= nil 199 tys, mems = parse_struct_signature(signature, @type_alias) 200 DL::CStructBuilder.create(CUnion, tys, mems) 201 end 202 203 def [](name) 204 @func_map[name] 205 end 206 207 def create_value(ty, val=nil) 208 s = struct([ty + " value"]) 209 ptr = s.malloc() 210 if( val ) 211 ptr.value = val 212 end 213 return ptr 214 end 215 alias value create_value 216 217 def import_value(ty, addr) 218 s = struct([ty + " value"]) 219 ptr = s.new(addr) 220 return ptr 221 end 222 223 def handler 224 defined?(@handler) or raise "call dlload before importing symbols and functions" 225 @handler 226 end 227 228 def import_symbol(name) 229 addr = handler.sym(name) 230 if( !addr ) 231 raise(DLError, "cannot find the symbol: #{name}") 232 end 233 CPtr.new(addr) 234 end 235 236 def import_function(name, ctype, argtype, call_type = nil) 237 addr = handler.sym(name) 238 if( !addr ) 239 raise(DLError, "cannot find the function: #{name}()") 240 end 241 Function.new(CFunc.new(addr, ctype, name, call_type || :cdecl), argtype) 242 end 243 244 def bind_function(name, ctype, argtype, call_type = nil, &block) 245 if DL.fiddle? 246 klass = Function.instance_eval { class_fiddle_closure_cfunc } 247 abi = Function.instance_eval { call_type_to_abi(call_type) } 248 closure = Class.new(klass) { 249 define_method(:call, block) 250 }.new(ctype, argtype, abi, name) 251 252 Function.new(closure, argtype, abi) 253 else 254 f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype) 255 f.bind(&block) 256 f 257 end 258 end 259 260 def create_temp_function(name, ctype, argtype, call_type = nil) 261 TempFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype) 262 end 263 264 def create_carried_function(name, ctype, argtype, call_type = nil, n = 0) 265 CarriedFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype, n) 266 end 267 end 268end 269