rubysl-dl 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,215 @@
1
+ /* -*- C -*-
2
+ * $Id: handle.c 11708 2007-02-12 23:01:19Z shyouhei $
3
+ */
4
+
5
+ #include <ruby.h>
6
+ #include "dl.h"
7
+
8
+ VALUE rb_cDLHandle;
9
+
10
+ void
11
+ dlhandle_free(struct dl_handle *dlhandle)
12
+ {
13
+ if (dlhandle->ptr && dlhandle->open && dlhandle->enable_close) {
14
+ dlclose(dlhandle->ptr);
15
+ }
16
+ }
17
+
18
+ VALUE
19
+ rb_dlhandle_close(VALUE self)
20
+ {
21
+ struct dl_handle *dlhandle;
22
+
23
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
24
+ dlhandle->open = 0;
25
+ return INT2NUM(dlclose(dlhandle->ptr));
26
+ }
27
+
28
+ VALUE
29
+ rb_dlhandle_s_allocate(VALUE klass)
30
+ {
31
+ VALUE obj;
32
+ struct dl_handle *dlhandle;
33
+
34
+ obj = Data_Make_Struct(rb_cDLHandle, struct dl_handle, 0,
35
+ dlhandle_free, dlhandle);
36
+ dlhandle->ptr = 0;
37
+ dlhandle->open = 0;
38
+ dlhandle->enable_close = 0;
39
+
40
+ return obj;
41
+ }
42
+
43
+ VALUE
44
+ rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
45
+ {
46
+ void *ptr;
47
+ struct dl_handle *dlhandle;
48
+ VALUE lib, flag;
49
+ char *clib = 0;
50
+ int cflag = 0;
51
+ const char *err;
52
+
53
+ switch (rb_scan_args(argc, argv, "11", &lib, &flag)) {
54
+ case 1:
55
+ clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
56
+ cflag = RTLD_LAZY | RTLD_GLOBAL;
57
+ break;
58
+ case 2:
59
+ clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
60
+ cflag = NUM2INT(flag);
61
+ break;
62
+ default:
63
+ rb_bug("rb_dlhandle_new");
64
+ }
65
+
66
+ ptr = dlopen(clib, cflag);
67
+ #if defined(HAVE_DLERROR)
68
+ if (!ptr && (err = dlerror())) {
69
+ rb_raise(rb_eRuntimeError, "%s", err);
70
+ }
71
+ #else
72
+ if (!ptr) {
73
+ err = dlerror();
74
+ rb_raise(rb_eRuntimeError, "%s", err);
75
+ }
76
+ #endif
77
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
78
+ if (dlhandle->ptr && dlhandle->open && dlhandle->enable_close) {
79
+ dlclose(dlhandle->ptr);
80
+ }
81
+ dlhandle->ptr = ptr;
82
+ dlhandle->open = 1;
83
+ dlhandle->enable_close = 0;
84
+
85
+ if (rb_block_given_p()) {
86
+ rb_ensure(rb_yield, self, rb_dlhandle_close, self);
87
+ }
88
+
89
+ return Qnil;
90
+ }
91
+
92
+ VALUE
93
+ rb_dlhandle_enable_close(VALUE self)
94
+ {
95
+ struct dl_handle *dlhandle;
96
+
97
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
98
+ dlhandle->enable_close = 1;
99
+ return Qnil;
100
+ }
101
+
102
+ VALUE
103
+ rb_dlhandle_disable_close(VALUE self)
104
+ {
105
+ struct dl_handle *dlhandle;
106
+
107
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
108
+ dlhandle->enable_close = 0;
109
+ return Qnil;
110
+ }
111
+
112
+ VALUE
113
+ rb_dlhandle_to_i(VALUE self)
114
+ {
115
+ struct dl_handle *dlhandle;
116
+
117
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
118
+ return DLLONG2NUM(dlhandle);
119
+ }
120
+
121
+ VALUE
122
+ rb_dlhandle_to_ptr(VALUE self)
123
+ {
124
+ struct dl_handle *dlhandle;
125
+
126
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
127
+ return rb_dlptr_new(dlhandle, sizeof(dlhandle), 0);
128
+ }
129
+
130
+ VALUE
131
+ rb_dlhandle_sym(int argc, VALUE argv[], VALUE self)
132
+ {
133
+ VALUE sym, type;
134
+ void (*func)();
135
+ VALUE val;
136
+ struct dl_handle *dlhandle;
137
+ void *handle;
138
+ const char *name, *stype;
139
+ const char *err;
140
+
141
+ rb_secure(2);
142
+ if (rb_scan_args(argc, argv, "11", &sym, &type) == 2) {
143
+ SafeStringValue(type);
144
+ stype = StringValuePtr(type);
145
+ }
146
+ else{
147
+ stype = NULL;
148
+ }
149
+
150
+ if (sym == Qnil) {
151
+ #if defined(RTLD_NEXT)
152
+ name = RTLD_NEXT;
153
+ #else
154
+ name = NULL;
155
+ #endif
156
+ }
157
+ else{
158
+ SafeStringValue(sym);
159
+ name = StringValuePtr(sym);
160
+ }
161
+
162
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
163
+ if (!dlhandle->open) {
164
+ rb_raise(rb_eRuntimeError, "closed handle");
165
+ }
166
+ handle = dlhandle->ptr;
167
+
168
+ func = dlsym(handle, name);
169
+ #if defined(HAVE_DLERROR)
170
+ if (!func && (err = dlerror()))
171
+ #else
172
+ if (!func)
173
+ #endif
174
+ {
175
+ #if defined(__CYGWIN__) || defined(WIN32) || defined(__MINGW32__)
176
+ {
177
+ int len = strlen(name);
178
+ char *name_a = (char*)dlmalloc(len+2);
179
+ strcpy(name_a, name);
180
+ name_a[len] = 'A';
181
+ name_a[len+1] = '\0';
182
+ func = dlsym(handle, name_a);
183
+ dlfree(name_a);
184
+ #if defined(HAVE_DLERROR)
185
+ if (!func && (err = dlerror()))
186
+ #else
187
+ if (!func)
188
+ #endif
189
+ {
190
+ rb_raise(rb_eRuntimeError, "unknown symbol \"%sA\"", name);
191
+ }
192
+ }
193
+ #else
194
+ rb_raise(rb_eRuntimeError, "unknown symbol \"%s\"", name);
195
+ #endif
196
+ }
197
+ val = rb_dlsym_new(func, name, stype);
198
+
199
+ return val;
200
+ }
201
+
202
+ void
203
+ Init_dlhandle()
204
+ {
205
+ rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject);
206
+ rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate);
207
+ rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1);
208
+ rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0);
209
+ rb_define_method(rb_cDLHandle, "to_ptr", rb_dlhandle_to_ptr, 0);
210
+ rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0);
211
+ rb_define_method(rb_cDLHandle, "sym", rb_dlhandle_sym, -1);
212
+ rb_define_method(rb_cDLHandle, "[]", rb_dlhandle_sym, -1);
213
+ rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0);
214
+ rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0);
215
+ }
@@ -0,0 +1,49 @@
1
+ require 'mkmf'
2
+ require 'ftools'
3
+
4
+ SO_LIBS = ["dl.so"]
5
+
6
+ $ruby_version = CONFIG['MAJOR'] + "." + CONFIG['MINOR']
7
+ $prefix = CONFIG['prefix']
8
+ $libdir = File.join($prefix,'lib')
9
+ $rubylibdir = File.join($libdir, 'ruby', $ruby_version)
10
+ $arch = CONFIG['arch']
11
+ $archdir = File.join($rubylibdir, $arch)
12
+
13
+ def find(dir, match = /./)
14
+ Dir.chdir(dir)
15
+ files = []
16
+ Dir.new(".").each{|file|
17
+ if( file != "." && file != ".." )
18
+ case File.ftype(file)
19
+ when "file"
20
+ if( file =~ match )
21
+ files.push(File.join(dir,file))
22
+ end
23
+ when "directory"
24
+ files += find(file, match).collect{|f| File.join(dir,f)}
25
+ end
26
+ end
27
+ }
28
+ Dir.chdir("..")
29
+ return files
30
+ end
31
+
32
+ def install()
33
+ rb_files = find(File.join(".","lib"), /.rb$/)
34
+
35
+ SO_LIBS.each{|f|
36
+ File.makedirs($rubylibdir, "#{$archdir}")
37
+ File.install(f, File.join($archdir,f), 0555, true)
38
+ }
39
+
40
+ rb_files.each{|f|
41
+ origfile = f
42
+ instfile = File.join($rubylibdir, origfile.sub("./lib/",""))
43
+ instdir = File.dirname(instfile)
44
+ File.makedirs(instdir)
45
+ File.install(origfile, instfile, 0644, true)
46
+ }
47
+ end
48
+
49
+ install()
@@ -0,0 +1,225 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'dl'
4
+ require 'dl/types'
5
+
6
+ module DL
7
+ module Importable
8
+ LIB_MAP = {}
9
+
10
+ module Internal
11
+ def init_types()
12
+ @types ||= ::DL::Types.new
13
+ end
14
+
15
+ def init_sym()
16
+ @SYM ||= {}
17
+ end
18
+
19
+ def [](name)
20
+ return @SYM[name.to_s][0]
21
+ end
22
+
23
+ def dlload(*libnames)
24
+ if( !defined?(@LIBS) )
25
+ @LIBS = []
26
+ end
27
+ libnames.each{|libname|
28
+ if( !LIB_MAP[libname] )
29
+ LIB_MAP[libname] = DL.dlopen(libname)
30
+ end
31
+ @LIBS.push(LIB_MAP[libname])
32
+ }
33
+ end
34
+ alias dllink :dlload
35
+
36
+ def parse_cproto(proto)
37
+ proto = proto.gsub(/\s+/, " ").strip
38
+ case proto
39
+ when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
40
+ ret = $1
41
+ args = $2.strip()
42
+ ret = ret.split(/\s+/)
43
+ args = args.split(/\s*,\s*/)
44
+ func = ret.pop()
45
+ if( func =~ /^\*/ )
46
+ func.gsub!(/^\*+/,"")
47
+ ret.push("*")
48
+ end
49
+ ret = ret.join(" ")
50
+ return [func, ret, args]
51
+ else
52
+ raise(RuntimeError,"can't parse the function prototype: #{proto}")
53
+ end
54
+ end
55
+
56
+ # example:
57
+ # extern "int strlen(char*)"
58
+ #
59
+ def extern(proto)
60
+ func,ret,args = parse_cproto(proto)
61
+ return import(func, ret, args)
62
+ end
63
+
64
+ # example:
65
+ # callback "int method_name(int, char*)"
66
+ #
67
+ def callback(proto)
68
+ func,ret,args = parse_cproto(proto)
69
+
70
+ init_types()
71
+ init_sym()
72
+
73
+ rty,renc,rdec = @types.encode_return_type(ret)
74
+ if( !rty )
75
+ raise(TypeError, "unsupported type: #{ret}")
76
+ end
77
+ ty,enc,dec = encode_argument_types(args)
78
+ symty = rty + ty
79
+
80
+ module_eval("module_function :#{func}")
81
+ sym = module_eval([
82
+ "DL::callback(\"#{symty}\"){|*args|",
83
+ " sym,rdec,enc,dec = @SYM['#{func}']",
84
+ " args = enc.call(args) if enc",
85
+ " r,rs = #{func}(*args)",
86
+ " r = renc.call(r) if rdec",
87
+ " rs = dec.call(rs) if (dec && rs)",
88
+ " @retval = r",
89
+ " @args = rs",
90
+ " r",
91
+ "}",
92
+ ].join("\n"))
93
+
94
+ @SYM[func] = [sym,rdec,enc,dec]
95
+
96
+ return sym
97
+ end
98
+
99
+ # example:
100
+ # typealias("uint", "unsigned int")
101
+ #
102
+ def typealias(alias_type, ty1, enc1=nil, dec1=nil, ty2=nil, enc2=nil, dec2=nil)
103
+ init_types()
104
+ @types.typealias(alias_type, ty1, enc1, dec1,
105
+ ty2||ty1, enc2, dec2)
106
+ end
107
+
108
+ # example:
109
+ # symbol "foo_value"
110
+ # symbol "foo_func", "IIP"
111
+ #
112
+ def symbol(name, ty = nil)
113
+ sym = nil
114
+ @LIBS.each{|lib|
115
+ begin
116
+ if( ty )
117
+ sym = lib[name, ty]
118
+ else
119
+ sym = lib[name]
120
+ end
121
+ rescue
122
+ next
123
+ end
124
+ }
125
+ if( !sym )
126
+ raise(RuntimeError, "can't find the symbol `#{name}'")
127
+ end
128
+ return sym
129
+ end
130
+
131
+ # example:
132
+ # import("get_length", "int", ["void*", "int"])
133
+ #
134
+ def import(name, rettype, argtypes = nil)
135
+ init_types()
136
+ init_sym()
137
+
138
+ rty,_,rdec = @types.encode_return_type(rettype)
139
+ if( !rty )
140
+ raise(TypeError, "unsupported type: #{rettype}")
141
+ end
142
+ ty,enc,dec = encode_argument_types(argtypes)
143
+ symty = rty + ty
144
+
145
+ sym = symbol(name, symty)
146
+
147
+ mname = name.dup
148
+ if( ?A <= mname[0] && mname[0] <= ?Z )
149
+ mname[0,1] = mname[0,1].downcase
150
+ end
151
+ @SYM[mname] = [sym,rdec,enc,dec]
152
+
153
+ module_eval [
154
+ "def #{mname}(*args)",
155
+ " sym,rdec,enc,dec = @SYM['#{mname}']",
156
+ " args = enc.call(args) if enc",
157
+ if( $DEBUG )
158
+ " p \"[DL] call #{mname} with \#{args.inspect}\""
159
+ else
160
+ ""
161
+ end,
162
+ " r,rs = sym.call(*args)",
163
+ if( $DEBUG )
164
+ " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\""
165
+ else
166
+ ""
167
+ end,
168
+ " r = rdec.call(r) if rdec",
169
+ " rs = dec.call(rs) if dec",
170
+ " @retval = r",
171
+ " @args = rs",
172
+ " return r",
173
+ "end",
174
+ "module_function :#{mname}",
175
+ ].join("\n")
176
+
177
+ return sym
178
+ end
179
+
180
+ def _args_
181
+ return @args
182
+ end
183
+
184
+ def _retval_
185
+ return @retval
186
+ end
187
+
188
+ def encode_argument_types(tys)
189
+ init_types()
190
+ encty = []
191
+ enc = nil
192
+ dec = nil
193
+ tys.each_with_index{|ty,idx|
194
+ ty,c1,c2 = @types.encode_argument_type(ty)
195
+ if( !ty )
196
+ raise(TypeError, "unsupported type: #{ty}")
197
+ end
198
+ encty.push(ty)
199
+ if( enc )
200
+ if( c1 )
201
+ conv1 = enc
202
+ enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v}
203
+ end
204
+ else
205
+ if( c1 )
206
+ enc = proc{|v| v[idx] = c1.call(v[idx]); v}
207
+ end
208
+ end
209
+ if( dec )
210
+ if( c2 )
211
+ conv2 = dec
212
+ dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v}
213
+ end
214
+ else
215
+ if( c2 )
216
+ dec = proc{|v| v[idx] = c2.call(v[idx]); v}
217
+ end
218
+ end
219
+ }
220
+ return [encty.join, enc, dec]
221
+ end
222
+ end # end of Internal
223
+ include Internal
224
+ end # end of Importable
225
+ end