cgen 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/History.txt +199 -0
- data/README.txt +34 -0
- data/examples/bench.rb +14 -0
- data/examples/complex.rb +63 -0
- data/examples/complex2.rb +48 -0
- data/examples/cshadow-example.rb +55 -0
- data/examples/cshadow-point.rb +58 -0
- data/examples/ctest.rb +34 -0
- data/examples/ctest2.rb +32 -0
- data/examples/ctest3.rb +179 -0
- data/examples/ctest4.rb +18 -0
- data/examples/ctest5.rb +27 -0
- data/examples/example-ruby-talk-30April2004.rb +65 -0
- data/examples/fixed-array.rb +221 -0
- data/examples/inherit-example.rb +26 -0
- data/examples/inherit-example.txt +80 -0
- data/examples/instance-eval.rb +66 -0
- data/examples/ivset.rb +55 -0
- data/examples/marshal-test.rb +19 -0
- data/examples/matrix.rb +91 -0
- data/examples/modular-def.rb +87 -0
- data/examples/objattr.rb +46 -0
- data/examples/opaque-struct-test.rb +36 -0
- data/examples/sample.rb +184 -0
- data/examples/struct.rb +103 -0
- data/examples/test.rb +24 -0
- data/examples/yaml.rb +56 -0
- data/install.rb +1015 -0
- data/lib/cgen/attribute.rb +414 -0
- data/lib/cgen/cgen.rb +2041 -0
- data/lib/cgen/cshadow.rb +1037 -0
- data/lib/cgen/inherit.rb +46 -0
- data/rakefile +42 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test-attribute.rb +430 -0
- data/test/test-cgen.rb +127 -0
- data/test/test-cshadow.rb +289 -0
- data/test/test.rb +17 -0
- metadata +123 -0
@@ -0,0 +1,414 @@
|
|
1
|
+
module CShadow
|
2
|
+
|
3
|
+
AttributeTypes = []
|
4
|
+
|
5
|
+
# This is the base class for all plug-in attribute classes used with the
|
6
|
+
# CShadow module. Each subclass provides information which CShadow uses to
|
7
|
+
# manage some of the housekeeping for the attribute:
|
8
|
+
#
|
9
|
+
# * declaration of the attribute in the shadow struct,
|
10
|
+
#
|
11
|
+
# * accessor code (which CShadow wraps in methods),
|
12
|
+
#
|
13
|
+
# * type conversion for the write accessor,
|
14
|
+
#
|
15
|
+
# * type checking for the write accessor,
|
16
|
+
#
|
17
|
+
# * the 'mark' function, if the attribute refers to Ruby objects,
|
18
|
+
#
|
19
|
+
# * the 'free' function, if the attribute refers to C data,
|
20
|
+
#
|
21
|
+
# * initialization (usually, this is left to the class's #initialize method),
|
22
|
+
#
|
23
|
+
# * serialization methods for the attribute.(*)
|
24
|
+
#
|
25
|
+
# (*) For Ruby versions before 1.7, requires a patch using the marshal.patch
|
26
|
+
# file (the patch is explained in marshal.txt).
|
27
|
+
#
|
28
|
+
# The subclass hierarchy has two branches: ObjectAttribute and
|
29
|
+
# CNativeAttribute. The former is a reference to a Ruby object (in other
|
30
|
+
# words, a struct member of type +VALUE+. The latter has subclasses for
|
31
|
+
# various C data types, such as +double+ and <tt>char *</tt>.
|
32
|
+
#
|
33
|
+
# ==Adding new attribute classes
|
34
|
+
#
|
35
|
+
# Each attribute class must define a class method called 'match' which returns
|
36
|
+
# true if the right hand side of the ':name => ...' expression is recognized
|
37
|
+
# as defining an attribute of the class. The class should have an initialize
|
38
|
+
# method to supply custom code for readers, writers, type checking, memory
|
39
|
+
# management, and serialization. (If serialization methods are omitted, the
|
40
|
+
# attribute will be ignored during +dump+/+load+.) The easiest way is to
|
41
|
+
# follow the examples. For many purposes, most of the work can be done by
|
42
|
+
# subclassing existing classes.
|
43
|
+
#
|
44
|
+
# The +dump+ and +load+ methods require a bit of explanation. Each attribute
|
45
|
+
# provides code to dump and load itself in a very generic way. The dump code
|
46
|
+
# must operate on a ruby array called result. It must push _one_ piece of ruby
|
47
|
+
# data (which may itself be an array, hash, etc.) onto this array. Similarly,
|
48
|
+
# the load code operates on a ruby array called from_array. It must shift
|
49
|
+
# _one_ piece of ruby data from this array. (Probably it would have been more
|
50
|
+
# efficient to use LIFO rather than FIFO. Oh, well.)
|
51
|
+
#
|
52
|
+
# ==To do:
|
53
|
+
#
|
54
|
+
# * Type checking and conversion should to to_str, to_ary, etc. first if
|
55
|
+
# appropriate.
|
56
|
+
#
|
57
|
+
# * Consider changing '[Foo]' to 'shadow(Foo)' and using [Foo, Bar, Baz],
|
58
|
+
# [Foo]*20, and [Foo .. Foo] to signify structs, fixed-length arrays, and
|
59
|
+
# var-length arrays of (VALUE *) ?
|
60
|
+
#
|
61
|
+
# * More attribute classes: floats, unsigned, fixed length arrays, bitfields,
|
62
|
+
# etc.
|
63
|
+
#
|
64
|
+
# * substructs?
|
65
|
+
#
|
66
|
+
# * Make classes more generic, so that there aren't so many classes. (Factory
|
67
|
+
# classes, like ArrayAttribute(PointerAttribute(:char)) ?)
|
68
|
+
#
|
69
|
+
# * Support for #freeze, #taint, etc.
|
70
|
+
#
|
71
|
+
# ==Limitations:
|
72
|
+
#
|
73
|
+
# * IntAttribute: No attempt to handle Bignums.
|
74
|
+
#
|
75
|
+
class Attribute
|
76
|
+
|
77
|
+
def Attribute.inherited subclass
|
78
|
+
AttributeTypes << subclass
|
79
|
+
end
|
80
|
+
|
81
|
+
def Attribute.match decl
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
attr_reader :var, :cvar, :cdecl,
|
86
|
+
:init, :reader, :check, :writer,
|
87
|
+
:mark, :free, :dump, :load,
|
88
|
+
:persists, :owner_class
|
89
|
+
|
90
|
+
def initialize owner_class, var, match, persists = true
|
91
|
+
@owner_class = owner_class
|
92
|
+
@var, @match = var, match
|
93
|
+
@persists = persists
|
94
|
+
end
|
95
|
+
|
96
|
+
def inspect
|
97
|
+
%{<#{self.class} #{@cvar} => #{@cdecl.inspect}>}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# There are two kinds of object attributes. Both refer to Ruby objects and can
|
102
|
+
# be typed or untyped. This one is less optimized but cat refer to arbitrary
|
103
|
+
# ruby objects.
|
104
|
+
#
|
105
|
+
# The syntax for adding an object attribute to a class is simple. The
|
106
|
+
# following code adds three object attributes, one untyped and two typed:
|
107
|
+
#
|
108
|
+
# class A
|
109
|
+
# include CShadow
|
110
|
+
# shadow_attr_accessor :obj => Object, :sym => Symbol, :ary => Array
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# (See CShadow for variations on #shadow_attr_accessor.)
|
114
|
+
#
|
115
|
+
# Assignment to +obj+ performs no type checking. Assignment to +sym+ raises a
|
116
|
+
# TypeError unless the object assigned is a +Symbol+ or +nil+. Similarly +ary+
|
117
|
+
# must always be an +Array+ or +nil+. Type checking always allows +nil+ in
|
118
|
+
# addition to the specified type. In each case, the attribute is initialized
|
119
|
+
# to +nil+.
|
120
|
+
#
|
121
|
+
# The referenced Ruby object is marked to protect it from the garbage
|
122
|
+
# collector.
|
123
|
+
#
|
124
|
+
class ObjectAttribute < Attribute
|
125
|
+
|
126
|
+
def ObjectAttribute.match decl
|
127
|
+
decl if decl.is_a? Class
|
128
|
+
end
|
129
|
+
|
130
|
+
def target_class; @class; end
|
131
|
+
|
132
|
+
def initialize(*args)
|
133
|
+
super
|
134
|
+
@class = @match
|
135
|
+
|
136
|
+
@cvar = @var
|
137
|
+
@cdecl = "VALUE #{@cvar}; // #{@class}"
|
138
|
+
|
139
|
+
@init = "shadow->#{@cvar} = Qnil" # otherwise, it's Qfalse == 0
|
140
|
+
@reader = "result = shadow->#{@cvar}"
|
141
|
+
@writer = "shadow->#{@cvar} = arg"
|
142
|
+
@check = @class unless @class == Object
|
143
|
+
@mark = "rb_gc_mark(shadow->#{@cvar})"
|
144
|
+
|
145
|
+
@dump = "rb_ary_push(result, shadow->#{@cvar})"
|
146
|
+
@load = "shadow->#{@cvar} = rb_ary_shift(from_array)"
|
147
|
+
end
|
148
|
+
|
149
|
+
def inspect
|
150
|
+
%{<#{self.class} #{@cvar} => #{@class.inspect}>}
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
# There are two kinds of object attributes. Both refer to Ruby objects and can
|
156
|
+
# be typed or untyped. This one is a slightly optimized variation that is
|
157
|
+
# restricted to references to other shadow objects.
|
158
|
+
#
|
159
|
+
# ShadowObjectAttribute is a restricted variant of ObjectAttribute in which
|
160
|
+
# the object referred to must belong to a class that includes CShadow. The
|
161
|
+
# actual pointer is to the shadow struct itself, rather than a +VALUE+. This
|
162
|
+
# difference is transparent to Ruby code. The syntax for this variant differs
|
163
|
+
# only in the use of brackets around the type. For example, using the class
|
164
|
+
# +A+ defined above:
|
165
|
+
#
|
166
|
+
# class B
|
167
|
+
# include CShadow
|
168
|
+
# shadow_attr_accessor :a => [A]
|
169
|
+
#
|
170
|
+
# def initialize
|
171
|
+
# self.a = A.new
|
172
|
+
# a.sym = :something
|
173
|
+
# end
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# Note that a shadow struct always has a +self+ pointer, so a
|
177
|
+
# ShadowObjectAttribute contains essentially the same information as an
|
178
|
+
# ObjectAttribute. It is included for situation in which the efficiency of a
|
179
|
+
# direct reference to the shadow struct is desirable. Note that only
|
180
|
+
# ObjectAttributes can refer to general Ruby objects which may or may not
|
181
|
+
# include the CShadow module.
|
182
|
+
#
|
183
|
+
# The accessors work just as with ObjectAttribute, with type checking
|
184
|
+
# performed by the writer. From Ruby, these two kinds of attributes are
|
185
|
+
# indistinguishable in all respects except their declaration syntax.
|
186
|
+
#
|
187
|
+
# The referenced Ruby object is marked to protect it from the garbage
|
188
|
+
# collector.
|
189
|
+
#
|
190
|
+
class ShadowObjectAttribute < Attribute
|
191
|
+
|
192
|
+
def ShadowObjectAttribute.match decl
|
193
|
+
decl[0] if decl.is_a? Array and decl.size == 1 and decl[0].is_a? Class
|
194
|
+
end
|
195
|
+
|
196
|
+
def target_class; @class; end
|
197
|
+
|
198
|
+
def initialize(*args)
|
199
|
+
super
|
200
|
+
@class = @match
|
201
|
+
|
202
|
+
ssn = @class.shadow_struct.name
|
203
|
+
|
204
|
+
@cvar = @var
|
205
|
+
if @class < CShadow
|
206
|
+
@cdecl = "struct #{ssn} *#{@cvar}"
|
207
|
+
else
|
208
|
+
raise ScriptError, "Class #{@class} doesn't include CShadow."
|
209
|
+
end
|
210
|
+
|
211
|
+
@reader = "result = shadow->#{@cvar} ? shadow->#{@cvar}->self : Qnil"
|
212
|
+
@writer = %{
|
213
|
+
if (arg != Qnil) {
|
214
|
+
Data_Get_Struct(arg, #{ssn}, shadow->#{@cvar});
|
215
|
+
} else
|
216
|
+
shadow->#{@cvar} = 0;
|
217
|
+
}
|
218
|
+
@check = @class unless @class == Object
|
219
|
+
@mark = %{\
|
220
|
+
if (shadow->#{@cvar})
|
221
|
+
rb_gc_mark(shadow->#{@cvar}->self);\
|
222
|
+
}
|
223
|
+
|
224
|
+
@dump =
|
225
|
+
"rb_ary_push(result, shadow->#{@cvar} ? shadow->#{@cvar}->self : 0)"
|
226
|
+
@load = %{
|
227
|
+
tmp = rb_ary_shift(from_array);
|
228
|
+
if (tmp) {
|
229
|
+
Data_Get_Struct(tmp, #{ssn}, shadow->#{@cvar});
|
230
|
+
} else
|
231
|
+
shadow->#{@cvar} = 0;
|
232
|
+
}
|
233
|
+
end
|
234
|
+
|
235
|
+
def inspect
|
236
|
+
%{<#{self.class} #{@cvar} => [#{@class.inspect}]>}
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# CNativeAttribute and its subclasses handle all but the two special cases
|
241
|
+
# described above. The general form for declarations of such attributes is:
|
242
|
+
#
|
243
|
+
# shadow_attr_accessor ruby_var => c_declaration
|
244
|
+
#
|
245
|
+
# where +ruby_var+ is the name (symbol or string) which will access the data
|
246
|
+
# from Ruby, and +c_declaration+ is the string used to declare the data. For
|
247
|
+
# example:
|
248
|
+
#
|
249
|
+
# shadow_attr_accessor :x => "double x", :y => "int yyy"
|
250
|
+
#
|
251
|
+
# Note that the symbol and C identifier need not be the same.
|
252
|
+
#
|
253
|
+
# Native attributes fall into two categories: those that embed data within the
|
254
|
+
# struct, and those that point to a separately allocated block. Embedded
|
255
|
+
# attributes are limited in that they are of fixed size. Pointer attributes do
|
256
|
+
# not have this limitation. But programmers should be wary of treating them as
|
257
|
+
# separate objects: the lifespan of the referenced data block is the same as
|
258
|
+
# the lifespan of the Ruby object. If the Ruby object and its shadow are
|
259
|
+
# garbage collected while the data is in use, the data will be freed and no
|
260
|
+
# longer valid.
|
261
|
+
#
|
262
|
+
# When using a separately allocated data block, it is a good practice is to
|
263
|
+
# use "copy" semantics, so that there can be no other references to the data.
|
264
|
+
# See CharPointerAttribute, for example. Reading or writing to such an
|
265
|
+
# attribute has copy semantics, in the following sense. On assignment, the
|
266
|
+
# Ruby string argument is copied into an allocated block; later references to
|
267
|
+
# this attribute generate a new Ruby string which is a copy of that array of
|
268
|
+
# char.
|
269
|
+
#
|
270
|
+
# Some CNativeAttribute classes are included for int, long, double, double *,
|
271
|
+
# char *, etc.
|
272
|
+
#
|
273
|
+
# Uninitialized numeric members are 0. Accessors for uninitialized strings
|
274
|
+
# return +nil+.
|
275
|
+
#
|
276
|
+
class CNativeAttribute < Attribute
|
277
|
+
|
278
|
+
attr_reader :ctype
|
279
|
+
|
280
|
+
@pattern = nil
|
281
|
+
|
282
|
+
def CNativeAttribute.match decl
|
283
|
+
if decl.is_a? String and @pattern and @pattern =~ decl
|
284
|
+
Regexp.last_match
|
285
|
+
else
|
286
|
+
false
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def initialize(*args)
|
291
|
+
super
|
292
|
+
@cdecl = @match[0]
|
293
|
+
@ctype = @match[1]
|
294
|
+
@cvar = @match[2]
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
class IntAttribute < CNativeAttribute
|
300
|
+
@pattern = /\A(int)\s+(\w+)\z/
|
301
|
+
def initialize(*args)
|
302
|
+
super
|
303
|
+
@reader = "result = INT2NUM(shadow->#{@cvar})"
|
304
|
+
@writer = "shadow->#{@cvar} = NUM2INT(arg)" # type check and conversion
|
305
|
+
@dump = "rb_ary_push(result, INT2NUM(shadow->#{@cvar}))"
|
306
|
+
@load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2INT(tmp)"
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
# Does not check for overflow.
|
311
|
+
class ShortAttribute < IntAttribute
|
312
|
+
@pattern = /\A(short)\s+(\w+)\z/
|
313
|
+
def initialize(*args)
|
314
|
+
super
|
315
|
+
@reader = "result = INT2NUM(shadow->#{@cvar})"
|
316
|
+
@writer = "shadow->#{@cvar} = NUM2INT(arg)" # type check and conversion
|
317
|
+
@dump = "rb_ary_push(result, INT2NUM(shadow->#{@cvar}))"
|
318
|
+
@load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2INT(tmp)"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
class LongAttribute < CNativeAttribute
|
323
|
+
@pattern = /\A(long)\s+(\w+)\z/
|
324
|
+
def initialize(*args)
|
325
|
+
super
|
326
|
+
@reader = "result = INT2NUM(shadow->#{@cvar})"
|
327
|
+
@writer = "shadow->#{@cvar} = NUM2LONG(arg)" # type check and conversion
|
328
|
+
@dump = "rb_ary_push(result, INT2NUM(shadow->#{@cvar}))"
|
329
|
+
@load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2LONG(tmp)"
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
class DoubleAttribute < CNativeAttribute
|
334
|
+
@pattern = /\A(double)\s+(\w+)\z/
|
335
|
+
def initialize(*args)
|
336
|
+
super
|
337
|
+
@reader = "result = rb_float_new(shadow->#{@cvar})"
|
338
|
+
@writer = "shadow->#{@cvar} = NUM2DBL(arg)" # type check and conversion
|
339
|
+
@dump = "rb_ary_push(result, rb_float_new(shadow->#{@cvar}))"
|
340
|
+
@load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = NUM2DBL(tmp)"
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
class PointerAttribute < CNativeAttribute
|
345
|
+
@pattern = nil
|
346
|
+
def initialize(*args)
|
347
|
+
super
|
348
|
+
@free = "free(shadow->#{@cvar})"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# Stores a null-terminated string
|
353
|
+
class CharPointerAttribute < PointerAttribute
|
354
|
+
@pattern = /\A(char)\s*\*\s*(\w+)\z/
|
355
|
+
def initialize(*args)
|
356
|
+
super
|
357
|
+
@reader =
|
358
|
+
"result = shadow->#{@cvar} ? rb_str_new2(shadow->#{@cvar}) : Qnil"
|
359
|
+
@writer = %{
|
360
|
+
{
|
361
|
+
int len;
|
362
|
+
char *str;
|
363
|
+
|
364
|
+
free(shadow->#{@cvar});
|
365
|
+
|
366
|
+
if (arg == Qnil)
|
367
|
+
shadow->#{@cvar} = 0;
|
368
|
+
else {
|
369
|
+
StringValueCStr(arg);
|
370
|
+
len = RSTRING(arg)->len;
|
371
|
+
str = RSTRING(arg)->ptr;
|
372
|
+
shadow->#{@cvar} = ALLOC_N(char, len + 1);
|
373
|
+
|
374
|
+
if (str)
|
375
|
+
memcpy(shadow->#{@cvar}, str, len);
|
376
|
+
|
377
|
+
shadow->#{@cvar}[len] = '\\0';
|
378
|
+
}
|
379
|
+
}
|
380
|
+
}
|
381
|
+
@dump = %{
|
382
|
+
rb_ary_push(result,
|
383
|
+
shadow->#{@cvar} ? rb_str_new2(shadow->#{@cvar}) : 0);
|
384
|
+
}
|
385
|
+
@load = %{
|
386
|
+
{
|
387
|
+
VALUE arg = rb_ary_shift(from_array);
|
388
|
+
int len;
|
389
|
+
char *str;
|
390
|
+
|
391
|
+
if (arg == Qnil)
|
392
|
+
shadow->#{@cvar} = 0;
|
393
|
+
else {
|
394
|
+
len = RSTRING(arg)->len;
|
395
|
+
str = RSTRING(arg)->ptr;
|
396
|
+
shadow->#{@cvar} = ALLOC_N(char, len + 1);
|
397
|
+
|
398
|
+
if (str)
|
399
|
+
memcpy(shadow->#{@cvar}, str, len);
|
400
|
+
|
401
|
+
shadow->#{@cvar}[len] = '\\0';
|
402
|
+
}
|
403
|
+
}
|
404
|
+
}
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
# can be used for variable length arrays--see examples/matrix.rb.
|
409
|
+
class DoublePointerAttribute < PointerAttribute
|
410
|
+
@pattern = /\A(double)\s*\*\s*(\w+)\z/
|
411
|
+
# can't do anything else in general
|
412
|
+
end
|
413
|
+
|
414
|
+
end
|
data/lib/cgen/cgen.rb
ADDED
@@ -0,0 +1,2041 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'cgen/inherit'
|
3
|
+
|
4
|
+
# ==Overview
|
5
|
+
#
|
6
|
+
# The CGenerator module is a framework for dynamically generating C
|
7
|
+
# extensions. It is a bit like Perl's +inline+ but intended for a different
|
8
|
+
# purpose: managing incremental, structured additions to C source files, and
|
9
|
+
# compiling the code and loading the library just in time for execution. Whereas
|
10
|
+
# +inline+ helps you write a C extension, CGenerator helps you write a Ruby
|
11
|
+
# program that generates C extensions. To put it another way, this is a Ruby
|
12
|
+
# interface to the Ruby C API.
|
13
|
+
#
|
14
|
+
# The original use of CGenerator was as the back end of a compiler for
|
15
|
+
# mathematical expressions in C-like syntax involving limited Ruby
|
16
|
+
# subexpressions. In that case, CGenerator allowed the compiler to think
|
17
|
+
# about the syntax and semantics of the input expressions without having to
|
18
|
+
# worry about the high-level structure of the generated .c and .h files.
|
19
|
+
#
|
20
|
+
# One potential use is quick-turnaround development and testing of C code,
|
21
|
+
# possibly using Ruby as a driver environment; the library under construction
|
22
|
+
# needn't be Ruby-specific. If SWIG didn't support Ruby, this framework could be
|
23
|
+
# the starting point for a program that generates wrapper code for existing
|
24
|
+
# libraries. Finally, a Ruby package that includes C extensions could benefit
|
25
|
+
# from being able to use Ruby code to dynamically specify the contents and
|
26
|
+
# control the build process during installation.
|
27
|
+
#
|
28
|
+
# The CGenerator framework consists of two base classes, Accumulator and
|
29
|
+
# Template. Think of accumulators as blanks in a form and templates as the form
|
30
|
+
# around the blanks, except that accumulators and templates can nest within each
|
31
|
+
# other. The base classes have subclasses which hierarchically decompose the
|
32
|
+
# information managed by the framework. This hierarchy is achieved by
|
33
|
+
# inheritance along the +parent+ attribute, which is secondary to subclass
|
34
|
+
# inheritance.
|
35
|
+
#
|
36
|
+
# ==Templates
|
37
|
+
#
|
38
|
+
# The main template in the CGenerator module is Library. It has accumulators for
|
39
|
+
# such constructs as including header files, declaring variables, declaring Ruby
|
40
|
+
# symbols, declaring classes, defining functions, and defining structs. Some
|
41
|
+
# accumulators, such as those for adding function and struct definitions, return
|
42
|
+
# a new template each time they are called. Those templates, in turn, have their
|
43
|
+
# own accumulators for structure members, function arguments, declarations,
|
44
|
+
# initialization, scope, etc.
|
45
|
+
#
|
46
|
+
# ===Library templates
|
47
|
+
#
|
48
|
+
# A Library corresponds to one main C source file and one shared C library (.so
|
49
|
+
# or .dll). It manages the +Init_library+ code (including registration of
|
50
|
+
# methods), as well as user-specified declaration and initialization in the
|
51
|
+
# scope of the .c file and its corresponding .h file. All files generated in the
|
52
|
+
# process of building the library are kept in a directory with the same name as
|
53
|
+
# the library. Additional C files in this directory will be compiled and linked
|
54
|
+
# to the library.
|
55
|
+
#
|
56
|
+
# Each library is the root of a template containment hierarchy, and it alone has
|
57
|
+
# a #commit method. After client code has sent all desired fragments to the
|
58
|
+
# accumulators, calling the commit method uses the structure imposed by the
|
59
|
+
# sub-templates of the library to joins the fragments into two strings, one for
|
60
|
+
# the .h file and one for the .c file. Then each string is written to the
|
61
|
+
# corresponding file (only if the string is different from the current file
|
62
|
+
# contents), and the library is compiled (if necessary) and loaded.
|
63
|
+
#
|
64
|
+
# ===Function templates
|
65
|
+
#
|
66
|
+
# Function templates are used to define the functions in a Library. The base
|
67
|
+
# class, CGenerator::Function, generates a function (by default, static) in the
|
68
|
+
# library without registering it with Ruby in any way.
|
69
|
+
#
|
70
|
+
# The CGenerator::RubyFunction templates define the function as above and also
|
71
|
+
# register the function as an instance method, module function, or singleton
|
72
|
+
# method of a specified class or module, or as a global function (a private
|
73
|
+
# method of +Kernel+).
|
74
|
+
#
|
75
|
+
# Client code does not instantiate these templates directly, but instead uses
|
76
|
+
# the library's #define accumulator methods, which return the new template.
|
77
|
+
#
|
78
|
+
# The function template for the library's initialization function can be
|
79
|
+
# accessed using the library's #init_library_function method, although direct
|
80
|
+
# access to this template is typically not needed. (Use the library's #setup
|
81
|
+
# method to write code to the #init_library_function.)
|
82
|
+
#
|
83
|
+
# ===Struct templates
|
84
|
+
#
|
85
|
+
# A struct template generates a typedef for a C struct. It can be external, in
|
86
|
+
# which case it is written to the .h file. It has a #declare accumulator for
|
87
|
+
# adding data members.
|
88
|
+
#
|
89
|
+
# ==Accumulators
|
90
|
+
#
|
91
|
+
# Accumulators are a way of defining a hierarchical structure and populating it
|
92
|
+
# with data in such a way that the data can be serialized to a string at any
|
93
|
+
# point during the process without side effects. Templates are Accumulators
|
94
|
+
# which contain other accumulators and have convenience methods for accessing
|
95
|
+
# them from client code.
|
96
|
+
#
|
97
|
+
# Accumulators can be fairly unstructured--they just accumulate in sequence
|
98
|
+
# whatever is sent to them, possibly with some filtering, which may include
|
99
|
+
# other accumulators. Templates are usually more more structured. In general,
|
100
|
+
# only Templates can be parents; other accumulators set the #parent of each
|
101
|
+
# accumulated item to be the accumulator's #parent, simplifying the #parent
|
102
|
+
# hierarchy.
|
103
|
+
#
|
104
|
+
# Accumulators are responsible for the format of each accumulated item, for
|
105
|
+
# joining the items to form a string when requested to do so, and for doing any
|
106
|
+
# necessary preprocessing on the items (e.g., discarding duplicates).
|
107
|
+
#
|
108
|
+
# From the point of view of client code, accumulators are methods for "filling
|
109
|
+
# in the blanks" in templates. Client code doesn't access the accumulator object
|
110
|
+
# directly, only through a method on the template. For example:
|
111
|
+
#
|
112
|
+
# lib.declare :global_int_array =>
|
113
|
+
# 'int global_int_array[100]',
|
114
|
+
# :name =>
|
115
|
+
# 'char *name'
|
116
|
+
#
|
117
|
+
# is used to access the "declare" accumulator of the library (which is actually
|
118
|
+
# delegated to a file template).
|
119
|
+
#
|
120
|
+
# Providing a key for each declaration (in the example, the keys are symbols,
|
121
|
+
# but they can be any hash keys) helps CGenerator reject repeated declarations.
|
122
|
+
# (Redundancy checking by simple string comparison is inadequate, because it
|
123
|
+
# would allow two declarations of different types, but the same name, or two
|
124
|
+
# declarations with insignificant whitespace differences.)
|
125
|
+
#
|
126
|
+
# The basic Accumulator class adds fragments to an array in sequence. When
|
127
|
+
# converted to a string with #to_s, it joins the fragments with newline
|
128
|
+
# separators. These behaviors change as needed in the subclasses. <b>Note that
|
129
|
+
# the accumulated items need not all be strings, they need only respond to
|
130
|
+
# +to_s+.</b>
|
131
|
+
#
|
132
|
+
# Return values of accumulators are not very consistent: in general, an
|
133
|
+
# accumulator returns whatever is needed for the caller to continue working with
|
134
|
+
# the thing that was just accumulated. It might be a template which supports
|
135
|
+
# some other accumulators, or it might be a string which can be inserted in C
|
136
|
+
# code.
|
137
|
+
#
|
138
|
+
# Some accumulators take existing Ruby objects as an argument. These
|
139
|
+
# accumulators typically return, as a Ruby symbol, the C identifier that has
|
140
|
+
# been defined or declared to refer to that Ruby object. This can be
|
141
|
+
# interpolated into C code to refer to the Ruby object from C.
|
142
|
+
#
|
143
|
+
# <b>Note about argument order:</b> Since hashes are unordered, passing a hash
|
144
|
+
# of key-value pairs to #declare or similar methods will not preserve the
|
145
|
+
# textual ordering. Internally, cgen sorts this hash into an array of pairs so
|
146
|
+
# that at least the result is deterministic, reducing recompilation. One can
|
147
|
+
# force an argument order by using an array of pairs.
|
148
|
+
#
|
149
|
+
# lib.declare [[:global_int_array,
|
150
|
+
# 'int global_int_array[100]'],
|
151
|
+
# [:name =>
|
152
|
+
# 'char *name']
|
153
|
+
#
|
154
|
+
# Alternately, simply break the declaration into multiple declares.
|
155
|
+
#
|
156
|
+
# ==C code output
|
157
|
+
#
|
158
|
+
# ===Format
|
159
|
+
#
|
160
|
+
# Some effort is made to generate readable code. Relative tabbing within code
|
161
|
+
# fragments is preserved. One goal of CGenerator is producing Ruby extensions
|
162
|
+
# that can be saved and distributed with little or no modification (as opposed
|
163
|
+
# to just created and loaded on the fly).
|
164
|
+
#
|
165
|
+
# ===Use of C identifiers
|
166
|
+
#
|
167
|
+
# CGenerator attempts to generate C identifiers in non-conflicting ways...
|
168
|
+
# (prove some nice property)
|
169
|
+
#
|
170
|
+
# ==Usage
|
171
|
+
#
|
172
|
+
# Create a library with:
|
173
|
+
#
|
174
|
+
# lib = CGenerator::Library.new "my_lib_name"
|
175
|
+
#
|
176
|
+
# The name must be an identifier: +/[A-Za-z0-9_]*/+.
|
177
|
+
#
|
178
|
+
# It is useful to keep a reference to +lib+ around to send define and declare
|
179
|
+
# messages to.
|
180
|
+
#
|
181
|
+
# ===Templates
|
182
|
+
#
|
183
|
+
# All templates respond to #library and #file methods, which return the library
|
184
|
+
# or file object which contains the template. (The library itself does not
|
185
|
+
# respond to #file.) They also respond to #name and #parent.
|
186
|
+
#
|
187
|
+
# ===Library
|
188
|
+
#
|
189
|
+
# ---Library#use_work_dir dir_name
|
190
|
+
#
|
191
|
+
# Changes into +dir_name+, creating it first if necessary. Does nothing if
|
192
|
+
# alread in a diredctory of that name. Often used with +"tmp"+.
|
193
|
+
#
|
194
|
+
# ---Library#commit
|
195
|
+
#
|
196
|
+
# Writes the files to disk, and makes and loads the library.
|
197
|
+
#
|
198
|
+
# Note that #commit must be called after all C code definitions for the library,
|
199
|
+
# but before instantiation of any objects that use those definitions. If a
|
200
|
+
# definition occurs after commit, or if instantiation occurs before commit, then
|
201
|
+
# a CGenerator::Library::CommitError is raised, with an appropriate message.
|
202
|
+
# Sometimes, this forces you to use many small libraries, each committed just in
|
203
|
+
# time for use. See examples/fixed-array.rb.
|
204
|
+
#
|
205
|
+
# ---Library#committed?
|
206
|
+
#
|
207
|
+
# True if the library has been committed.
|
208
|
+
#
|
209
|
+
# ---Library#before_commit(&block)
|
210
|
+
# ---Library#after_commit(&block)
|
211
|
+
#
|
212
|
+
# Schedules block to run before or after Library#commit. The before blocks are
|
213
|
+
# run in the same order in which they were scheduled; the after blocks run in
|
214
|
+
# the reverse order (analogously with +BEGIN+/+END+). Each block is evaluated in
|
215
|
+
# the context in which it was created (instance_eval is *not* used), and it is
|
216
|
+
# passed the library as an argument.
|
217
|
+
#
|
218
|
+
# ---Library#empty?
|
219
|
+
#
|
220
|
+
# True if no content has been added to the library.
|
221
|
+
#
|
222
|
+
# ---Library#add_file name
|
223
|
+
#
|
224
|
+
# Creates templates for two files, a source (.c) file and an include (.h) file
|
225
|
+
# that will be generated in the same dir as the library. The base file name is
|
226
|
+
# taken from the argument. Returns an array containing the include file template
|
227
|
+
# and the source file template, in that order.
|
228
|
+
#
|
229
|
+
# Functions can be added to the source file by calling #define_method and
|
230
|
+
# similar methods on the source file template. Their +rb_init+ calls are done in
|
231
|
+
# #init_library_function in the main library source file. The new source file
|
232
|
+
# automatically #includes the library's main header file, as well as its own
|
233
|
+
# header file, and the library's main source file also #includes the new header
|
234
|
+
# file. Declarations can be added to the header file by calling #declare on it,
|
235
|
+
# but in many cases this is taken care of automatically.
|
236
|
+
#
|
237
|
+
# ---Library#extconf
|
238
|
+
#
|
239
|
+
# Override #extconf if you want to do more than just #create_makefile. Note that
|
240
|
+
# #create_makefile recognizes all .c files in the library directory, and
|
241
|
+
# generates a makefile that compiles them and links them into the dynamic
|
242
|
+
# library.
|
243
|
+
#
|
244
|
+
# ---Library#write
|
245
|
+
# ---Library#makedepend
|
246
|
+
# ---Library#mkmf
|
247
|
+
# ---Library#make arg = nil
|
248
|
+
#
|
249
|
+
# Internal methods called, in sequence, by #commit:
|
250
|
+
#
|
251
|
+
# * #write dumps each file template to disk, if needed
|
252
|
+
# * #makedepend executes +makedepend+
|
253
|
+
# * #mkmf calls Library#extconf
|
254
|
+
# * #make executes the system's +make+ program.
|
255
|
+
#
|
256
|
+
# These methods can be overridden, but are more typically called directly. The
|
257
|
+
# argument to #make is interpolated into the system call as a command line
|
258
|
+
# argument to the +make+ program. If the argument is 'clean' or 'distclean' then
|
259
|
+
# the make log is deleted; if the argument is 'distclean' then all .c and .h
|
260
|
+
# files generated by #write are deleted (additional user-supplied .c and .h
|
261
|
+
# files in the library dir are not affected).
|
262
|
+
#
|
263
|
+
# ---Library#update_file f, template
|
264
|
+
#
|
265
|
+
# Called by write on each .c and .h file to actually write +template+ to the
|
266
|
+
# open file +f+. The default behavior is to compare the existing data with the
|
267
|
+
# generated data, and leave the file untouched if nothing changed. Subclasses
|
268
|
+
# may have more efficient ways of doing this. (For instance, check a version
|
269
|
+
# indicator in the file on disk, perhaps stored using the file's preamble
|
270
|
+
# accumulator. It is even possible to defer some entries in the template until
|
271
|
+
# after this check has been made: code that only needs to be regenerated if some
|
272
|
+
# specification has changed)
|
273
|
+
#
|
274
|
+
# ---Library#purge_source_dir
|
275
|
+
# ---Library#purge_source_dir= flag
|
276
|
+
#
|
277
|
+
# Access the #purge_source_dir attribute of a library, which controls what
|
278
|
+
# happens to .c, .h, and .o files in the source dir of the library that are not
|
279
|
+
# among those generated as part of the library. If this is set to +:delete+,
|
280
|
+
# then those files are deleted. Other true values cause the .c, .h, and .o files
|
281
|
+
# to be renamed with the .hide extension. (Note that this makes it difficult to
|
282
|
+
# keep manually written C files in the same dir.) False +flag+ values (the
|
283
|
+
# default) cause CGen to leave the files untouched.
|
284
|
+
#
|
285
|
+
# Note that, regardless of this setting, #mkmf will construct a Makefile which
|
286
|
+
# lists all .c files that are in the source dir. If you do not delete obsolete
|
287
|
+
# files, they will be compiled into your library!
|
288
|
+
#
|
289
|
+
# ---Library#init_library_function
|
290
|
+
#
|
291
|
+
# Returns a Function template object; see below. This function is called when
|
292
|
+
# the library is loaded. Method definitions put stuff here to register methods
|
293
|
+
# with Ruby. Usually, there is no need to bother this guy directly. Use
|
294
|
+
# Library#setup instead.
|
295
|
+
#
|
296
|
+
# ---Library#setup key => "statements", ...
|
297
|
+
#
|
298
|
+
# Inserts code in the #init_library_function, which is called when the library
|
299
|
+
# is loaded. The +key+ is used for redundancy checking, as in the #declare
|
300
|
+
# accumulators. Note that hashes are unordered, so constructs like
|
301
|
+
#
|
302
|
+
# setup :x => "...", :y => "..."
|
303
|
+
#
|
304
|
+
# can result in unpredictable order. To avoid this, use several #setup calls.
|
305
|
+
#
|
306
|
+
# ---Library#source_file ---Library#include_file
|
307
|
+
#
|
308
|
+
# Returns the template for the main source or include file of the library.
|
309
|
+
# Usually, there is no need to access these directly.
|
310
|
+
#
|
311
|
+
# ---Library#define_c_function name, type
|
312
|
+
#
|
313
|
+
# Defines a plain ol' C function. Returns a Function template (see below), or a
|
314
|
+
# template of the specified +type+, if given.
|
315
|
+
#
|
316
|
+
# ---Library#define_c_method mod, name, subclass
|
317
|
+
# ---Library#define_c_module_function mod, name, subclass
|
318
|
+
# ---Library#define_c_global_function name, subclass
|
319
|
+
# ---Library#define_c_singleton_method mod, name, subclass
|
320
|
+
# ---Library#define_c_class_method mod, name, subclass
|
321
|
+
#
|
322
|
+
# Defines a function of the specified name and type in the given class/module
|
323
|
+
# (or in the global scope), and returns the function template (often used with
|
324
|
+
# #instance_eval to add arguments, code, etc.). The +subclass+ argument is
|
325
|
+
# optional and allows the template to belong to a subclass of the function
|
326
|
+
# template it would normally belong to.
|
327
|
+
#
|
328
|
+
# For example,
|
329
|
+
#
|
330
|
+
# define_c_method String, "reverse"
|
331
|
+
#
|
332
|
+
# The arguments accepted by the method automatically include +self+. By default,
|
333
|
+
# arguments are passed as individual C arguments, but the can be passed in a
|
334
|
+
# Ruby or C array. The latter has the advantage of argument parsing (based on
|
335
|
+
# rb_scan_args), defaults, and typechecking. See Method#c_array_args.
|
336
|
+
# #define_c_class_method is just an alias for #define_c_singleton_method.
|
337
|
+
#
|
338
|
+
# ---Library#include "file1.h", "<file2.h>", ...
|
339
|
+
#
|
340
|
+
# Insert the include statement(s) at the top of the library's main .c file. For
|
341
|
+
# convenience, <ruby.h> is included automatically, as is the header file of the
|
342
|
+
# library itself.
|
343
|
+
#
|
344
|
+
# ---Library#declare :x => "int x", ... ---Library#declare_extern :x => "int x",
|
345
|
+
# ...
|
346
|
+
#
|
347
|
+
# Puts the string in the declaration area of the .c or .h file, respectively.
|
348
|
+
# The declaration area is before the function definitions, and after the
|
349
|
+
# structure declarations.
|
350
|
+
#
|
351
|
+
# ---Library#declare_struct name, attributes=nil
|
352
|
+
# ---Library#declare_extern_struct name, attributes=nil
|
353
|
+
#
|
354
|
+
# Returns a Structure template, which generates to a typedefed C struct in the
|
355
|
+
# .c or .h file. The #declare method of this template is used to add members.
|
356
|
+
#
|
357
|
+
# ---Library#declare_class cl ---Library#declare_module mod
|
358
|
+
# ---Library#declare_symbol sym
|
359
|
+
#
|
360
|
+
# Define a C variable which will be initialized to refer to the class, module,
|
361
|
+
# or symbol. These accumulators return the name of the C variable which will be
|
362
|
+
# generated and initialized to the ID of the symbol, and this return value can
|
363
|
+
# be interpolated into C calls to the Ruby API. (The arguments are the actual
|
364
|
+
# Ruby objects.) This is very useful in #rb_ivar_get/#rb_ivar_set calls, and it
|
365
|
+
# avoids doing the lookup more than once:
|
366
|
+
#
|
367
|
+
# ...
|
368
|
+
# declare :my_ivar => "VALUE my_ivar"
|
369
|
+
# body %{
|
370
|
+
# my_ivar = rb_ivar_get(shadow->self, #{declare_symbol :@my_ivar});
|
371
|
+
# rb_ivar_set(shadow->self, #{declare_symbol :@my_ivar}, Qnil);
|
372
|
+
# }
|
373
|
+
#
|
374
|
+
# The second declaration notices that the library already has a variable that
|
375
|
+
# will be initialized to the ID of the symbol, and uses it.
|
376
|
+
#
|
377
|
+
# ---Library#literal_symbol sym
|
378
|
+
#
|
379
|
+
# Like Library#declare_symbol, but converts the ID to a VALUE at library
|
380
|
+
# initialization time. Useful for looking up hash values keyed by symbol
|
381
|
+
# objects, for example. +sym+ is a string or symbol.
|
382
|
+
#
|
383
|
+
# ---Library#show_times message
|
384
|
+
#
|
385
|
+
# If the attribute #show_times_flag is set to true, print the user and system
|
386
|
+
# times (and child user and child system on some platforms) and real time for
|
387
|
+
# each major step of the commit process. Display +message+.
|
388
|
+
#
|
389
|
+
# ===File
|
390
|
+
#
|
391
|
+
# File templates are managed by the Library, and most users do not need to
|
392
|
+
# interact with them directly. They are structured into four sections: includes,
|
393
|
+
# structure declarations, variable and function declarations, and function
|
394
|
+
# definitions. Each source file automatically includes its corresponding header
|
395
|
+
# file and the main header file for the library (which includes ruby.h). The
|
396
|
+
# main source file for the library includes each additional header file.
|
397
|
+
#
|
398
|
+
# ---File#define_c_method
|
399
|
+
# ---File#define_c_module_function
|
400
|
+
# ---File#define_c_global_function
|
401
|
+
# ---File#define_c_singleton_method
|
402
|
+
#
|
403
|
+
# As for the Library, but can be used on any source file within the library.
|
404
|
+
# Used to break large projects up into many files.
|
405
|
+
#
|
406
|
+
# ---File#preamble
|
407
|
+
#
|
408
|
+
# An accumulator that wraps its input in C comments and places it at the head of
|
409
|
+
# the source file.
|
410
|
+
#
|
411
|
+
# ===Function
|
412
|
+
#
|
413
|
+
# ---Funtion#scope :static ---Funtion#scope :extern ---Funtion#arguments 'int
|
414
|
+
# x', 'double y', 'VALUE obj', ... ---Funtion#return_type 'void'
|
415
|
+
#
|
416
|
+
# These accumulators affect the prototype of the function, which will be placed
|
417
|
+
# in the declaration section of either the .h or the .c file, depending on the
|
418
|
+
# scope setting. The default scope is static. The default return type is 'void'.
|
419
|
+
#
|
420
|
+
# For the Method subclasses of Function, argument and return types can be
|
421
|
+
# omitted, in which case they default to 'VALUE'.
|
422
|
+
#
|
423
|
+
# ---Funtion#declare :x => "static double x", ... ---Funtion#init "x = 0", ...
|
424
|
+
# ---Funtion#setup 'x' => "x += 1", ... ---Funtion#body 'y = sin(x);
|
425
|
+
# printf("%d\n", y)', ...
|
426
|
+
#
|
427
|
+
# These four accumulators determine the contents of the function between the
|
428
|
+
# opening and closing braces. The #init code is executed once when the function
|
429
|
+
# first runs; it's useful for initializing static data. The #setup code runs
|
430
|
+
# each time the function is called, as does the #body. Distinguishing #setup
|
431
|
+
# from #body is useful for two reasons: first, #setup is guaranteed to execute
|
432
|
+
# before #body, and, second, one can avoid setting up the same variable twice,
|
433
|
+
# because of the key.
|
434
|
+
#
|
435
|
+
# ---Funtion#returns "2*x"
|
436
|
+
#
|
437
|
+
# Specifies the string used in the final return statement of the function.
|
438
|
+
# Subsequent uses of this method clobber the previous value. Alternately, one
|
439
|
+
# can simply insert a "return" manually in the body.
|
440
|
+
#
|
441
|
+
# ===Method ===ModuleFunction ===GlobalFunction ===SingletonMethod
|
442
|
+
#
|
443
|
+
# These subclasses of the Function template are designed for coding Ruby
|
444
|
+
# methods. The necessary registration (+rb_define_method+, etc.) is handled
|
445
|
+
# automatically. Defaults are different from Function: +'VALUE self'+ is
|
446
|
+
# automatically an argument, and argument and return types are assumed to be
|
447
|
+
# +'VALUE'+ and can be omitted by the caller. The return value is +nil+ by
|
448
|
+
# default.
|
449
|
+
#
|
450
|
+
# ---Method#arguments :arg1, :arg2, ...
|
451
|
+
#
|
452
|
+
# The default way of specifying arguments. Allows a fixed number of VALUE
|
453
|
+
# arguments.
|
454
|
+
#
|
455
|
+
# ---Method#c_array_args argc_name = 'argc', argv_name = 'argv', &block
|
456
|
+
# ---Method#rb_array_args args_name = 'args'
|
457
|
+
#
|
458
|
+
# Specifies that arguments are to be collected and passed in a C or Ruby array,
|
459
|
+
# instead of individually (which is the default). In each case, the array of
|
460
|
+
# actual arguments will be bound to a C parameter with the name specified. See
|
461
|
+
# the Ruby API documentation for details.
|
462
|
+
#
|
463
|
+
# If a block is given to Method#c_array_args, it will be used to specify a call
|
464
|
+
# to the API function +rb_scan_args+ and to declare the associated variables.
|
465
|
+
# For example:
|
466
|
+
#
|
467
|
+
# c_array_args('argc', 'argv') {
|
468
|
+
# required :arg0, :arg1
|
469
|
+
# optional :arg2, :arg3, :arg4
|
470
|
+
# rest :rest
|
471
|
+
# block :block
|
472
|
+
# }
|
473
|
+
#
|
474
|
+
# declares all the listed symbols as variables of type +VALUE+ in function
|
475
|
+
# scope, and arranges for the following to be called in the #setup clause (i.e.,
|
476
|
+
# before the #body):
|
477
|
+
#
|
478
|
+
# rb_scan_args(argc, argv, "23*&", &arg0, &arg1, &arg2, &arg3, &arg4, &rest, &block);
|
479
|
+
#
|
480
|
+
# The <tt>'argc', 'argv'</tt> are the default values and are usually omitted.
|
481
|
+
#
|
482
|
+
# The lines in the block can occur in any order, and any line can be omitted.
|
483
|
+
# However, only one line of each kind should be used. In addition, each optional
|
484
|
+
# argument can be associated with a fragment of C code that will be executed to
|
485
|
+
# assign it a default value, if needed. For example, one can add the following
|
486
|
+
# lines to the above block:
|
487
|
+
#
|
488
|
+
# default :arg3 => "INT2NUM(7)",
|
489
|
+
# :arg4 => "INT2NUM(NUM2INT(arg2) + NUM2INT(arg3))"
|
490
|
+
#
|
491
|
+
# Otherwise, optional arguments are assigned nil.
|
492
|
+
#
|
493
|
+
# In this case, if +arg4+ is not provided by +argv+, then it is initialized
|
494
|
+
# using the code given. If, in addition, +arg3+ is not provided, then it too is
|
495
|
+
# initialized. These initializations happen in the #setup clause of the Function
|
496
|
+
# template and are executed in the same order as the arguments are given in the
|
497
|
+
# +optional+ line.
|
498
|
+
#
|
499
|
+
# Finally, argument types can be checked automatically:
|
500
|
+
#
|
501
|
+
# typecheck :arg2 => Numeric, :arg3 => Numeric
|
502
|
+
#
|
503
|
+
# The value passed to the function must either be +nil+ or match the type. Note
|
504
|
+
# that type checking happens *before* default assignment, so that default
|
505
|
+
# calculation code can assume types are correct. No typechecking code is
|
506
|
+
# generated if the type is Object.
|
507
|
+
#
|
508
|
+
# ===Structure
|
509
|
+
#
|
510
|
+
# ---Structure#declare :x => "int x"
|
511
|
+
#
|
512
|
+
# Adds the specified string to define a structure member.
|
513
|
+
#
|
514
|
+
# ===Utility functions
|
515
|
+
#
|
516
|
+
# ---CGenerator.make_c_name s
|
517
|
+
#
|
518
|
+
# Geenrates a unique C itentifier from the given Ruby identifier, which may
|
519
|
+
# include +/[@$?!]/+, +'::'+, and even +'.'+. (Some special globals are not yet
|
520
|
+
# supported: +$:+ and +$-I+, for example.)
|
521
|
+
#
|
522
|
+
# It is unique in the sense that distinct Ruby identifiers map to distinct C
|
523
|
+
# identifiers. (Not completely checked. Might fail for some really obscure
|
524
|
+
# cases.)
|
525
|
+
#
|
526
|
+
# ---String.tab n
|
527
|
+
#
|
528
|
+
# Tabs left or right by n chars, using spaces.
|
529
|
+
#
|
530
|
+
# ---String.tabto n
|
531
|
+
#
|
532
|
+
# The first non-empty line is adjusted to have n spaces before the first
|
533
|
+
# nonspace. Additional lines are changed to preserve relative tabbing.
|
534
|
+
#
|
535
|
+
# ---String.taballto n
|
536
|
+
#
|
537
|
+
# Aligns each line to have n spaces before the first non-space.
|
538
|
+
#
|
539
|
+
# (These routines probably don't work well, if at all, with "hard" tabs.)
|
540
|
+
#
|
541
|
+
# ==Example
|
542
|
+
#
|
543
|
+
# require 'cgen'
|
544
|
+
#
|
545
|
+
# lib = CGenerator::Library.new "sample_lib"
|
546
|
+
#
|
547
|
+
# class Point; end
|
548
|
+
#
|
549
|
+
# lib.declare_extern_struct(:point).instance_eval {
|
550
|
+
# # make it extern so we can see it from another lib
|
551
|
+
# declare :x => "double x"
|
552
|
+
# declare :y => "double y"
|
553
|
+
# }
|
554
|
+
#
|
555
|
+
# lib.define_c_global_function(:new_point).instance_eval {
|
556
|
+
# arguments "x", "y" # 'VALUE' is assumed
|
557
|
+
# declare :p => "point *p"
|
558
|
+
# declare :result => "VALUE result"
|
559
|
+
# # semicolons are added automatically
|
560
|
+
# body %{
|
561
|
+
# result = Data_Make_Struct(#{lib.declare_class Point}, point, 0, free, p);
|
562
|
+
# p->x = NUM2DBL(x);
|
563
|
+
# p->y = NUM2DBL(y);
|
564
|
+
#
|
565
|
+
# // might want to do something like this, too:
|
566
|
+
# // rb_funcall(result, #{lib.declare_symbol :initialize}, 0);
|
567
|
+
# }
|
568
|
+
# returns "result"
|
569
|
+
# # can put a return statement in the body, if preferred
|
570
|
+
# }
|
571
|
+
#
|
572
|
+
# for var in [:x, :y] # metaprogramming in C!
|
573
|
+
# lib.define_c_method(Point, var).instance_eval {
|
574
|
+
# declare :p => "point *p"
|
575
|
+
# body %{
|
576
|
+
# Data_Get_Struct(self, point, p);
|
577
|
+
# }
|
578
|
+
# returns "rb_float_new(p->#{var})"
|
579
|
+
# }
|
580
|
+
# end
|
581
|
+
#
|
582
|
+
# # A utility function, available to other C files
|
583
|
+
# lib.define_c_function("distance").instance_eval {
|
584
|
+
# arguments "point *p1", "point *p2"
|
585
|
+
# return_type "double"
|
586
|
+
# scope :extern
|
587
|
+
# returns "sqrt(pow(p1->x - p2->x, 2) + pow(p1->y - p2->y, 2))"
|
588
|
+
# include "<math.h>"
|
589
|
+
# # The include accumulator call propagates up the parent
|
590
|
+
# # hierarchy until something handles it. In this case,
|
591
|
+
# # the Library lib handles it by adding an include
|
592
|
+
# # directive to the .c file. This allows related, but
|
593
|
+
# # separate aspects of the C source to be handled in
|
594
|
+
# # the same place in the Ruby code. We could also have
|
595
|
+
# # called include directly on lib.
|
596
|
+
# }
|
597
|
+
#
|
598
|
+
# lib.define_c_method(Point, :distance).instance_eval {
|
599
|
+
# # no name conflict between this "distance" and the previous one,
|
600
|
+
# # because "method" and "Point" are both part of the C identifier
|
601
|
+
# # for this method
|
602
|
+
# arguments "other"
|
603
|
+
# declare :p => "point *p"
|
604
|
+
# declare :q => "point *q"
|
605
|
+
# body %{
|
606
|
+
# Data_Get_Struct(self, point, p);
|
607
|
+
# Data_Get_Struct(other, point, q);
|
608
|
+
# }
|
609
|
+
# returns "rb_float_new(distance(p, q))"
|
610
|
+
# }
|
611
|
+
#
|
612
|
+
# lib.commit # now you can use the new definitions
|
613
|
+
#
|
614
|
+
# p1 = new_point(1, 2)
|
615
|
+
# puts "p1: x is #{p1.x}, y is #{p1.y}"
|
616
|
+
#
|
617
|
+
# p2 = new_point(5, 8)
|
618
|
+
# puts "p2: x is #{p2.x}, y is #{p2.y}"
|
619
|
+
#
|
620
|
+
# puts "distance from p1 to p2 is #{p1.distance p2}"
|
621
|
+
#
|
622
|
+
# Output is:
|
623
|
+
#
|
624
|
+
# p1: x is 1.0, y is 2.0
|
625
|
+
# p2: x is 5.0, y is 8.0
|
626
|
+
# distance from p1 to p2 is 7.211102551
|
627
|
+
#
|
628
|
+
# That's a lot of code to do a simple operation, compared with an Inline-style
|
629
|
+
# construct. CGenerator's value shows up with more complex tasks. The
|
630
|
+
# +sample.rb+ file extends this example.
|
631
|
+
#
|
632
|
+
# ==Notes
|
633
|
+
#
|
634
|
+
# * My first Ruby extension was built with this module. That speaks well of the
|
635
|
+
# elegance, simplicity, and utter coolness of Ruby and its extension
|
636
|
+
# architecture. Thanks matz!
|
637
|
+
#
|
638
|
+
# * Some accumulators, like declare_symbol and declare_class, operate by default
|
639
|
+
# on the file scope, even if called on a method definition, so the declarations
|
640
|
+
# are shared across the library. This reduces redundancy with no disadvantage.
|
641
|
+
# (In general, accumulator calls propagate first thru the inheritance hierarchy
|
642
|
+
# and then thru the parent Template hierarchy.)
|
643
|
+
#
|
644
|
+
# * Note that accumulators can nest within accumulators, because #to_s is
|
645
|
+
# applied recursively. This is *very* useful (see Library#initialize for
|
646
|
+
# example). This defines a many-to-one dataflow pattern among accumulators. A
|
647
|
+
# one-to-many dataflow pattern arises when a method calls several accumulators,
|
648
|
+
# as in #define_c_method and kin.
|
649
|
+
#
|
650
|
+
# * CGenerator makes no attempt to check for C syntax errors in code supplied to
|
651
|
+
# the accumulators.
|
652
|
+
#
|
653
|
+
# * It may help to think of templates as heterogeneous collections, like
|
654
|
+
# structs, and accumulators as homogeneous collections, like arrays.
|
655
|
+
#
|
656
|
+
# * The containment hierarchy is represented by the #parent accessor in
|
657
|
+
# Accumulators and Templates. It provides a secondary inheritance of calls to
|
658
|
+
# accumulators. (As a result, doing #include at the function level adds an
|
659
|
+
# #include directive at the file level.)
|
660
|
+
#
|
661
|
+
# * The basic Template and Accumulator class are more general than C source, or
|
662
|
+
# even strings. The Module#inherit method is also reusable.
|
663
|
+
#
|
664
|
+
# * CGenerator does not allow more than one C function with the same name. This
|
665
|
+
# could be changed fairly easily.
|
666
|
+
#
|
667
|
+
# * You can subclass Library and override #extconf to do more complex processing
|
668
|
+
# than just #create_makefile.
|
669
|
+
#
|
670
|
+
# * Calling a #to_s method on an accumulator more than once has no unexpected
|
671
|
+
# side effects. It can be called at any time for a snapshot of the whole library
|
672
|
+
# or of a subtemplate.
|
673
|
+
#
|
674
|
+
# * CGenerator is probably not very efficient, so it may not be useful with
|
675
|
+
# large amounts of C code.
|
676
|
+
#
|
677
|
+
# * Library#commit will try to commit even if already comitted (in which case it
|
678
|
+
# raises a CommitError) or if the lib is empty. Use #committed? and #empty? to
|
679
|
+
# check for these cases. (Should these checks, or just the latter, be
|
680
|
+
# automatic?)
|
681
|
+
#
|
682
|
+
# * Library#commit first reads the .c and .h file and checks for changes. If
|
683
|
+
# there are none, it doesn't write to the file. If neither file gets written to,
|
684
|
+
# make won't need to compile them...
|
685
|
+
#
|
686
|
+
# * CGenerator generates header file entries for any non-static functions or
|
687
|
+
# data. This can be used for communication between files in the library without
|
688
|
+
# using Ruby calls, and to provide an API for other C libraries and executables.
|
689
|
+
#
|
690
|
+
# * Accumulator#inspect is a nice hierarchy-aware inspector.
|
691
|
+
#
|
692
|
+
# ==To do
|
693
|
+
#
|
694
|
+
# * Automatically generate inner and outer functions as in Michael Neumann's
|
695
|
+
# cplusruby. Similarly, should there be another field to refer to a struct of
|
696
|
+
# function pointers, so that C code can call the inner functions without
|
697
|
+
# funcall?
|
698
|
+
#
|
699
|
+
# * Try CFLAGS for optimization: with gcc, -march, -O3, -fomit-frame-pointer
|
700
|
+
#
|
701
|
+
# * Rename to something less generic (cgen --> "sagehen"?)
|
702
|
+
#
|
703
|
+
# * Option to target ruby/ext dir: generate MANIFEST file, but no Makefile. What
|
704
|
+
# about depend? how to generate it in installation-independent format?
|
705
|
+
#
|
706
|
+
# * Let user set dir to build in, rather than rely on chdir, which is not thread
|
707
|
+
# safe.
|
708
|
+
#
|
709
|
+
# * Instead of using an external program to makedepend, do it manually based on
|
710
|
+
# include operations? (Might have to do this anyway on mswin.)
|
711
|
+
#
|
712
|
+
# * Investigate Tiny C--Linux only, but fast, and libtcc allows dynamic codegen.
|
713
|
+
# Maybe best used in "develop" mode, rather than for production code (no -O).
|
714
|
+
#
|
715
|
+
# * Option in define_c_method to make method private/protected (see
|
716
|
+
# rb_define_private/protected_method in intern.h).
|
717
|
+
#
|
718
|
+
# * Optimization: declare_symbol and declare_module should do less work if the
|
719
|
+
# declaration has already neen done.
|
720
|
+
#
|
721
|
+
# * Macros, e.g. something for rb_funcall that does the declare_class for you.
|
722
|
+
#
|
723
|
+
# * Extend c_array_args features to rb_array_args and fixed length arglists.
|
724
|
+
#
|
725
|
+
# * Exception if modify descendant of Library after committed. Accumulators
|
726
|
+
# always notify parent before admitting any changes.
|
727
|
+
#
|
728
|
+
# * Freeze data structures after commit?
|
729
|
+
#
|
730
|
+
# * More wrappers: define_class, globals (in C and in Ruby), funcalls,
|
731
|
+
# iterators, argument type conversion, etc. Really, all of Chapter 17 of Thomas
|
732
|
+
# & Hunt.
|
733
|
+
#
|
734
|
+
# * Make commit happen automatically when the first call is made to a method in
|
735
|
+
# the library. (Use alias, maybe, since method_missing won't work--won't let you
|
736
|
+
# override.)
|
737
|
+
#
|
738
|
+
# * Finer granularity in accumulators. For example, #init could take a (lvalue,
|
739
|
+
# rvalue) pair, which would allow it to detect initialization of the same var
|
740
|
+
# with different values.
|
741
|
+
#
|
742
|
+
# * make this into Inline for ruby:
|
743
|
+
#
|
744
|
+
# Module#define_c_method ("name") { ... }
|
745
|
+
#
|
746
|
+
# (use instance_eval, so that accumulators can be used in the block?) The main
|
747
|
+
# drawback is that no Library is specified, so where does it go? (Actually,
|
748
|
+
# CShadow solves this problem, if you don't mind having a struct as overhead.)
|
749
|
+
#
|
750
|
+
# * investigate unloading a .so/.dll. Or: maybe rb_define_* can be called again,
|
751
|
+
# but in a different library (append version number to the lib name, but not to
|
752
|
+
# the dir name). See Ruby/DL in RAA. (See dln.c, eval.c, ruby.c in ruby source.
|
753
|
+
# It all seems possible, but a bit of work.)
|
754
|
+
#
|
755
|
+
# * parser/generator for (at first) simple ruby code, like '@x.y': one option
|
756
|
+
# would be to use init to define a Proc and use setup to call the Proc
|
757
|
+
#
|
758
|
+
# * check ANSI, check w/ other compilers
|
759
|
+
#
|
760
|
+
# * Improve space recognition in the tab routines (check for \t and handle
|
761
|
+
# intelligently, etc.).
|
762
|
+
#
|
763
|
+
# * Formalize the relation between templates and accumulators. Make it easier
|
764
|
+
# for client code to use its own templates and accumulators.
|
765
|
+
#
|
766
|
+
# * Double-ended accumulators (add_at_end vs. add_at_beginning, or push vs.
|
767
|
+
# unshift).
|
768
|
+
#
|
769
|
+
# * Automatically load/link other dynamic or static libs in the same dir. For
|
770
|
+
# static, use 'have_library' in #extconf; see p.185 of pickaxe. For dynamic, use
|
771
|
+
# Ruby/DL from RAA, or just require. (Currently, this can be done manually by
|
772
|
+
# subclassing and overriding extconf.)
|
773
|
+
#
|
774
|
+
# * More thorough checking for assert_uncommitted. Currently, just a few
|
775
|
+
# top-level methods (Library#commit and some of the define methods) check if the
|
776
|
+
# library has already been committed. Ideally, #commit would freeze all
|
777
|
+
# accumulators. But then the problem is how to report a freeze exception in a
|
778
|
+
# way that makes clear that the problem is really with commit.
|
779
|
+
module CGenerator
|
780
|
+
|
781
|
+
VERSION = '0.16.0'
|
782
|
+
|
783
|
+
class Accumulator ## should be a mixin? "Cumulative"?
|
784
|
+
|
785
|
+
## should delegate Accs into two objects with two inheritance hierarchies,
|
786
|
+
## one for adding items, one for generating strings
|
787
|
+
##OR:
|
788
|
+
## two hierarchies of modules that get included into Template subclasses
|
789
|
+
|
790
|
+
attr_reader :name, :parent
|
791
|
+
|
792
|
+
def initialize name, parent = nil
|
793
|
+
@name = name; @parent = parent
|
794
|
+
@pile = []
|
795
|
+
end
|
796
|
+
|
797
|
+
def accept? item
|
798
|
+
true
|
799
|
+
end
|
800
|
+
|
801
|
+
def add_one_really item
|
802
|
+
@pile << item
|
803
|
+
end
|
804
|
+
|
805
|
+
def add_one item
|
806
|
+
add_one_really item if accept? item
|
807
|
+
end
|
808
|
+
|
809
|
+
def add(*items)
|
810
|
+
for item in items
|
811
|
+
add_one item
|
812
|
+
end
|
813
|
+
end
|
814
|
+
|
815
|
+
def output_one item
|
816
|
+
item
|
817
|
+
end
|
818
|
+
|
819
|
+
def output items
|
820
|
+
items.collect { |item|
|
821
|
+
output_one item
|
822
|
+
}.select { |item|
|
823
|
+
item && item != ""
|
824
|
+
}
|
825
|
+
end
|
826
|
+
|
827
|
+
def separator; "\n"; end
|
828
|
+
|
829
|
+
def to_s
|
830
|
+
output(@pile).join(separator)
|
831
|
+
end
|
832
|
+
|
833
|
+
def inspect
|
834
|
+
eol = "\n" if @pile.size > 0
|
835
|
+
s = "s" if @pile.size != 1
|
836
|
+
%{<#{self.class} "#{@name}": #{@pile.size} item#{s}>#{eol}} +
|
837
|
+
@pile.collect { |item| inspect_one item }.join("\n").tabto(2)
|
838
|
+
end
|
839
|
+
|
840
|
+
def inspect_one item
|
841
|
+
item.inspect
|
842
|
+
end
|
843
|
+
|
844
|
+
end # class Accumulator
|
845
|
+
|
846
|
+
module SetAccumulator
|
847
|
+
def accept? item
|
848
|
+
not @pile.include? item
|
849
|
+
end
|
850
|
+
end
|
851
|
+
|
852
|
+
module KeyAccumulator
|
853
|
+
def initialize(*args)
|
854
|
+
super
|
855
|
+
@hash = {} # @pile maintains ordered list of keys for @hash
|
856
|
+
end
|
857
|
+
|
858
|
+
def add_one item
|
859
|
+
## why not do this?
|
860
|
+
# unless item.is_a? Hash
|
861
|
+
# raise ArgumentError,
|
862
|
+
# "Tried to add non-hash '#{item}' to KeyAccumulator."
|
863
|
+
# end
|
864
|
+
|
865
|
+
item = item.sort_by {|k,v| k.to_s} unless item.is_a?(Array)
|
866
|
+
|
867
|
+
for key, value in item
|
868
|
+
if not @hash.has_key? key
|
869
|
+
super key
|
870
|
+
end
|
871
|
+
@hash[key] = value_filter(value)
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
def value_filter(value)
|
876
|
+
value
|
877
|
+
end
|
878
|
+
|
879
|
+
def output_one item
|
880
|
+
super @hash[item]
|
881
|
+
end
|
882
|
+
|
883
|
+
def inspect_one item
|
884
|
+
@hash[item].inspect
|
885
|
+
end
|
886
|
+
|
887
|
+
def [](item)
|
888
|
+
@hash[item]
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
class Template < Accumulator
|
893
|
+
|
894
|
+
def initialize name = "", parent = nil, &block
|
895
|
+
super
|
896
|
+
instance_eval(&block) if block
|
897
|
+
## not very useful: users call an accumulator, rather than Template#new
|
898
|
+
end
|
899
|
+
|
900
|
+
def Template.accumulator(*names)
|
901
|
+
kind = if block_given? then yield else Accumulator end
|
902
|
+
|
903
|
+
for name in names
|
904
|
+
|
905
|
+
module_eval %{
|
906
|
+
def #{name}(*items)
|
907
|
+
#{name}!.add(*items)
|
908
|
+
end
|
909
|
+
def #{name}!
|
910
|
+
@#{name} ||= #{kind}.new(:#{name}, self)
|
911
|
+
end
|
912
|
+
}
|
913
|
+
|
914
|
+
unless Template.respond_to? name
|
915
|
+
Template.inherit :@parent, name
|
916
|
+
end
|
917
|
+
|
918
|
+
end
|
919
|
+
|
920
|
+
end
|
921
|
+
|
922
|
+
end # class Template
|
923
|
+
|
924
|
+
|
925
|
+
class Library < Template
|
926
|
+
|
927
|
+
class CommitError < RuntimeError; end
|
928
|
+
|
929
|
+
attr_reader :init_library_function, :include_file, :source_file
|
930
|
+
attr_accessor :purge_source_dir, :show_times_flag
|
931
|
+
|
932
|
+
def initialize name
|
933
|
+
super name
|
934
|
+
|
935
|
+
@show_times_flag = @purge_source_dir = false
|
936
|
+
@committed = false
|
937
|
+
@source_file = nil
|
938
|
+
|
939
|
+
@rtime = Time.now.to_f
|
940
|
+
@ptime = process_times
|
941
|
+
|
942
|
+
unless name =~ /\A[A-Za-z_]\w*\z/
|
943
|
+
raise NameError,
|
944
|
+
"\n Not a valid library name: '#{name}'." +
|
945
|
+
"\n Name must be a C identifier."
|
946
|
+
end
|
947
|
+
|
948
|
+
@include_file, @source_file = add_file name
|
949
|
+
@include_file.include '<ruby.h>'
|
950
|
+
|
951
|
+
@init_library_function = define_c_function "Init_" + name
|
952
|
+
@init_library_function.scope :extern
|
953
|
+
|
954
|
+
@init_library_function.body \
|
955
|
+
rb_define_method!,
|
956
|
+
rb_define_module_function!,
|
957
|
+
rb_define_global_function!,
|
958
|
+
rb_define_singleton_method!
|
959
|
+
## odd, putting an accum inside
|
960
|
+
## a template which is not the parent
|
961
|
+
end
|
962
|
+
|
963
|
+
def use_work_dir dir_name
|
964
|
+
if File.basename(Dir.pwd) == dir_name
|
965
|
+
yield
|
966
|
+
else
|
967
|
+
require 'fileutils'
|
968
|
+
FileUtils.makedirs dir_name
|
969
|
+
Dir.chdir dir_name do
|
970
|
+
yield
|
971
|
+
end
|
972
|
+
end
|
973
|
+
end
|
974
|
+
|
975
|
+
def add_file name, opts = {}
|
976
|
+
pair = @pile.detect {|p| p[0].name == name + ".h"}
|
977
|
+
|
978
|
+
if not pair
|
979
|
+
new_include_file = CFile.new name + ".h", self
|
980
|
+
new_source_file = CFile.new name + ".c", self, new_include_file
|
981
|
+
|
982
|
+
if @source_file
|
983
|
+
new_source_file.include @include_file unless opts[:independent]
|
984
|
+
@source_file.include new_include_file
|
985
|
+
end
|
986
|
+
new_source_file.include new_include_file
|
987
|
+
|
988
|
+
pair = [new_include_file, new_source_file]
|
989
|
+
add pair # for inspect and commit
|
990
|
+
end
|
991
|
+
|
992
|
+
return pair
|
993
|
+
end
|
994
|
+
|
995
|
+
def assert_uncommitted
|
996
|
+
if @committed
|
997
|
+
raise CommitError, "\nLibrary #{@name} has already been committed."
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
|
1001
|
+
def committed?
|
1002
|
+
@committed
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
def empty?
|
1006
|
+
@init_library_function.empty? ## is this enough?
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def before_commit(&block)
|
1010
|
+
(@before_commit ||= []) << block
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def after_commit(&block)
|
1014
|
+
(@after_commit ||= []) << block
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def commit(build = true)
|
1018
|
+
assert_uncommitted
|
1019
|
+
|
1020
|
+
while @before_commit
|
1021
|
+
bc = @before_commit; @before_commit = nil
|
1022
|
+
bc.each {|block| block[self]}
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
@committed = true
|
1026
|
+
|
1027
|
+
if build
|
1028
|
+
@logname ||= "make.log"
|
1029
|
+
|
1030
|
+
show_times "precommit"
|
1031
|
+
show_times "write" do write end
|
1032
|
+
show_times "makedepend" do makedepend end
|
1033
|
+
show_times "mkmf" do mkmf end
|
1034
|
+
show_times "make" do make end
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
show_times "loadlib" do loadlib end
|
1038
|
+
|
1039
|
+
while @after_commit
|
1040
|
+
ac = @after_commit; @after_commit = nil
|
1041
|
+
ac.reverse.each {|block| block[self]}
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
def process_times
|
1046
|
+
RUBY_VERSION.to_f >= 1.7 ? Process.times : Time.times
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
def show_times message
|
1050
|
+
yield if block_given?
|
1051
|
+
if @show_times_flag
|
1052
|
+
unless @show_times_started
|
1053
|
+
printf "\n%20s %6s %6s %6s %6s %7s\n",
|
1054
|
+
"__step__", "utime", "stime", "cutime", "cstime", "real"
|
1055
|
+
@show_times_started = true
|
1056
|
+
end
|
1057
|
+
ptime = self.process_times
|
1058
|
+
rtime = Time.now.to_f
|
1059
|
+
printf "%20s %6.2f %6.2f %6.2f %6.2f %7.3f\n", message,
|
1060
|
+
ptime.utime - @ptime.utime, ptime.stime - @ptime.stime,
|
1061
|
+
ptime.cutime - @ptime.cutime, ptime.cstime - @ptime.cstime,
|
1062
|
+
rtime - @rtime
|
1063
|
+
@ptime = ptime
|
1064
|
+
@rtime = rtime
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
def write
|
1069
|
+
build_wrapper do
|
1070
|
+
templates = @pile.flatten.sort_by { |t| t.name }
|
1071
|
+
|
1072
|
+
if @purge_source_dir
|
1073
|
+
# hide or delete files not listed in templates
|
1074
|
+
files = Dir["*.{c,h,o}"]
|
1075
|
+
template_files = templates.map { |t| t.name }
|
1076
|
+
template_files +=
|
1077
|
+
template_files.grep(/\.c$/).map { |f| f.sub(/\.c$/, ".o") }
|
1078
|
+
for file in files - template_files
|
1079
|
+
if @purge_source_dir == :delete
|
1080
|
+
File.delete(file) rescue SystemCallError
|
1081
|
+
else
|
1082
|
+
File.rename(file, file + ".hide") rescue SystemCallError
|
1083
|
+
end
|
1084
|
+
end
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
for template in templates do
|
1088
|
+
begin
|
1089
|
+
File.open(template.name, 'r+') {|f| update_file f, template}
|
1090
|
+
rescue SystemCallError
|
1091
|
+
File.open(template.name, 'w+') {|f| update_file f, template}
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
def update_file f, template
|
1098
|
+
template_str = template.to_s
|
1099
|
+
file_data = f.gets(nil) ## sysread is faster?
|
1100
|
+
unless file_data == template_str
|
1101
|
+
if defined?($CGEN_VERBOSE) and $CGEN_VERBOSE
|
1102
|
+
print_update_reason(template, template_str, file_data)
|
1103
|
+
end
|
1104
|
+
f.rewind
|
1105
|
+
f.print template_str
|
1106
|
+
f.truncate f.pos
|
1107
|
+
end
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
def print_update_reason template, template_str, file_data
|
1111
|
+
puts "\nUpdating file #{template.name}"
|
1112
|
+
|
1113
|
+
if file_data == nil
|
1114
|
+
puts "File on disk is empty"
|
1115
|
+
return
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
s = file_data
|
1119
|
+
t = template_str
|
1120
|
+
slines = s.split "\n"
|
1121
|
+
tlines = t.split "\n"
|
1122
|
+
i = 0
|
1123
|
+
sline = slines[i]
|
1124
|
+
tline = tlines[i]
|
1125
|
+
catch :done do
|
1126
|
+
while sline and tline
|
1127
|
+
if sline != tline
|
1128
|
+
puts "Line #{i+1}",
|
1129
|
+
"On disk: #{sline.inspect}",
|
1130
|
+
"In memory: #{tline.inspect}",
|
1131
|
+
""
|
1132
|
+
throw :done
|
1133
|
+
end
|
1134
|
+
i += 1
|
1135
|
+
sline = slines[i]
|
1136
|
+
tline = tlines[i]
|
1137
|
+
end
|
1138
|
+
if sline == nil and tline == nil
|
1139
|
+
puts "Very strange, no difference found!"
|
1140
|
+
else
|
1141
|
+
if slines.size > tlines.size
|
1142
|
+
puts "file on disk is longer"
|
1143
|
+
else
|
1144
|
+
puts "file in memory is longer"
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
def makedepend
|
1151
|
+
return if /mswin/i =~ RUBY_PLATFORM ## what else can we do?
|
1152
|
+
build_wrapper do
|
1153
|
+
cfg = Config::CONFIG
|
1154
|
+
dirs = [cfg["sitearchdir"], cfg["archdir"], cfg["includedir"]]
|
1155
|
+
result = system %{
|
1156
|
+
touch depend
|
1157
|
+
makedepend -fdepend *.c -I#{dirs.join " -I"} >#{@logname} 2>&1
|
1158
|
+
} ## what about "gcc -MM" as in step 6 in README.EXT ?
|
1159
|
+
unless result
|
1160
|
+
log_data = File.read(@logname) rescue nil
|
1161
|
+
msg = "\n makedepend failed for #{@name}."
|
1162
|
+
if log_data
|
1163
|
+
msg <<
|
1164
|
+
"\n Transcript is saved in #{@name}/#{@logname} and follows:" +
|
1165
|
+
"\n " + "_" * 60 +
|
1166
|
+
"\n" + log_data.tabto(3).gsub(/^ /, " |") +
|
1167
|
+
" " + "_" * 60 + "\n"
|
1168
|
+
else
|
1169
|
+
msg <<
|
1170
|
+
"\n No log available.\n"
|
1171
|
+
end
|
1172
|
+
raise CommitError, msg
|
1173
|
+
end
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
def mkmf
|
1178
|
+
need_to_make_clean = false
|
1179
|
+
|
1180
|
+
# Need to do this in a separate process because mkmf.rb pollutes
|
1181
|
+
# the global namespace.
|
1182
|
+
build_wrapper do
|
1183
|
+
require 'rbconfig'
|
1184
|
+
ruby = Config::CONFIG["RUBY_INSTALL_NAME"]
|
1185
|
+
|
1186
|
+
old_contents = File.read("extconf.rb") rescue nil
|
1187
|
+
contents = extconf
|
1188
|
+
require 'stringio'
|
1189
|
+
s = StringIO.new
|
1190
|
+
s.puts(contents)
|
1191
|
+
s.rewind
|
1192
|
+
contents = s.read
|
1193
|
+
|
1194
|
+
if old_contents != contents
|
1195
|
+
File.open("extconf.rb", "w") do |f|
|
1196
|
+
f.puts contents
|
1197
|
+
end
|
1198
|
+
need_to_make_clean = true
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
system %{
|
1202
|
+
#{ruby} extconf.rb > #{@logname}
|
1203
|
+
}
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
make "clean" if need_to_make_clean
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
## use -j and -l make switches for multiprocessor builds (man sysconf)
|
1210
|
+
## see http://www.gnu.org/manual/make/html_chapter/make_5.html#SEC47
|
1211
|
+
def make arg = nil
|
1212
|
+
build_wrapper do
|
1213
|
+
unless system "#{make_program} #{arg} >>#{@logname} 2>&1"
|
1214
|
+
raise CommitError,
|
1215
|
+
"\n Make #{arg} failed for #{@name}." +
|
1216
|
+
"\n Transcript is saved in #{@name}/#{@logname} and follows:" +
|
1217
|
+
"\n " + "_" * 60 +
|
1218
|
+
"\n" + File.read(@logname).tabto(3).gsub(/^ /, " |") +
|
1219
|
+
" " + "_" * 60 + "\n"
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
if arg == 'clean' or arg == 'distclean'
|
1223
|
+
File.delete(@logname) rescue SystemCallError
|
1224
|
+
if arg == 'distclean'
|
1225
|
+
for template in @pile.flatten do
|
1226
|
+
File.delete(template.name) rescue SystemCallError
|
1227
|
+
end
|
1228
|
+
end
|
1229
|
+
end
|
1230
|
+
end
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
def make_program
|
1234
|
+
case RUBY_PLATFORM
|
1235
|
+
when /mswin/i
|
1236
|
+
"nmake"
|
1237
|
+
when /mingw/i
|
1238
|
+
"make"
|
1239
|
+
# "mingw32-make" is the MSYS-independent, MSVC native version
|
1240
|
+
# which is supposedly less useful
|
1241
|
+
else
|
1242
|
+
"make"
|
1243
|
+
end
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
def build_wrapper
|
1247
|
+
if File.exists? @name
|
1248
|
+
unless File.directory? @name
|
1249
|
+
raise CommitError, "Library #{@name}: Can't mkdir; file exists."
|
1250
|
+
end
|
1251
|
+
else
|
1252
|
+
Dir.mkdir @name
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
Dir.chdir @name do yield end
|
1256
|
+
### this is fragile--should record abs path when Lib is created
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
# Yields the array of lines being constructed so that additional configuration
|
1260
|
+
# can be added. See the ruby documentation on mkmf.
|
1261
|
+
def extconf # :yields: lines_array
|
1262
|
+
a = []
|
1263
|
+
a << "require 'mkmf'"
|
1264
|
+
a << "$CFLAGS = \"#$CFLAGS\"" if defined?($CFLAGS)
|
1265
|
+
yield a if block_given?
|
1266
|
+
a << "create_makefile '#{@name}'"
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
def loadlib
|
1270
|
+
require File.join(".", @name, @name)
|
1271
|
+
rescue ScriptError, StandardError => e
|
1272
|
+
raise e.class, "\nCgen: problem loading library:\n" + e.message
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
class RbDefineAccumulator < Accumulator
|
1276
|
+
def add spec
|
1277
|
+
c_name = spec[:c_name]
|
1278
|
+
mod = spec[:mod]
|
1279
|
+
rb_name = spec[:rb_name]
|
1280
|
+
|
1281
|
+
meth_rec =
|
1282
|
+
if c_name
|
1283
|
+
@pile.find { |s| s[:c_name] == c_name }
|
1284
|
+
else
|
1285
|
+
@pile.find { |s| s[:mod] == mod and s[:rb_name] == rb_name }
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
if meth_rec
|
1289
|
+
meth_rec.update spec
|
1290
|
+
else
|
1291
|
+
meth_rec = spec
|
1292
|
+
|
1293
|
+
unless rb_name
|
1294
|
+
raise ArgumentError, "define: must provide method name."
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
kind = @name.to_s.sub(/\Arb_define_/, "")
|
1298
|
+
if mod
|
1299
|
+
meth_rec[:mod_c_name] ||= @parent.declare_module(mod) ## @parent ?
|
1300
|
+
meth_rec[:c_name] ||=
|
1301
|
+
("#{CGenerator::make_c_name rb_name}" +
|
1302
|
+
"_#{meth_rec[:mod_c_name]}_#{kind}").intern
|
1303
|
+
else
|
1304
|
+
meth_rec[:c_name] ||=
|
1305
|
+
"#{CGenerator::make_c_name rb_name}_#{kind}".intern
|
1306
|
+
end
|
1307
|
+
meth_rec[:argc] ||= 0
|
1308
|
+
@pile << meth_rec
|
1309
|
+
end
|
1310
|
+
|
1311
|
+
meth_rec[:c_name]
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
def to_s
|
1315
|
+
@pile.collect { |m|
|
1316
|
+
rb_name = m[:rb_name]
|
1317
|
+
c_name = m[:c_name]
|
1318
|
+
argc = m[:argc]
|
1319
|
+
if m[:mod]
|
1320
|
+
mod_c_name = m[:mod_c_name]
|
1321
|
+
"#{@name}(#{mod_c_name}, \"#{rb_name}\", #{c_name}, #{argc});"
|
1322
|
+
else
|
1323
|
+
"#{@name}(\"#{rb_name}\", #{c_name}, #{argc});"
|
1324
|
+
end
|
1325
|
+
}.join "\n"
|
1326
|
+
end
|
1327
|
+
|
1328
|
+
end # class RbDefineAccumulator
|
1329
|
+
|
1330
|
+
accumulator(:rb_define_method,
|
1331
|
+
:rb_define_module_function,
|
1332
|
+
:rb_define_global_function,
|
1333
|
+
:rb_define_singleton_method) {RbDefineAccumulator}
|
1334
|
+
|
1335
|
+
def define_c_method(*args)
|
1336
|
+
@source_file.define_c_method(*args)
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
def define_c_module_function(*args)
|
1340
|
+
@source_file.define_c_module_function(*args)
|
1341
|
+
end
|
1342
|
+
|
1343
|
+
def define_c_global_function(*args)
|
1344
|
+
@source_file.define_c_global_function(*args)
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
def define_c_singleton_method(*args)
|
1348
|
+
@source_file.define_c_singleton_method(*args)
|
1349
|
+
end
|
1350
|
+
alias define_c_class_method define_c_singleton_method
|
1351
|
+
|
1352
|
+
def include(*args)
|
1353
|
+
@source_file.include(*args)
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
def declare(*args)
|
1357
|
+
@source_file.declare(*args)
|
1358
|
+
end
|
1359
|
+
alias declare_static declare
|
1360
|
+
|
1361
|
+
def declare_extern(*args)
|
1362
|
+
@include_file.declare(*args)
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
def declare_struct struct_name, *rest
|
1366
|
+
@source_file.declare_struct struct_name, *rest
|
1367
|
+
end
|
1368
|
+
alias declare_static_struct declare_struct
|
1369
|
+
|
1370
|
+
def declare_extern_struct struct_name, *rest
|
1371
|
+
@include_file.declare_struct struct_name, *rest
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
def define(*args)
|
1375
|
+
@source_file.define(*args)
|
1376
|
+
end
|
1377
|
+
alias define_c_function define
|
1378
|
+
|
1379
|
+
def declare_module mod
|
1380
|
+
c_name = "module_#{CGenerator::make_c_name mod.to_s}"
|
1381
|
+
declare mod => "VALUE #{c_name}"
|
1382
|
+
declare_extern mod => "extern VALUE #{c_name}"
|
1383
|
+
setup mod => "#{c_name} = rb_path2class(\"#{mod}\")"
|
1384
|
+
c_name.intern
|
1385
|
+
end
|
1386
|
+
alias declare_class declare_module
|
1387
|
+
|
1388
|
+
def declare_symbol sym
|
1389
|
+
c_name = "ID_#{CGenerator::make_c_name sym}"
|
1390
|
+
declare sym => "ID #{c_name}"
|
1391
|
+
declare_extern sym => "extern ID #{c_name}"
|
1392
|
+
setup sym => "#{c_name} = rb_intern(\"#{sym}\")"
|
1393
|
+
c_name.intern
|
1394
|
+
end
|
1395
|
+
|
1396
|
+
def literal_symbol sym
|
1397
|
+
c_name = "SYM_#{CGenerator::make_c_name sym}"
|
1398
|
+
declare sym => "VALUE #{c_name}"
|
1399
|
+
declare_extern sym => "extern VALUE #{c_name}"
|
1400
|
+
setup sym => "#{c_name} = ID2SYM(rb_intern(\"#{sym}\"))"
|
1401
|
+
c_name.intern
|
1402
|
+
end
|
1403
|
+
|
1404
|
+
def setup(*args)
|
1405
|
+
@init_library_function.setup(*args)
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
Template.inherit :parent,
|
1409
|
+
:declare_module, :declare_symbol,
|
1410
|
+
:declare_static, :declare_extern,
|
1411
|
+
:declare_class, :declare_module,
|
1412
|
+
:literal_symbol,
|
1413
|
+
:library, :file,
|
1414
|
+
:assert_uncommitted
|
1415
|
+
|
1416
|
+
def library
|
1417
|
+
self
|
1418
|
+
end
|
1419
|
+
|
1420
|
+
end # class Library
|
1421
|
+
|
1422
|
+
|
1423
|
+
class CFragment < Template
|
1424
|
+
|
1425
|
+
class StatementAccumulator < Accumulator
|
1426
|
+
def add_one_really item
|
1427
|
+
if item.kind_of? String
|
1428
|
+
super item.tabto(0)
|
1429
|
+
else
|
1430
|
+
super
|
1431
|
+
end
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
def output_one item
|
1435
|
+
str = item.to_s
|
1436
|
+
# if str =~ /(?:\A|[;}])\s*\z/
|
1437
|
+
if str.empty? or str =~ /[\s;}]\z/ or str =~ /\A\s*(?:\/\/|#)/
|
1438
|
+
str
|
1439
|
+
else
|
1440
|
+
str + ';'
|
1441
|
+
end
|
1442
|
+
end
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
class StatementKeyAccumulator < StatementAccumulator
|
1446
|
+
include KeyAccumulator
|
1447
|
+
def value_filter(value)
|
1448
|
+
if value.kind_of? String
|
1449
|
+
super value.tabto(0)
|
1450
|
+
else
|
1451
|
+
super
|
1452
|
+
end
|
1453
|
+
end
|
1454
|
+
end
|
1455
|
+
|
1456
|
+
class BlockAccumulator < StatementAccumulator
|
1457
|
+
def add(*args)
|
1458
|
+
super
|
1459
|
+
return self
|
1460
|
+
end
|
1461
|
+
def to_s
|
1462
|
+
["{", super.tabto(4), "}"].join "\n"
|
1463
|
+
end
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
class SingletonAccumulator < Accumulator
|
1467
|
+
def add_one item
|
1468
|
+
@pile = [item]
|
1469
|
+
end
|
1470
|
+
end
|
1471
|
+
|
1472
|
+
end # class CFragment
|
1473
|
+
|
1474
|
+
|
1475
|
+
class CFile < CFragment
|
1476
|
+
|
1477
|
+
attr_reader :include_file
|
1478
|
+
|
1479
|
+
def initialize name, library, include_file = nil
|
1480
|
+
super name, library
|
1481
|
+
@include_file = include_file
|
1482
|
+
if include_file
|
1483
|
+
add preamble!, include!, declare!, define!
|
1484
|
+
else
|
1485
|
+
## it's a little hacky to decide in this way that this is a .h file
|
1486
|
+
sym = name.gsub(/\W/, '_')
|
1487
|
+
add "#ifndef #{sym}\n#define #{sym}",
|
1488
|
+
preamble!, include!, declare!, define!,
|
1489
|
+
"#endif"
|
1490
|
+
end
|
1491
|
+
end
|
1492
|
+
|
1493
|
+
def separator
|
1494
|
+
"\n\n"
|
1495
|
+
end
|
1496
|
+
|
1497
|
+
class FunctionAccumulator < Accumulator
|
1498
|
+
|
1499
|
+
def add name, kind = Function
|
1500
|
+
@parent.assert_uncommitted
|
1501
|
+
name = name.intern if name.is_a? String
|
1502
|
+
|
1503
|
+
if kind.is_a? Symbol or kind.is_a? String
|
1504
|
+
kind = eval "CGenerator::#{kind}"
|
1505
|
+
end
|
1506
|
+
|
1507
|
+
unless kind <= Function
|
1508
|
+
raise ArgumentError,
|
1509
|
+
"#{kind.class} #{kind} is not a subclass of CGenerator::Function."
|
1510
|
+
end
|
1511
|
+
|
1512
|
+
fn = @pile.find { |f| f.name == name }
|
1513
|
+
unless fn
|
1514
|
+
fn = kind.new name, @parent
|
1515
|
+
super fn
|
1516
|
+
end
|
1517
|
+
fn
|
1518
|
+
end
|
1519
|
+
|
1520
|
+
def separator
|
1521
|
+
"\n\n"
|
1522
|
+
end
|
1523
|
+
|
1524
|
+
end
|
1525
|
+
|
1526
|
+
class IncludeAccumulator < Accumulator
|
1527
|
+
include SetAccumulator
|
1528
|
+
def output_one item
|
1529
|
+
item = item.name unless item.is_a? String
|
1530
|
+
"#include " +
|
1531
|
+
if item =~ /\A<.*>\z/
|
1532
|
+
item
|
1533
|
+
else
|
1534
|
+
'"' + item + '"'
|
1535
|
+
end
|
1536
|
+
end
|
1537
|
+
end
|
1538
|
+
|
1539
|
+
class CommentAccumulator < Accumulator
|
1540
|
+
def to_s
|
1541
|
+
str = super
|
1542
|
+
if str.length > 0
|
1543
|
+
str.gsub(/^(?!\/\/)/, "// ")
|
1544
|
+
else
|
1545
|
+
str
|
1546
|
+
end
|
1547
|
+
end
|
1548
|
+
end
|
1549
|
+
|
1550
|
+
accumulator(:preamble) {CommentAccumulator}
|
1551
|
+
accumulator(:include) {IncludeAccumulator}
|
1552
|
+
accumulator(:declare) {StatementKeyAccumulator}
|
1553
|
+
accumulator(:define) {FunctionAccumulator}
|
1554
|
+
|
1555
|
+
def define_c_function c_name, subclass = Function
|
1556
|
+
define c_name, subclass
|
1557
|
+
end
|
1558
|
+
|
1559
|
+
def define_c_method mod, name, subclass = Method
|
1560
|
+
unless subclass <= Method ## should use assert
|
1561
|
+
raise "#{subclass.name} is not <= Method"
|
1562
|
+
end
|
1563
|
+
c_name = library.rb_define_method :mod => mod, :rb_name => name
|
1564
|
+
define c_name, subclass
|
1565
|
+
end
|
1566
|
+
|
1567
|
+
def define_c_module_function mod, name, subclass = ModuleFunction
|
1568
|
+
raise unless subclass <= ModuleFunction
|
1569
|
+
c_name = library.rb_define_module_function :mod => mod, :rb_name => name
|
1570
|
+
define c_name, subclass
|
1571
|
+
end
|
1572
|
+
|
1573
|
+
def define_c_global_function name, subclass = GlobalFunction
|
1574
|
+
raise unless subclass <= GlobalFunction
|
1575
|
+
c_name = library.rb_define_global_function :rb_name => name
|
1576
|
+
define c_name, subclass
|
1577
|
+
end
|
1578
|
+
|
1579
|
+
def define_c_singleton_method mod, name, subclass = SingletonMethod
|
1580
|
+
raise unless subclass <= SingletonMethod
|
1581
|
+
c_name = library.rb_define_singleton_method :mod => mod, :rb_name => name
|
1582
|
+
define c_name, subclass
|
1583
|
+
end
|
1584
|
+
alias define_c_class_method define_c_singleton_method
|
1585
|
+
|
1586
|
+
# For ruby 1.7/1.8 after 20Dec2002
|
1587
|
+
def define_alloc_func klass
|
1588
|
+
klass_c_name = declare_class klass
|
1589
|
+
c_name = "alloc_func_#{klass_c_name}"
|
1590
|
+
library.init_library_function.body \
|
1591
|
+
%{rb_define_alloc_func(#{klass_c_name}, #{c_name})}
|
1592
|
+
define c_name, Function
|
1593
|
+
end
|
1594
|
+
|
1595
|
+
def declare_struct struct_name, *rest
|
1596
|
+
struct = CGenerator::Structure.new struct_name, self, *rest
|
1597
|
+
declare struct_name => ["\n", struct, ";\n"]
|
1598
|
+
struct
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
def declare_extern_struct struct_name, *rest
|
1602
|
+
@include_file.declare_struct struct_name, *rest
|
1603
|
+
end
|
1604
|
+
|
1605
|
+
alias declare_static declare
|
1606
|
+
|
1607
|
+
def declare_extern(*args)
|
1608
|
+
if @include_file
|
1609
|
+
@include_file.declare(*args)
|
1610
|
+
else
|
1611
|
+
declare(*args)
|
1612
|
+
end
|
1613
|
+
end
|
1614
|
+
|
1615
|
+
def to_s
|
1616
|
+
super + "\n"
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
def file
|
1620
|
+
self
|
1621
|
+
end
|
1622
|
+
|
1623
|
+
end # class CFile
|
1624
|
+
|
1625
|
+
|
1626
|
+
class Prototype < CFragment
|
1627
|
+
|
1628
|
+
class ArgumentAccumulator < Accumulator
|
1629
|
+
include SetAccumulator
|
1630
|
+
def to_s
|
1631
|
+
if @pile.size > 0
|
1632
|
+
"(" + @pile.join(", ") + ")"
|
1633
|
+
else
|
1634
|
+
'(void)'
|
1635
|
+
end
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
def size
|
1639
|
+
@pile.size
|
1640
|
+
end
|
1641
|
+
end
|
1642
|
+
|
1643
|
+
accumulator(:scope,
|
1644
|
+
:return_type) {SingletonAccumulator}
|
1645
|
+
accumulator(:arguments) {ArgumentAccumulator}
|
1646
|
+
|
1647
|
+
def initialize name, parent
|
1648
|
+
super
|
1649
|
+
add scope!, return_type!, " ", name, arguments!
|
1650
|
+
end
|
1651
|
+
|
1652
|
+
def separator; ""; end
|
1653
|
+
|
1654
|
+
def argc
|
1655
|
+
arguments!.size
|
1656
|
+
end
|
1657
|
+
|
1658
|
+
end # class Prototype
|
1659
|
+
|
1660
|
+
class Function < CFragment
|
1661
|
+
|
1662
|
+
def initialize name, parent
|
1663
|
+
super
|
1664
|
+
|
1665
|
+
scope :static
|
1666
|
+
return_type 'void'
|
1667
|
+
|
1668
|
+
add prototype,
|
1669
|
+
block(declare!, init!, setup!, body!, returns!)
|
1670
|
+
end
|
1671
|
+
|
1672
|
+
def empty?
|
1673
|
+
block!.to_s =~ /\A\{\s*\}\z/m
|
1674
|
+
end
|
1675
|
+
|
1676
|
+
def prototype
|
1677
|
+
@prototype ||= Prototype.new(name, self)
|
1678
|
+
end
|
1679
|
+
|
1680
|
+
def scope s
|
1681
|
+
scope_str = s.to_s
|
1682
|
+
unless defined?(@scope) and scope_str == @scope
|
1683
|
+
@scope = scope_str
|
1684
|
+
case scope_str
|
1685
|
+
when "static"
|
1686
|
+
prototype.scope "static " ## this is kludgy
|
1687
|
+
declare_static @name => prototype
|
1688
|
+
declare_extern @name => nil
|
1689
|
+
when "extern"
|
1690
|
+
prototype.scope "" ## would be too much work to do "extern "
|
1691
|
+
declare_extern @name => prototype
|
1692
|
+
declare_static @name => nil
|
1693
|
+
end
|
1694
|
+
end
|
1695
|
+
end
|
1696
|
+
|
1697
|
+
class ReturnAccumulator < SingletonAccumulator
|
1698
|
+
def to_s
|
1699
|
+
if @pile.size > 0
|
1700
|
+
"return #{@pile.join};"
|
1701
|
+
else
|
1702
|
+
""
|
1703
|
+
end
|
1704
|
+
end
|
1705
|
+
end
|
1706
|
+
|
1707
|
+
class InitAccumulator < BlockAccumulator
|
1708
|
+
def add_one_really(*args)
|
1709
|
+
super
|
1710
|
+
@parent.declare :first_time => "static int first_time = 1"
|
1711
|
+
end
|
1712
|
+
|
1713
|
+
def to_s
|
1714
|
+
if @pile.size > 0
|
1715
|
+
["\nif (first_time)", super].join(" ") +
|
1716
|
+
"\nif (first_time) first_time = 0;\n"
|
1717
|
+
else
|
1718
|
+
""
|
1719
|
+
end
|
1720
|
+
end
|
1721
|
+
end
|
1722
|
+
|
1723
|
+
accumulator(:block) {BlockAccumulator}
|
1724
|
+
accumulator(:declare) {StatementKeyAccumulator}
|
1725
|
+
accumulator(:init) {InitAccumulator}
|
1726
|
+
accumulator(:setup) {StatementKeyAccumulator}
|
1727
|
+
accumulator(:body) {StatementAccumulator}
|
1728
|
+
accumulator(:returns) {ReturnAccumulator}
|
1729
|
+
|
1730
|
+
def return_type(*args)
|
1731
|
+
prototype.return_type(*args)
|
1732
|
+
end
|
1733
|
+
|
1734
|
+
def arguments(*args)
|
1735
|
+
prototype.arguments(*args)
|
1736
|
+
end
|
1737
|
+
|
1738
|
+
end # class Function
|
1739
|
+
|
1740
|
+
|
1741
|
+
class MethodPrototype < Prototype
|
1742
|
+
|
1743
|
+
class MethodArgumentAccumulator < ArgumentAccumulator
|
1744
|
+
def add_one item
|
1745
|
+
item = item.to_s
|
1746
|
+
unless item =~ /\AVALUE /
|
1747
|
+
item = "VALUE " + item
|
1748
|
+
end
|
1749
|
+
super
|
1750
|
+
end
|
1751
|
+
def reset
|
1752
|
+
@pile = []
|
1753
|
+
end
|
1754
|
+
end
|
1755
|
+
|
1756
|
+
class RbScanArgsSpec
|
1757
|
+
def initialize bl
|
1758
|
+
@required = @optional = @typecheck = @default = @rest = @block = nil
|
1759
|
+
if bl
|
1760
|
+
instance_eval(&bl)
|
1761
|
+
end
|
1762
|
+
end
|
1763
|
+
|
1764
|
+
def required(*args); @required = args; end
|
1765
|
+
def optional(*args); @optional = args; end
|
1766
|
+
def typecheck(arg); @typecheck = arg; end
|
1767
|
+
def default(arg); @default = arg; end
|
1768
|
+
def rest(arg); @rest = arg; end
|
1769
|
+
def block(arg); @block = arg; end
|
1770
|
+
|
1771
|
+
def get_required; @required; end
|
1772
|
+
def get_optional; @optional; end
|
1773
|
+
def get_typecheck; @typecheck; end
|
1774
|
+
def get_default; @default; end
|
1775
|
+
def get_rest; @rest; end
|
1776
|
+
def get_block; @block; end
|
1777
|
+
end
|
1778
|
+
|
1779
|
+
accumulator(:arguments) {MethodArgumentAccumulator}
|
1780
|
+
|
1781
|
+
def c_array_args(argc_name = 'argc', argv_name = 'argv', &bl)
|
1782
|
+
arguments!.reset
|
1783
|
+
arguments!.add_one_really "int #{argc_name}"
|
1784
|
+
arguments!.add "*#{argv_name}", "self"
|
1785
|
+
@pile.freeze
|
1786
|
+
|
1787
|
+
scan_spec = RbScanArgsSpec.new(bl)
|
1788
|
+
|
1789
|
+
fmt_str = '"'
|
1790
|
+
arg_list = [fmt_str]
|
1791
|
+
|
1792
|
+
required = scan_spec.get_required
|
1793
|
+
count_required = required ? required.size : 0
|
1794
|
+
if count_required > 0
|
1795
|
+
fmt_str << "#{required.size}"
|
1796
|
+
for arg in required
|
1797
|
+
arg_list << arg
|
1798
|
+
declare arg => "VALUE #{arg}"
|
1799
|
+
end
|
1800
|
+
end
|
1801
|
+
|
1802
|
+
optional = scan_spec.get_optional
|
1803
|
+
|
1804
|
+
count_optional = optional ? optional.size : 0
|
1805
|
+
if count_optional > 0
|
1806
|
+
fmt_str << "0" unless count_required > 0
|
1807
|
+
fmt_str << "#{optional.size}"
|
1808
|
+
for arg in optional
|
1809
|
+
arg_list << arg
|
1810
|
+
declare arg => "VALUE #{arg}"
|
1811
|
+
end
|
1812
|
+
end
|
1813
|
+
|
1814
|
+
rest = scan_spec.get_rest
|
1815
|
+
if rest
|
1816
|
+
fmt_str << "*"
|
1817
|
+
arg_list << rest
|
1818
|
+
declare rest => "VALUE #{rest}"
|
1819
|
+
end
|
1820
|
+
|
1821
|
+
block = scan_spec.get_block
|
1822
|
+
if block
|
1823
|
+
fmt_str << "&"
|
1824
|
+
arg_list << block
|
1825
|
+
declare block => "VALUE #{block}"
|
1826
|
+
end
|
1827
|
+
|
1828
|
+
fmt_str << '"'
|
1829
|
+
arg_str = arg_list.join ", &"
|
1830
|
+
|
1831
|
+
unless arg_str == '""'
|
1832
|
+
setup :rb_scan_args => %{
|
1833
|
+
rb_scan_args(#{argc_name}, #{argv_name}, #{arg_str});
|
1834
|
+
}.tabto(0)
|
1835
|
+
|
1836
|
+
typecheck = scan_spec.get_typecheck
|
1837
|
+
if typecheck
|
1838
|
+
for arg, argtype in typecheck
|
1839
|
+
next unless argtype and argtype != Object
|
1840
|
+
## this could be a function call
|
1841
|
+
setup "#{arg} typecheck" => %{\
|
1842
|
+
if (!NIL_P(#{arg}) &&
|
1843
|
+
rb_obj_is_kind_of(#{arg}, #{declare_class argtype}) != Qtrue)
|
1844
|
+
rb_raise(#{declare_class TypeError},
|
1845
|
+
"argument #{arg} declared #{argtype} but passed %s.",
|
1846
|
+
STR2CSTR(rb_funcall(
|
1847
|
+
rb_funcall(#{arg}, #{declare_symbol :class}, 0),
|
1848
|
+
#{declare_symbol :to_s}, 0)));
|
1849
|
+
}.tabto(0)
|
1850
|
+
end
|
1851
|
+
end
|
1852
|
+
|
1853
|
+
default = scan_spec.get_default
|
1854
|
+
if default and default.size > 0
|
1855
|
+
cases =
|
1856
|
+
(0..count_optional-1).map { |i|
|
1857
|
+
"case #{i}:" +
|
1858
|
+
if default[optional[i]]
|
1859
|
+
" #{optional[i]} = #{default[optional[i]]};"
|
1860
|
+
else
|
1861
|
+
""
|
1862
|
+
end
|
1863
|
+
}.join("\n")
|
1864
|
+
|
1865
|
+
setup :rb_scan_args_defaults => %{\
|
1866
|
+
switch (argc - #{count_required}) {\n#{cases}
|
1867
|
+
}
|
1868
|
+
}.tabto(0)
|
1869
|
+
end
|
1870
|
+
end
|
1871
|
+
end
|
1872
|
+
|
1873
|
+
def rb_array_args args_name = 'args'
|
1874
|
+
arguments "#{args_name}"
|
1875
|
+
@pile.freeze
|
1876
|
+
end
|
1877
|
+
|
1878
|
+
end # class MethodPrototype
|
1879
|
+
|
1880
|
+
class RubyFunction < Function
|
1881
|
+
|
1882
|
+
def initialize name, parent
|
1883
|
+
super
|
1884
|
+
return_type 'VALUE'
|
1885
|
+
arguments 'self'
|
1886
|
+
returns 'Qnil'
|
1887
|
+
end
|
1888
|
+
|
1889
|
+
def prototype
|
1890
|
+
@prototype ||= MethodPrototype.new(name, self)
|
1891
|
+
end
|
1892
|
+
|
1893
|
+
def c_array_args(*args, &bl)
|
1894
|
+
prototype.c_array_args(*args, &bl)
|
1895
|
+
register_args :c_name => @name, :argc => -1 # code used by Ruby C API
|
1896
|
+
end
|
1897
|
+
|
1898
|
+
def rb_array_args(*args, &bl)
|
1899
|
+
prototype.rb_array_args(*args, &bl)
|
1900
|
+
register_args :c_name => @name, :argc => -2 # code used by Ruby C API
|
1901
|
+
end
|
1902
|
+
|
1903
|
+
def arguments(*args, &bl)
|
1904
|
+
prototype.arguments(*args, &bl)
|
1905
|
+
register_args :c_name => @name, :argc => prototype.argc - 1
|
1906
|
+
end
|
1907
|
+
|
1908
|
+
end
|
1909
|
+
|
1910
|
+
|
1911
|
+
class Method < RubyFunction
|
1912
|
+
def register_args(*args)
|
1913
|
+
rb_define_method(*args)
|
1914
|
+
end
|
1915
|
+
end
|
1916
|
+
|
1917
|
+
class ModuleFunction < RubyFunction
|
1918
|
+
def register_args(*args)
|
1919
|
+
rb_define_module_function(*args)
|
1920
|
+
end
|
1921
|
+
end
|
1922
|
+
|
1923
|
+
class GlobalFunction < RubyFunction
|
1924
|
+
def register_args(*args)
|
1925
|
+
rb_define_global_function(*args)
|
1926
|
+
end
|
1927
|
+
end
|
1928
|
+
|
1929
|
+
class SingletonMethod < RubyFunction
|
1930
|
+
def register_args(*args)
|
1931
|
+
rb_define_singleton_method(*args)
|
1932
|
+
end
|
1933
|
+
end
|
1934
|
+
|
1935
|
+
|
1936
|
+
class Structure < CFragment
|
1937
|
+
|
1938
|
+
class InheritAccumulator < Accumulator; include SetAccumulator; end
|
1939
|
+
|
1940
|
+
accumulator(:block) {BlockAccumulator}
|
1941
|
+
accumulator(:inherit) {InheritAccumulator}
|
1942
|
+
accumulator(:declare) {StatementKeyAccumulator}
|
1943
|
+
|
1944
|
+
def initialize name, parent, attribute = nil
|
1945
|
+
super(name, parent)
|
1946
|
+
if attribute
|
1947
|
+
add "typedef struct #{name}", block!, "#{attribute} #{name}"
|
1948
|
+
else
|
1949
|
+
add "typedef struct #{name}", block!, name
|
1950
|
+
end
|
1951
|
+
block inherit!, declare!
|
1952
|
+
end
|
1953
|
+
|
1954
|
+
def separator; " "; end
|
1955
|
+
|
1956
|
+
end # class Structure
|
1957
|
+
|
1958
|
+
|
1959
|
+
OpName= {
|
1960
|
+
'<' => :op_lt,
|
1961
|
+
'<=' => :op_le,
|
1962
|
+
'>' => :op_gt,
|
1963
|
+
'>=' => :op_ge,
|
1964
|
+
'==' => :op_eqeq
|
1965
|
+
}
|
1966
|
+
|
1967
|
+
def CGenerator.make_c_name s
|
1968
|
+
s = s.to_s
|
1969
|
+
OpName[s] || translate_ruby_identifier(s)
|
1970
|
+
end
|
1971
|
+
|
1972
|
+
def CGenerator.translate_ruby_identifier(s)
|
1973
|
+
# For uniqueness, we use a single '_' to indicate our subs
|
1974
|
+
# and translate pre-existing '_' to '__'
|
1975
|
+
# It should be possible to write another method which
|
1976
|
+
# converts the output back to the original.
|
1977
|
+
c_name = s.gsub(/_/, '__')
|
1978
|
+
|
1979
|
+
|
1980
|
+
# Ruby identifiers can include prefix $, @, or @@, or suffix ?, !, or =
|
1981
|
+
# and they can be [] or []=
|
1982
|
+
c_name.gsub!(/\$/, 'global_')
|
1983
|
+
c_name.gsub!(/@/, 'attr_')
|
1984
|
+
c_name.gsub!(/\?/, '_query')
|
1985
|
+
c_name.gsub!(/!/, '_bang')
|
1986
|
+
c_name.gsub!(/=/, '_equals')
|
1987
|
+
c_name.gsub!(/::/, '_')
|
1988
|
+
c_name.gsub!(/\[\]/, '_brackets')
|
1989
|
+
|
1990
|
+
# so that some Ruby expressions can be associated with a name,
|
1991
|
+
# we allow '.' in the str. Eventually, handle more Ruby exprs.
|
1992
|
+
c_name.gsub!(/\./, '_dot_')
|
1993
|
+
|
1994
|
+
# we should also make an attempt to encode special globals
|
1995
|
+
# like $: and $-I
|
1996
|
+
|
1997
|
+
unless c_name =~ /\A[A-Za-z_]\w*\z/
|
1998
|
+
raise SyntaxError,
|
1999
|
+
"Cgen's encoding cannot handle #{s.inspect}; " +
|
2000
|
+
"best try is #{c_name.inspect}."
|
2001
|
+
end
|
2002
|
+
|
2003
|
+
c_name.intern
|
2004
|
+
end
|
2005
|
+
|
2006
|
+
end # module CGenerator
|
2007
|
+
|
2008
|
+
|
2009
|
+
##class Array
|
2010
|
+
## def join_nonempty str
|
2011
|
+
## map { |x|. x.to_s }.reject { |s| s == "" }.join(str)
|
2012
|
+
## end
|
2013
|
+
##end
|
2014
|
+
|
2015
|
+
class String
|
2016
|
+
|
2017
|
+
# tabs left or right by n chars, using spaces
|
2018
|
+
def tab n
|
2019
|
+
if n >= 0
|
2020
|
+
gsub(/^/, ' ' * n)
|
2021
|
+
else
|
2022
|
+
gsub(/^ {0,#{-n}}/, "")
|
2023
|
+
end
|
2024
|
+
end
|
2025
|
+
|
2026
|
+
# preserves relative tabbing
|
2027
|
+
# the first non-empty line ends up with n spaces before nonspace
|
2028
|
+
def tabto n
|
2029
|
+
if self =~ /^( *)\S/
|
2030
|
+
tab(n - $1.length)
|
2031
|
+
else
|
2032
|
+
self
|
2033
|
+
end
|
2034
|
+
end
|
2035
|
+
|
2036
|
+
# aligns each line
|
2037
|
+
def taballto n
|
2038
|
+
gsub(/^ */, ' ' * n)
|
2039
|
+
end
|
2040
|
+
|
2041
|
+
end # class String
|