mall 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/mall/mall.c ADDED
@@ -0,0 +1,301 @@
1
+ #include <ruby.h>
2
+ #include <malloc.h>
3
+ #include <stdio.h>
4
+
5
+
6
+
7
+ static VALUE sym_arena;
8
+
9
+ static VALUE sym_ordblks;
10
+
11
+ static VALUE sym_smblks;
12
+
13
+ static VALUE sym_hblks;
14
+
15
+ static VALUE sym_hblkhd;
16
+
17
+ static VALUE sym_usmblks;
18
+
19
+ static VALUE sym_fsmblks;
20
+
21
+ static VALUE sym_uordblks;
22
+
23
+ static VALUE sym_fordblks;
24
+
25
+ static VALUE sym_keepcost;
26
+
27
+
28
+ /*
29
+ * call-seq:
30
+ * Mall.info -> hash
31
+ *
32
+ * Returns a hash with the following keys:
33
+ *
34
+ * :arena - bytes allocated via sbrk() (and not mmap())
35
+ * :ordblks - number of free (unused) chunks
36
+ * :smblks - number of fastbin blocks[1]
37
+ * :hblks - number of allocated mmap()-ed regions
38
+ * :hblkhd - bytes allocated in mmap()-ed regions
39
+ * :usmblks - maximum total allocated space[1]
40
+ * :fsmblks - space available in freed fastbin blocks[1]
41
+ * :uordblks - total allocated space in use
42
+ * :fordblks - total free space
43
+ * :keepcost - top-most, releasable (via malloc_trim) space
44
+ *
45
+ * All values are limited to 32-bit integers. This uses the limited
46
+ * mallinfo(3) function, consider using Mall.xml and parsing its output
47
+ * if you are using glibc (2.10+) with malloc_info(3)
48
+ *
49
+ * See also:
50
+ * http:// gnu.org/software/libc/manual/html_node/Statistics-of-Malloc.html
51
+ *
52
+ * [1] - this key is unused by glibc (ptmalloc2)
53
+ */
54
+ static VALUE info(VALUE klass)
55
+ {
56
+ VALUE rv = rb_hash_new();
57
+ struct mallinfo stats = mallinfo(); /* whee aggregate returns :( */
58
+
59
+ #define MALLINFO_SET(KEY) \
60
+ rb_hash_aset(rv, sym_##KEY, INT2FIX(stats.KEY))
61
+
62
+ MALLINFO_SET(arena);
63
+ MALLINFO_SET(ordblks);
64
+ MALLINFO_SET(smblks);
65
+ MALLINFO_SET(hblks);
66
+ MALLINFO_SET(hblkhd);
67
+ MALLINFO_SET(usmblks);
68
+ MALLINFO_SET(fsmblks);
69
+ MALLINFO_SET(uordblks);
70
+ MALLINFO_SET(fordblks);
71
+ MALLINFO_SET(keepcost);
72
+ #undef MALLINFO_SET
73
+ return rv;
74
+ }
75
+
76
+ /*
77
+ * call-seq:
78
+ * Mall.opt(Mall::MMAP_THRESHOLD, 128 * 1024)
79
+ *
80
+ * some malloc implementations may not like mallopt() being called after
81
+ * malloc has been initialized (first call to malloc()). This is not
82
+ * the case with glibc malloc.
83
+ *
84
+ * See also:
85
+ * http://gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html
86
+ */
87
+ static VALUE opt(VALUE klass, VALUE param, VALUE value)
88
+ {
89
+ int rv = mallopt(FIX2INT(param), FIX2INT(value));
90
+
91
+ return rv == 0 ? Qfalse : Qtrue;
92
+ }
93
+
94
+ #ifdef HAVE_MALLOC_TRIM
95
+ /*
96
+ * call-seq:
97
+ * Mall.trim(pad) => true or false
98
+ *
99
+ * Attempt to trim off the top of the heap and release it back to
100
+ * the OS. +pad+ represents the amount of free space (in bytes) to
101
+ * leave unreleased for future allocations.
102
+ *
103
+ * Returns true if memory was released and false if not.
104
+ *
105
+ * This method is glibc-specific.
106
+ */
107
+ static VALUE trim(VALUE klass, VALUE pad)
108
+ {
109
+ unsigned long tmp = NUM2ULONG(pad);
110
+ int rv = malloc_trim((size_t)tmp);
111
+
112
+ return rv == 1 ? Qtrue : Qfalse;
113
+ return Qfalse;
114
+ }
115
+ #endif /* HAVE_MALLOC_TRIM */
116
+
117
+ #ifdef HAVE_MALLOC_STATS
118
+ /*
119
+ * call-seq:
120
+ * Mall.dump_stats
121
+ *
122
+ * Dump malloc stats to STDERR
123
+ *
124
+ * This calls malloc_stats() internally, a function that is glibc-specific
125
+ */
126
+ static VALUE dump_stats(VALUE klass)
127
+ {
128
+ fflush(stderr);
129
+ malloc_stats();
130
+ fflush(stderr);
131
+ return Qnil;
132
+ }
133
+ #endif /* HAVE_MALLOC_STATS */
134
+
135
+ #ifdef HAVE_MALLOC_INFO
136
+ static ID id_ltlt;
137
+ #include <errno.h>
138
+ static void xmlerr(FILE *fp, int err, const char *msg)
139
+ {
140
+ fclose(fp);
141
+ errno = err ? err : EIO; /* gotta have something */
142
+ rb_sys_fail(msg);
143
+ }
144
+
145
+ /*
146
+ * call-seq:
147
+ * Mall.xml -> XML string
148
+ * Mall.xml(options = 0, io = $stderr) -> io
149
+ *
150
+ * Called with no arguments, this returns an XML string suitable for
151
+ * parsing with your favorite XML parser.
152
+ *
153
+ * If specified, +options+ must currently be +0+, but is reserved for
154
+ * future expansion.
155
+ *
156
+ * The second optional argument may be any object that responds to "<<"
157
+ * so it may be an IO, Array, StringIO, or String object among other
158
+ * things.
159
+ *
160
+ * This relies on malloc_info(3) which is only in glibc 2.10+
161
+ */
162
+ static VALUE xml(int argc, VALUE *argv, VALUE self)
163
+ {
164
+ int err;
165
+ long len;
166
+ VALUE options, out, buf;
167
+ int xoptions;
168
+ FILE *fp;
169
+
170
+ rb_scan_args(argc, argv, "02", &options, &out);
171
+ xoptions = NIL_P(options) ? 0 : NUM2INT(options);
172
+
173
+ fp = tmpfile();
174
+ if (fp == NULL)
175
+ rb_sys_fail("tmpfile");
176
+
177
+ err = malloc_info(xoptions, fp);
178
+ if (err != 0)
179
+ xmlerr(fp, err, "malloc_info");
180
+
181
+ len = ftell(fp);
182
+ if (len < 0)
183
+ xmlerr(fp, errno, "ftell");
184
+
185
+ rewind(fp);
186
+ buf = rb_str_new(0, len);
187
+ if (fread(RSTRING_PTR(buf), 1, len, fp) != (size_t)len)
188
+ xmlerr(fp, ferror(fp), "fread");
189
+ fclose(fp);
190
+
191
+ if (NIL_P(out))
192
+ return buf;
193
+ return rb_funcall(out, id_ltlt, 1, buf);
194
+ }
195
+ #endif /* HAVE_MALLOC_INFO */
196
+
197
+ /*
198
+ * Mall is a single module with several singleton methods, most of which
199
+ * are glibc-specific. All constants may be used as the first argument
200
+ * to Mall.opt.
201
+ */
202
+ void Init_mall(void)
203
+ {
204
+ VALUE mMall = rb_define_module("Mall");
205
+ rb_define_singleton_method(mMall, "opt", opt, 2);
206
+ rb_define_singleton_method(mMall, "info", info, 0);
207
+ #ifdef HAVE_MALLOC_TRIM
208
+ rb_define_singleton_method(mMall, "trim", trim, 1);
209
+ #endif /* HAVE_MALLOC_TRIM */
210
+ #ifdef HAVE_MALLOC_STATS
211
+ rb_define_singleton_method(mMall, "dump_stats", dump_stats, 0);
212
+ #endif /* HAVE_MALLOC_STATS */
213
+ #ifdef HAVE_MALLOC_INFO
214
+ id_ltlt = rb_intern("<<");
215
+ rb_define_singleton_method(mMall, "xml", xml, -1);
216
+ #endif /* HAVE_MALLOC_INFO*/
217
+
218
+
219
+ sym_arena = ID2SYM(rb_intern("arena"));
220
+
221
+ sym_ordblks = ID2SYM(rb_intern("ordblks"));
222
+
223
+ sym_smblks = ID2SYM(rb_intern("smblks"));
224
+
225
+ sym_hblks = ID2SYM(rb_intern("hblks"));
226
+
227
+ sym_hblkhd = ID2SYM(rb_intern("hblkhd"));
228
+
229
+ sym_usmblks = ID2SYM(rb_intern("usmblks"));
230
+
231
+ sym_fsmblks = ID2SYM(rb_intern("fsmblks"));
232
+
233
+ sym_uordblks = ID2SYM(rb_intern("uordblks"));
234
+
235
+ sym_fordblks = ID2SYM(rb_intern("fordblks"));
236
+
237
+ sym_keepcost = ID2SYM(rb_intern("keepcost"));
238
+
239
+
240
+
241
+ #ifdef M_MXFAST
242
+ /* max request size for "fastbins" */
243
+ rb_define_const(mMall, "MXFAST", INT2FIX(M_MXFAST));
244
+ #endif
245
+
246
+ #ifdef M_NLBLKS
247
+ /* unused in glibc */
248
+ rb_define_const(mMall, "NLBLKS", INT2FIX(M_NLBLKS));
249
+ #endif
250
+
251
+ #ifdef M_GRAIN
252
+ /* unused in glibc */
253
+ rb_define_const(mMall, "GRAIN", INT2FIX(M_GRAIN));
254
+ #endif
255
+
256
+ #ifdef M_KEEP
257
+ /* unused in glibc */
258
+ rb_define_const(mMall, "KEEP", INT2FIX(M_KEEP));
259
+ #endif
260
+
261
+ #ifdef M_TRIM_THRESHOLD
262
+ /* maximum amount of unused memory at the top of the heapto keep before releasing it back to the kernel */
263
+ rb_define_const(mMall, "TRIM_THRESHOLD", INT2FIX(M_TRIM_THRESHOLD));
264
+ #endif
265
+
266
+ #ifdef M_TOP_PAD
267
+ /* amount of extra space to allocate when allocating from the heap */
268
+ rb_define_const(mMall, "TOP_PAD", INT2FIX(M_TOP_PAD));
269
+ #endif
270
+
271
+ #ifdef M_MMAP_THRESHOLD
272
+ /* the request size threshold for using mmap() (instead of sbrk()) */
273
+ rb_define_const(mMall, "MMAP_THRESHOLD", INT2FIX(M_MMAP_THRESHOLD));
274
+ #endif
275
+
276
+ #ifdef M_MMAP_MAX
277
+ /* the maximum number of active mmap() requests in use at once */
278
+ rb_define_const(mMall, "MMAP_MAX", INT2FIX(M_MMAP_MAX));
279
+ #endif
280
+
281
+ #ifdef M_CHECK_ACTION
282
+ /* bitmask value used for debug message output (glibc) */
283
+ rb_define_const(mMall, "CHECK_ACTION", INT2FIX(M_CHECK_ACTION));
284
+ #endif
285
+
286
+ #ifdef M_PERTURB
287
+ /* perturb memory allocations with a given byte (for debugging) (glibc) */
288
+ rb_define_const(mMall, "PERTURB", INT2FIX(M_PERTURB));
289
+ #endif
290
+
291
+ #ifdef M_ARENA_TEST
292
+ /* initial number of arenas to allocate (glibc 2.10+) */
293
+ rb_define_const(mMall, "ARENA_TEST", INT2FIX(M_ARENA_TEST));
294
+ #endif
295
+
296
+ #ifdef M_ARENA_MAX
297
+ /* maximum number of arenas to allocate (glibc 2.10+) */
298
+ rb_define_const(mMall, "ARENA_MAX", INT2FIX(M_ARENA_MAX));
299
+ #endif
300
+
301
+ }
@@ -0,0 +1,246 @@
1
+ #include <ruby.h>
2
+ #include <malloc.h>
3
+ #include <stdio.h>
4
+ <%
5
+ mallinfo_keys = %w(
6
+ arena
7
+ ordblks
8
+ smblks
9
+ hblks
10
+ hblkhd
11
+ usmblks
12
+ fsmblks
13
+ uordblks
14
+ fordblks
15
+ keepcost
16
+ ) %>
17
+
18
+ <% mallinfo_keys.each { |x| %>
19
+ static VALUE sym_<%= x %>;
20
+ <% } %>
21
+
22
+ /*
23
+ * call-seq:
24
+ * Mall.info -> hash
25
+ *
26
+ * Returns a hash with the following keys:
27
+ *
28
+ * :arena - bytes allocated via sbrk() (and not mmap())
29
+ * :ordblks - number of free (unused) chunks
30
+ * :smblks - number of fastbin blocks[1]
31
+ * :hblks - number of allocated mmap()-ed regions
32
+ * :hblkhd - bytes allocated in mmap()-ed regions
33
+ * :usmblks - maximum total allocated space[1]
34
+ * :fsmblks - space available in freed fastbin blocks[1]
35
+ * :uordblks - total allocated space in use
36
+ * :fordblks - total free space
37
+ * :keepcost - top-most, releasable (via malloc_trim) space
38
+ *
39
+ * All values are limited to 32-bit integers. This uses the limited
40
+ * mallinfo(3) function, consider using Mall.xml and parsing its output
41
+ * if you are using glibc (2.10+) with malloc_info(3)
42
+ *
43
+ * See also:
44
+ * http:// gnu.org/software/libc/manual/html_node/Statistics-of-Malloc.html
45
+ *
46
+ * [1] - this key is unused by glibc (ptmalloc2)
47
+ */
48
+ static VALUE info(VALUE klass)
49
+ {
50
+ VALUE rv = rb_hash_new();
51
+ struct mallinfo stats = mallinfo(); /* whee aggregate returns :( */
52
+
53
+ #define MALLINFO_SET(KEY) \
54
+ rb_hash_aset(rv, sym_##KEY, INT2FIX(stats.KEY))
55
+
56
+ MALLINFO_SET(arena);
57
+ MALLINFO_SET(ordblks);
58
+ MALLINFO_SET(smblks);
59
+ MALLINFO_SET(hblks);
60
+ MALLINFO_SET(hblkhd);
61
+ MALLINFO_SET(usmblks);
62
+ MALLINFO_SET(fsmblks);
63
+ MALLINFO_SET(uordblks);
64
+ MALLINFO_SET(fordblks);
65
+ MALLINFO_SET(keepcost);
66
+ #undef MALLINFO_SET
67
+ return rv;
68
+ }
69
+
70
+ /*
71
+ * call-seq:
72
+ * Mall.opt(Mall::MMAP_THRESHOLD, 128 * 1024)
73
+ *
74
+ * some malloc implementations may not like mallopt() being called after
75
+ * malloc has been initialized (first call to malloc()). This is not
76
+ * the case with glibc malloc.
77
+ *
78
+ * See also:
79
+ * http://gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html
80
+ */
81
+ static VALUE opt(VALUE klass, VALUE param, VALUE value)
82
+ {
83
+ int rv = mallopt(FIX2INT(param), FIX2INT(value));
84
+
85
+ return rv == 0 ? Qfalse : Qtrue;
86
+ }
87
+
88
+ #ifdef HAVE_MALLOC_TRIM
89
+ /*
90
+ * call-seq:
91
+ * Mall.trim(pad) => true or false
92
+ *
93
+ * Attempt to trim off the top of the heap and release it back to
94
+ * the OS. +pad+ represents the amount of free space (in bytes) to
95
+ * leave unreleased for future allocations.
96
+ *
97
+ * Returns true if memory was released and false if not.
98
+ *
99
+ * This method is glibc-specific.
100
+ */
101
+ static VALUE trim(VALUE klass, VALUE pad)
102
+ {
103
+ unsigned long tmp = NUM2ULONG(pad);
104
+ int rv = malloc_trim((size_t)tmp);
105
+
106
+ return rv == 1 ? Qtrue : Qfalse;
107
+ return Qfalse;
108
+ }
109
+ #endif /* HAVE_MALLOC_TRIM */
110
+
111
+ #ifdef HAVE_MALLOC_STATS
112
+ /*
113
+ * call-seq:
114
+ * Mall.dump_stats
115
+ *
116
+ * Dump malloc stats to STDERR
117
+ *
118
+ * This calls malloc_stats() internally, a function that is glibc-specific
119
+ */
120
+ static VALUE dump_stats(VALUE klass)
121
+ {
122
+ fflush(stderr);
123
+ malloc_stats();
124
+ fflush(stderr);
125
+ return Qnil;
126
+ }
127
+ #endif /* HAVE_MALLOC_STATS */
128
+
129
+ #ifdef HAVE_MALLOC_INFO
130
+ static ID id_ltlt;
131
+ #include <errno.h>
132
+ static void xmlerr(FILE *fp, int err, const char *msg)
133
+ {
134
+ fclose(fp);
135
+ errno = err ? err : EIO; /* gotta have something */
136
+ rb_sys_fail(msg);
137
+ }
138
+
139
+ /*
140
+ * call-seq:
141
+ * Mall.xml -> XML string
142
+ * Mall.xml(options = 0, io = $stderr) -> io
143
+ *
144
+ * Called with no arguments, this returns an XML string suitable for
145
+ * parsing with your favorite XML parser.
146
+ *
147
+ * If specified, +options+ must currently be +0+, but is reserved for
148
+ * future expansion.
149
+ *
150
+ * The second optional argument may be any object that responds to "<<"
151
+ * so it may be an IO, Array, StringIO, or String object among other
152
+ * things.
153
+ *
154
+ * This relies on malloc_info(3) which is only in glibc 2.10+
155
+ */
156
+ static VALUE xml(int argc, VALUE *argv, VALUE self)
157
+ {
158
+ int err;
159
+ long len;
160
+ VALUE options, out, buf;
161
+ int xoptions;
162
+ FILE *fp;
163
+
164
+ rb_scan_args(argc, argv, "02", &options, &out);
165
+ xoptions = NIL_P(options) ? 0 : NUM2INT(options);
166
+
167
+ fp = tmpfile();
168
+ if (fp == NULL)
169
+ rb_sys_fail("tmpfile");
170
+
171
+ err = malloc_info(xoptions, fp);
172
+ if (err != 0)
173
+ xmlerr(fp, err, "malloc_info");
174
+
175
+ len = ftell(fp);
176
+ if (len < 0)
177
+ xmlerr(fp, errno, "ftell");
178
+
179
+ rewind(fp);
180
+ buf = rb_str_new(0, len);
181
+ if (fread(RSTRING_PTR(buf), 1, len, fp) != (size_t)len)
182
+ xmlerr(fp, ferror(fp), "fread");
183
+ fclose(fp);
184
+
185
+ if (NIL_P(out))
186
+ return buf;
187
+ return rb_funcall(out, id_ltlt, 1, buf);
188
+ }
189
+ #endif /* HAVE_MALLOC_INFO */
190
+
191
+ /*
192
+ * Mall is a single module with several singleton methods, most of which
193
+ * are glibc-specific. All constants may be used as the first argument
194
+ * to Mall.opt.
195
+ */
196
+ void Init_mall(void)
197
+ {
198
+ VALUE mMall = rb_define_module("Mall");
199
+ rb_define_singleton_method(mMall, "opt", opt, 2);
200
+ rb_define_singleton_method(mMall, "info", info, 0);
201
+ #ifdef HAVE_MALLOC_TRIM
202
+ rb_define_singleton_method(mMall, "trim", trim, 1);
203
+ #endif /* HAVE_MALLOC_TRIM */
204
+ #ifdef HAVE_MALLOC_STATS
205
+ rb_define_singleton_method(mMall, "dump_stats", dump_stats, 0);
206
+ #endif /* HAVE_MALLOC_STATS */
207
+ #ifdef HAVE_MALLOC_INFO
208
+ id_ltlt = rb_intern("<<");
209
+ rb_define_singleton_method(mMall, "xml", xml, -1);
210
+ #endif /* HAVE_MALLOC_INFO*/
211
+
212
+ <% mallinfo_keys.each { |x| %>
213
+ sym_<%= x %> = ID2SYM(rb_intern("<%= x %>"));
214
+ <% } %>
215
+
216
+ <%
217
+ {
218
+ :mxfast => 'max request size for "fastbins"',
219
+ :nlblks => 'unused in glibc',
220
+ :grain => 'unused in glibc',
221
+ :keep => 'unused in glibc',
222
+ :trim_threshold =>
223
+ 'maximum amount of unused memory at the top of the heap' \
224
+ 'to keep before releasing it back to the kernel',
225
+ :top_pad =>
226
+ 'amount of extra space to allocate when allocating from the heap',
227
+ :mmap_threshold =>
228
+ 'the request size threshold for using mmap() (instead of sbrk())',
229
+ :mmap_max =>
230
+ 'the maximum number of active mmap() requests in use at once',
231
+ :check_action =>
232
+ 'bitmask value used for debug message output (glibc)',
233
+ :perturb =>
234
+ 'perturb memory allocations with a given byte (for debugging) (glibc)',
235
+ :arena_test => 'initial number of arenas to allocate (glibc 2.10+)',
236
+ :arena_max => 'maximum number of arenas to allocate (glibc 2.10+)',
237
+ }.each { |opt, doc|
238
+ opt = opt.to_s.upcase!
239
+ m_opt = "M_#{opt}"
240
+ %>
241
+ #ifdef <%= m_opt %>
242
+ /* <%= doc %> */
243
+ rb_define_const(mMall, "<%= opt %>", INT2FIX(<%= m_opt %>));
244
+ #endif
245
+ <% } %>
246
+ }
data/mall.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ manifest = File.exist?('.manifest') ?
2
+ IO.readlines('.manifest').map!(&:chomp!) : `git ls-files`.split("\n")
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = %q{mall}
6
+ s.version = (ENV["VERSION"] || '1.0.3').dup
7
+ s.authors = ["#{s.name} hackers (mall@yhbt.net)", "Ivan Prisyazhnyy"]
8
+ s.description = File.read('README').split("\n\n")[1] + "\n\n" +
9
+ "1.0.3 fixes minor issues to be compatible with gem install and rake."
10
+ s.email = ["john.koepi@gmail.com", "mall@yhbt.net"]
11
+ s.extra_rdoc_files = IO.readlines('.document').map!(&:chomp!).keep_if do |f|
12
+ File.exist?(f)
13
+ end
14
+ s.require_paths = %w(ext)
15
+ s.files = manifest
16
+ s.homepage = 'https://github.com/sitano/mall'
17
+ s.summary = 'access malloc tuning/reporting functions + glibc extras. linux only.'
18
+ s.test_files = Dir["test/test_*.rb"]
19
+ s.extensions = %w(ext/mall/extconf.rb)
20
+ s.licenses = ["LGPL"]
21
+ end
data/pkg.mk ADDED
@@ -0,0 +1,150 @@
1
+ RUBY = ruby
2
+ RAKE = rake
3
+ RSYNC = rsync
4
+ OLDDOC = olddoc
5
+ RDOC = rdoc
6
+
7
+ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
8
+ @./GIT-VERSION-GEN
9
+ -include GIT-VERSION-FILE
10
+ -include local.mk
11
+ DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts RbConfig::CONFIG["DLEXT"]')
12
+ RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
13
+ RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
14
+ lib := lib
15
+
16
+ ext := $(firstword $(wildcard ext/*))
17
+ ifneq ($(ext),)
18
+ ext_pfx := tmp/ext/$(RUBY_ENGINE)-$(RUBY_VERSION)
19
+ ext_h := $(wildcard $(ext)/*/*.h $(ext)/*.h)
20
+ ext_src := $(wildcard $(ext)/*.c $(ext_h))
21
+ ext_pfx_src := $(addprefix $(ext_pfx)/,$(ext_src))
22
+ ext_d := $(ext_pfx)/$(ext)/.d
23
+ $(ext)/extconf.rb: $(wildcard $(ext)/*.h)
24
+ @>> $@
25
+ $(ext_d):
26
+ @mkdir -p $(@D)
27
+ @> $@
28
+ $(ext_pfx)/$(ext)/%: $(ext)/% $(ext_d)
29
+ install -m 644 $< $@
30
+ $(ext_pfx)/$(ext)/Makefile: $(ext)/extconf.rb $(ext_d) $(ext_h)
31
+ $(RM) -f $(@D)/*.o
32
+ cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb $(EXTCONF_ARGS)
33
+ ext_sfx := _ext.$(DLEXT)
34
+ ext_dl := $(ext_pfx)/$(ext)/$(notdir $(ext)_ext.$(DLEXT))
35
+ $(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
36
+ @echo $^ == $@
37
+ $(MAKE) -C $(@D)
38
+ lib := $(lib):$(ext_pfx)/$(ext)
39
+ build: $(ext_dl)
40
+ else
41
+ build:
42
+ endif
43
+
44
+ pkg_extra += GIT-VERSION-FILE NEWS LATEST
45
+ NEWS: GIT-VERSION-FILE .olddoc.yml
46
+ $(OLDDOC) prepare
47
+ LATEST: NEWS
48
+
49
+ manifest:
50
+ $(RM) .manifest
51
+ $(MAKE) .manifest
52
+
53
+ .manifest: $(pkg_extra)
54
+ (git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
55
+ LC_ALL=C sort > $@+
56
+ cmp $@+ $@ || mv $@+ $@
57
+ $(RM) $@+
58
+
59
+ doc:: .document .olddoc.yml $(pkg_extra) $(PLACEHOLDERS)
60
+ -find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
61
+ -find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
62
+ $(RM) -r doc
63
+ $(RDOC) -f dark216
64
+ $(OLDDOC) merge
65
+ install -m644 COPYING doc/COPYING
66
+ install -m644 NEWS doc/NEWS
67
+ install -m644 NEWS.atom.xml doc/NEWS.atom.xml
68
+ install -m644 $(shell LC_ALL=C grep '^[A-Z]' .document) doc/
69
+
70
+ ifneq ($(VERSION),)
71
+ pkggem := pkg/$(rfpackage)-$(VERSION).gem
72
+ pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
73
+
74
+ # ensures we're actually on the tagged $(VERSION), only used for release
75
+ verify:
76
+ test x"$(shell umask)" = x0022
77
+ git rev-parse --verify refs/tags/v$(VERSION)^{}
78
+ git diff-index --quiet HEAD^0
79
+ test $$(git rev-parse --verify HEAD^0) = \
80
+ $$(git rev-parse --verify refs/tags/v$(VERSION)^{})
81
+
82
+ fix-perms:
83
+ -git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
84
+ -git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
85
+
86
+ gem: $(pkggem)
87
+
88
+ install-gem: $(pkggem)
89
+ gem install --local $(CURDIR)/$<
90
+
91
+ $(pkggem): manifest fix-perms
92
+ gem build $(rfpackage).gemspec
93
+ mkdir -p pkg
94
+ mv $(@F) $@
95
+
96
+ $(pkgtgz): distdir = $(basename $@)
97
+ $(pkgtgz): HEAD = v$(VERSION)
98
+ $(pkgtgz): manifest fix-perms
99
+ @test -n "$(distdir)"
100
+ $(RM) -r $(distdir)
101
+ mkdir -p $(distdir)
102
+ tar cf - $$(cat .manifest) | (cd $(distdir) && tar xf -)
103
+ cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
104
+ mv $@+ $@
105
+
106
+ package: $(pkgtgz) $(pkggem)
107
+
108
+ release:: verify package
109
+ # push gem to RubyGems.org
110
+ gem push $(pkggem)
111
+ else
112
+ gem install-gem: GIT-VERSION-FILE
113
+ $(MAKE) $@ VERSION=$(GIT_VERSION)
114
+ endif
115
+
116
+ all:: check
117
+ test_units := $(wildcard test/test_*.rb)
118
+ test: check
119
+ check: test-unit
120
+ test-unit: $(test_units)
121
+ $(test_units): build
122
+ $(VALGRIND) $(RUBY) -w -I $(lib) $@ $(RUBY_TEST_OPTS)
123
+
124
+ # this requires GNU coreutils variants
125
+ ifneq ($(RSYNC_DEST),)
126
+ publish_doc:
127
+ -git set-file-times
128
+ $(MAKE) doc
129
+ $(MAKE) doc_gz
130
+ $(RSYNC) -av doc/ $(RSYNC_DEST)/
131
+ git ls-files | xargs touch
132
+ endif
133
+
134
+ # Create gzip variants of the same timestamp as the original so nginx
135
+ # "gzip_static on" can serve the gzipped versions directly.
136
+ doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.gz$$')
137
+ doc_gz:
138
+ for i in $(docs); do \
139
+ gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
140
+ check-warnings:
141
+ @(for i in $$(git ls-files '*.rb'| grep -v '^setup\.rb$$'); \
142
+ do $(RUBY) -d -W2 -c $$i; done) | grep -v '^Syntax OK$$' || :
143
+
144
+ ifneq ($(PLACEHOLDERS),)
145
+ $(PLACEHOLDERS):
146
+ echo olddoc_placeholder > $@
147
+ endif
148
+
149
+ .PHONY: all .FORCE-GIT-VERSION-FILE doc check test $(test_units) manifest
150
+ .PHONY: check-warnings