mkmfmf 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/lib/mkmfmf.rb ADDED
@@ -0,0 +1,2112 @@
1
+ # -*- indent-tabs-mode: t -*-
2
+ # module to create Makefile for extension modules
3
+ # invoke like: ruby -r mkmf extconf.rb
4
+
5
+ require 'rbconfig'
6
+ require 'fileutils'
7
+ require 'shellwords'
8
+
9
+ CONFIG = RbConfig::MAKEFILE_CONFIG
10
+ CONFIG['CC'] = ENV['CC'] if ENV['CC']
11
+ ORIG_LIBPATH = ENV['LIB']
12
+
13
+ CXX_EXT = %w[cc cxx cpp]
14
+ if File::FNM_SYSCASE.zero?
15
+ CXX_EXT.concat(%w[C])
16
+ end
17
+ SRC_EXT = %w[c m].concat(CXX_EXT)
18
+ $static = nil
19
+ $config_h = '$(arch_hdrdir)/ruby/config.h'
20
+ $default_static = $static
21
+
22
+ unless defined? $configure_args
23
+ $configure_args = {}
24
+ args = CONFIG["configure_args"]
25
+ if ENV["CONFIGURE_ARGS"]
26
+ args << " " << ENV["CONFIGURE_ARGS"]
27
+ end
28
+ for arg in Shellwords::shellwords(args)
29
+ arg, val = arg.split('=', 2)
30
+ next unless arg
31
+ arg.tr!('_', '-')
32
+ if arg.sub!(/^(?!--)/, '--')
33
+ val or next
34
+ arg.downcase!
35
+ end
36
+ next if /^--(?:top|topsrc|src|cur)dir$/ =~ arg
37
+ $configure_args[arg] = val || true
38
+ end
39
+ for arg in ARGV
40
+ arg, val = arg.split('=', 2)
41
+ next unless arg
42
+ arg.tr!('_', '-')
43
+ if arg.sub!(/^(?!--)/, '--')
44
+ val or next
45
+ arg.downcase!
46
+ end
47
+ $configure_args[arg] = val || true
48
+ end
49
+ end
50
+
51
+ $libdir = CONFIG["libdir"]
52
+ $rubylibdir = CONFIG["rubylibdir"]
53
+ $archdir = CONFIG["archdir"]
54
+ $sitedir = CONFIG["sitedir"]
55
+ $sitelibdir = CONFIG["sitelibdir"]
56
+ $sitearchdir = CONFIG["sitearchdir"]
57
+ $vendordir = CONFIG["vendordir"]
58
+ $vendorlibdir = CONFIG["vendorlibdir"]
59
+ $vendorarchdir = CONFIG["vendorarchdir"]
60
+
61
+ $mswin = /mswin/ =~ RUBY_PLATFORM
62
+ $bccwin = /bccwin/ =~ RUBY_PLATFORM
63
+ $mingw = /mingw/ =~ RUBY_PLATFORM
64
+ $cygwin = /cygwin/ =~ RUBY_PLATFORM
65
+ $netbsd = /netbsd/ =~ RUBY_PLATFORM
66
+ $os2 = /os2/ =~ RUBY_PLATFORM
67
+ $beos = /beos/ =~ RUBY_PLATFORM
68
+ $haiku = /haiku/ =~ RUBY_PLATFORM
69
+ $solaris = /solaris/ =~ RUBY_PLATFORM
70
+ $universal = /universal/ =~ RUBY_PLATFORM
71
+ $dest_prefix_pattern = (File::PATH_SEPARATOR == ';' ? /\A([[:alpha:]]:)?/ : /\A/)
72
+
73
+ # :stopdoc:
74
+
75
+ def config_string(key, config = CONFIG)
76
+ s = config[key] and !s.empty? and block_given? ? yield(s) : s
77
+ end
78
+
79
+ def dir_re(dir)
80
+ Regexp.new('\$(?:\('+dir+'\)|\{'+dir+'\})(?:\$(?:\(target_prefix\)|\{target_prefix\}))?')
81
+ end
82
+
83
+ def relative_from(path, base)
84
+ dir = File.join(path, "")
85
+ if File.expand_path(dir) == File.expand_path(dir, base)
86
+ path
87
+ else
88
+ File.join(base, path)
89
+ end
90
+ end
91
+
92
+ INSTALL_DIRS = [
93
+ [dir_re('commondir'), "$(RUBYCOMMONDIR)"],
94
+ [dir_re('sitedir'), "$(RUBYCOMMONDIR)"],
95
+ [dir_re('vendordir'), "$(RUBYCOMMONDIR)"],
96
+ [dir_re('rubylibdir'), "$(RUBYLIBDIR)"],
97
+ [dir_re('archdir'), "$(RUBYARCHDIR)"],
98
+ [dir_re('sitelibdir'), "$(RUBYLIBDIR)"],
99
+ [dir_re('vendorlibdir'), "$(RUBYLIBDIR)"],
100
+ [dir_re('sitearchdir'), "$(RUBYARCHDIR)"],
101
+ [dir_re('vendorarchdir'), "$(RUBYARCHDIR)"],
102
+ [dir_re('rubyhdrdir'), "$(RUBYHDRDIR)"],
103
+ [dir_re('sitehdrdir'), "$(SITEHDRDIR)"],
104
+ [dir_re('vendorhdrdir'), "$(VENDORHDRDIR)"],
105
+ [dir_re('bindir'), "$(BINDIR)"],
106
+ ]
107
+
108
+ def install_dirs(target_prefix = nil)
109
+ if $extout
110
+ dirs = [
111
+ ['BINDIR', '$(extout)/bin'],
112
+ ['RUBYCOMMONDIR', '$(extout)/common'],
113
+ ['RUBYLIBDIR', '$(RUBYCOMMONDIR)$(target_prefix)'],
114
+ ['RUBYARCHDIR', '$(extout)/$(arch)$(target_prefix)'],
115
+ ['HDRDIR', '$(extout)/include/ruby$(target_prefix)'],
116
+ ['ARCHHDRDIR', '$(extout)/include/$(arch)/ruby$(target_prefix)'],
117
+ ['extout', "#$extout"],
118
+ ['extout_prefix', "#$extout_prefix"],
119
+ ]
120
+ elsif $extmk
121
+ dirs = [
122
+ ['BINDIR', '$(bindir)'],
123
+ ['RUBYCOMMONDIR', '$(rubylibdir)'],
124
+ ['RUBYLIBDIR', '$(rubylibdir)$(target_prefix)'],
125
+ ['RUBYARCHDIR', '$(archdir)$(target_prefix)'],
126
+ ['HDRDIR', '$(rubyhdrdir)/ruby$(target_prefix)'],
127
+ ['ARCHHDRDIR', '$(rubyhdrdir)/$(arch)/ruby$(target_prefix)'],
128
+ ]
129
+ elsif $configure_args.has_key?('--vendor')
130
+ dirs = [
131
+ ['BINDIR', '$(bindir)'],
132
+ ['RUBYCOMMONDIR', '$(vendordir)$(target_prefix)'],
133
+ ['RUBYLIBDIR', '$(vendorlibdir)$(target_prefix)'],
134
+ ['RUBYARCHDIR', '$(vendorarchdir)$(target_prefix)'],
135
+ ['HDRDIR', '$(rubyhdrdir)/ruby$(target_prefix)'],
136
+ ['ARCHHDRDIR', '$(rubyhdrdir)/$(arch)/ruby$(target_prefix)'],
137
+ ]
138
+ else
139
+ dirs = [
140
+ ['BINDIR', '$(bindir)'],
141
+ ['RUBYCOMMONDIR', '$(sitedir)$(target_prefix)'],
142
+ ['RUBYLIBDIR', '$(sitelibdir)$(target_prefix)'],
143
+ ['RUBYARCHDIR', '$(sitearchdir)$(target_prefix)'],
144
+ ['HDRDIR', '$(rubyhdrdir)/ruby$(target_prefix)'],
145
+ ['ARCHHDRDIR', '$(rubyhdrdir)/$(arch)/ruby$(target_prefix)'],
146
+ ]
147
+ end
148
+ dirs << ['target_prefix', (target_prefix ? "/#{target_prefix}" : "")]
149
+ dirs
150
+ end
151
+
152
+ def map_dir(dir, map = nil)
153
+ map ||= INSTALL_DIRS
154
+ map.inject(dir) {|d, (orig, new)| d.gsub(orig, new)}
155
+ end
156
+
157
+ topdir = File.dirname(libdir = File.dirname(__FILE__))
158
+ extdir = File.expand_path("ext", topdir)
159
+ path = File.expand_path($0)
160
+ $extmk = path[0, topdir.size+1] == topdir+"/"
161
+ $extmk &&= %r"\A(?:ext|enc|tool|test(?:/.+))\z" =~ File.dirname(path[topdir.size+1..-1])
162
+ $extmk &&= true
163
+ if not $extmk and File.exist?(($hdrdir = RbConfig::CONFIG["rubyhdrdir"]) + "/ruby/ruby.h")
164
+ $topdir = $hdrdir
165
+ $top_srcdir = $hdrdir
166
+ $arch_hdrdir = $hdrdir + "/$(arch)"
167
+ elsif File.exist?(($hdrdir = ($top_srcdir ||= topdir) + "/include") + "/ruby.h")
168
+ $topdir ||= RbConfig::CONFIG["topdir"]
169
+ $arch_hdrdir = "$(extout)/include/$(arch)"
170
+ else
171
+ abort "mkmf.rb can't find header files for ruby at #{$hdrdir}/ruby.h"
172
+ end
173
+
174
+ OUTFLAG = CONFIG['OUTFLAG']
175
+ COUTFLAG = CONFIG['COUTFLAG']
176
+ CPPOUTFILE = CONFIG['CPPOUTFILE']
177
+
178
+ CONFTEST_C = "conftest.c".freeze
179
+
180
+ class String
181
+ # Wraps a string in escaped quotes if it contains whitespace.
182
+ def quote
183
+ /\s/ =~ self ? "\"#{self}\"" : "#{self}"
184
+ end
185
+
186
+ # Generates a string used as cpp macro name.
187
+ def tr_cpp
188
+ strip.upcase.tr_s("^A-Z0-9_", "_")
189
+ end
190
+ end
191
+ class Array
192
+ # Wraps all strings in escaped quotes if they contain whitespace.
193
+ def quote
194
+ map {|s| s.quote}
195
+ end
196
+ end
197
+
198
+ def rm_f(*files)
199
+ opt = (Hash === files.last ? [files.pop] : [])
200
+ FileUtils.rm_f(Dir[*files.flatten], *opt)
201
+ end
202
+
203
+ def rm_rf(*files)
204
+ opt = (Hash === files.last ? [files.pop] : [])
205
+ FileUtils.rm_rf(Dir[*files.flatten], *opt)
206
+ end
207
+
208
+ # Returns time stamp of the +target+ file if it exists and is newer
209
+ # than or equal to all of +times+.
210
+ def modified?(target, times)
211
+ (t = File.mtime(target)) rescue return nil
212
+ Array === times or times = [times]
213
+ t if times.all? {|n| n <= t}
214
+ end
215
+
216
+ def merge_libs(*libs)
217
+ libs.inject([]) do |x, y|
218
+ xy = x & y
219
+ xn = yn = 0
220
+ y = y.inject([]) {|ary, e| ary.last == e ? ary : ary << e}
221
+ y.each_with_index do |v, yi|
222
+ if xy.include?(v)
223
+ xi = [x.index(v), xn].max()
224
+ x[xi, 1] = y[yn..yi]
225
+ xn, yn = xi + (yi - yn + 1), yi + 1
226
+ end
227
+ end
228
+ x.concat(y[yn..-1] || [])
229
+ end
230
+ end
231
+
232
+ # This is a custom logging module. It generates an mkmf.log file when you
233
+ # run your extconf.rb script. This can be useful for debugging unexpected
234
+ # failures.
235
+ #
236
+ # This module and its associated methods are meant for internal use only.
237
+ #
238
+ module Logging
239
+ @log = nil
240
+ @logfile = 'mkmf.log'
241
+ @orgerr = $stderr.dup
242
+ @orgout = $stdout.dup
243
+ @postpone = 0
244
+ @quiet = $extmk
245
+
246
+ def self::log_open
247
+ @log ||= File::open(@logfile, 'wb')
248
+ @log.sync = true
249
+ end
250
+
251
+ def self::open
252
+ log_open
253
+ $stderr.reopen(@log)
254
+ $stdout.reopen(@log)
255
+ yield
256
+ ensure
257
+ $stderr.reopen(@orgerr)
258
+ $stdout.reopen(@orgout)
259
+ end
260
+
261
+ def self::message(*s)
262
+ log_open
263
+ @log.printf(*s)
264
+ end
265
+
266
+ def self::logfile file
267
+ @logfile = file
268
+ if @log and not @log.closed?
269
+ @log.flush
270
+ @log.close
271
+ @log = nil
272
+ end
273
+ end
274
+
275
+ def self::postpone
276
+ tmplog = "mkmftmp#{@postpone += 1}.log"
277
+ open do
278
+ log, *save = @log, @logfile, @orgout, @orgerr
279
+ @log, @logfile, @orgout, @orgerr = nil, tmplog, log, log
280
+ begin
281
+ log.print(open {yield})
282
+ ensure
283
+ @log.close
284
+ File::open(tmplog) {|t| FileUtils.copy_stream(t, log)}
285
+ @log, @logfile, @orgout, @orgerr = log, *save
286
+ @postpone -= 1
287
+ rm_f tmplog
288
+ end
289
+ end
290
+ end
291
+
292
+ class << self
293
+ attr_accessor :quiet
294
+ end
295
+ end
296
+
297
+ def xsystem command
298
+ varpat = /\$\((\w+)\)|\$\{(\w+)\}/
299
+ if varpat =~ command
300
+ vars = Hash.new {|h, k| h[k] = ''; ENV[k]}
301
+ command = command.dup
302
+ nil while command.gsub!(varpat) {vars[$1||$2]}
303
+ end
304
+ Logging::open do
305
+ puts command.quote
306
+ system(command)
307
+ end
308
+ end
309
+
310
+ def xpopen command, *mode, &block
311
+ Logging::open do
312
+ case mode[0]
313
+ when nil, /^r/
314
+ puts "#{command} |"
315
+ else
316
+ puts "| #{command}"
317
+ end
318
+ IO.popen(command, *mode, &block)
319
+ end
320
+ end
321
+
322
+ def log_src(src)
323
+ src = src.split(/^/)
324
+ fmt = "%#{src.size.to_s.size}d: %s"
325
+ Logging::message <<"EOM"
326
+ checked program was:
327
+ /* begin */
328
+ EOM
329
+ src.each_with_index {|line, no| Logging::message fmt, no+1, line}
330
+ Logging::message <<"EOM"
331
+ /* end */
332
+
333
+ EOM
334
+ end
335
+
336
+ def create_tmpsrc(src)
337
+ src = "#{COMMON_HEADERS}\n#{src}"
338
+ src = yield(src) if block_given?
339
+ src.gsub!(/[ \t]+$/, '')
340
+ src.gsub!(/\A\n+|^\n+$/, '')
341
+ src.sub!(/[^\n]\z/, "\\&\n")
342
+ count = 0
343
+ begin
344
+ open(CONFTEST_C, "wb") do |cfile|
345
+ cfile.print src
346
+ end
347
+ rescue Errno::EACCES
348
+ if (count += 1) < 5
349
+ sleep 0.2
350
+ retry
351
+ end
352
+ end
353
+ src
354
+ end
355
+
356
+ def have_devel?
357
+ unless defined? $have_devel
358
+ $have_devel = true
359
+ $have_devel = try_link(MAIN_DOES_NOTHING)
360
+ end
361
+ $have_devel
362
+ end
363
+
364
+ def try_do(src, command, &b)
365
+ unless have_devel?
366
+ raise <<MSG
367
+ The complier failed to generate an executable file.
368
+ You have to install development tools first.
369
+ MSG
370
+ end
371
+ begin
372
+ src = create_tmpsrc(src, &b)
373
+ xsystem(command)
374
+ ensure
375
+ log_src(src)
376
+ rm_rf 'conftest.dSYM'
377
+ end
378
+ end
379
+
380
+ def link_command(ldflags, opt="", libpath=$DEFLIBPATH|$LIBPATH)
381
+ conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote,
382
+ 'src' => "#{CONFTEST_C}",
383
+ 'arch_hdrdir' => "#$arch_hdrdir",
384
+ 'top_srcdir' => $top_srcdir.quote,
385
+ 'INCFLAGS' => "#$INCFLAGS",
386
+ 'CPPFLAGS' => "#$CPPFLAGS",
387
+ 'CFLAGS' => "#$CFLAGS",
388
+ 'ARCH_FLAG' => "#$ARCH_FLAG",
389
+ 'LDFLAGS' => "#$LDFLAGS #{ldflags}",
390
+ 'LIBPATH' => libpathflag(libpath),
391
+ 'LOCAL_LIBS' => "#$LOCAL_LIBS #$libs",
392
+ 'LIBS' => "#$LIBRUBYARG_STATIC #{opt} #$LIBS")
393
+ RbConfig::expand(TRY_LINK.dup, conf)
394
+ end
395
+
396
+ def cc_command(opt="")
397
+ conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote, 'srcdir' => $srcdir.quote,
398
+ 'arch_hdrdir' => "#$arch_hdrdir",
399
+ 'top_srcdir' => $top_srcdir.quote)
400
+ RbConfig::expand("$(CC) #$INCFLAGS #$CPPFLAGS #$CFLAGS #$ARCH_FLAG #{opt} -c #{CONFTEST_C}",
401
+ conf)
402
+ end
403
+
404
+ def cpp_command(outfile, opt="")
405
+ conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote, 'srcdir' => $srcdir.quote,
406
+ 'arch_hdrdir' => "#$arch_hdrdir",
407
+ 'top_srcdir' => $top_srcdir.quote)
408
+ RbConfig::expand("$(CPP) #$INCFLAGS #$CPPFLAGS #$CFLAGS #{opt} #{CONFTEST_C} #{outfile}",
409
+ conf)
410
+ end
411
+
412
+ def libpathflag(libpath=$DEFLIBPATH|$LIBPATH)
413
+ libpath.map{|x|
414
+ case x
415
+ when "$(topdir)", /\A\./
416
+ LIBPATHFLAG
417
+ else
418
+ LIBPATHFLAG+RPATHFLAG
419
+ end % x.quote
420
+ }.join
421
+ end
422
+
423
+ def try_link0(src, opt="", &b)
424
+ cmd = link_command("", opt)
425
+ if $universal
426
+ require 'tmpdir'
427
+ Dir.mktmpdir("mkmf_", oldtmpdir = ENV["TMPDIR"]) do |tmpdir|
428
+ begin
429
+ ENV["TMPDIR"] = tmpdir
430
+ try_do(src, cmd, &b)
431
+ ensure
432
+ ENV["TMPDIR"] = oldtmpdir
433
+ end
434
+ end
435
+ else
436
+ try_do(src, cmd, &b)
437
+ end
438
+ end
439
+
440
+ def try_link(src, opt="", &b)
441
+ try_link0(src, opt, &b)
442
+ ensure
443
+ rm_f "conftest*", "c0x32*"
444
+ end
445
+
446
+ def try_compile(src, opt="", &b)
447
+ try_do(src, cc_command(opt), &b)
448
+ ensure
449
+ rm_f "conftest*"
450
+ end
451
+
452
+ def try_cpp(src, opt="", &b)
453
+ try_do(src, cpp_command(CPPOUTFILE, opt), &b)
454
+ ensure
455
+ rm_f "conftest*"
456
+ end
457
+
458
+ class Object
459
+ alias_method :try_header, (config_string('try_header') || :try_cpp)
460
+ end
461
+
462
+ def cpp_include(header)
463
+ if header
464
+ header = [header] unless header.kind_of? Array
465
+ header.map {|h| String === h ? "#include <#{h}>\n" : h}.join
466
+ else
467
+ ""
468
+ end
469
+ end
470
+
471
+ def with_cppflags(flags)
472
+ cppflags = $CPPFLAGS
473
+ $CPPFLAGS = flags
474
+ ret = yield
475
+ ensure
476
+ $CPPFLAGS = cppflags unless ret
477
+ end
478
+
479
+ def with_cflags(flags)
480
+ cflags = $CFLAGS
481
+ $CFLAGS = flags
482
+ ret = yield
483
+ ensure
484
+ $CFLAGS = cflags unless ret
485
+ end
486
+
487
+ def with_ldflags(flags)
488
+ ldflags = $LDFLAGS
489
+ $LDFLAGS = flags
490
+ ret = yield
491
+ ensure
492
+ $LDFLAGS = ldflags unless ret
493
+ end
494
+
495
+ def try_static_assert(expr, headers = nil, opt = "", &b)
496
+ headers = cpp_include(headers)
497
+ try_compile(<<SRC, opt, &b)
498
+ #{headers}
499
+ /*top*/
500
+ int conftest_const[(#{expr}) ? 1 : -1];
501
+ SRC
502
+ end
503
+
504
+ def try_constant(const, headers = nil, opt = "", &b)
505
+ includes = cpp_include(headers)
506
+ if CROSS_COMPILING
507
+ if try_static_assert("#{const} > 0", headers, opt)
508
+ # positive constant
509
+ elsif try_static_assert("#{const} < 0", headers, opt)
510
+ neg = true
511
+ const = "-(#{const})"
512
+ elsif try_static_assert("#{const} == 0", headers, opt)
513
+ return 0
514
+ else
515
+ # not a constant
516
+ return nil
517
+ end
518
+ upper = 1
519
+ lower = 0
520
+ until try_static_assert("#{const} <= #{upper}", headers, opt)
521
+ lower = upper
522
+ upper <<= 1
523
+ end
524
+ return nil unless lower
525
+ while upper > lower + 1
526
+ mid = (upper + lower) / 2
527
+ if try_static_assert("#{const} > #{mid}", headers, opt)
528
+ lower = mid
529
+ else
530
+ upper = mid
531
+ end
532
+ end
533
+ upper = -upper if neg
534
+ return upper
535
+ else
536
+ src = %{#{includes}
537
+ #include <stdio.h>
538
+ /*top*/
539
+ int conftest_const = (int)(#{const});
540
+ int main() {printf("%d\\n", conftest_const); return 0;}
541
+ }
542
+ if try_link0(src, opt, &b)
543
+ xpopen("./conftest") do |f|
544
+ return Integer(f.gets)
545
+ end
546
+ end
547
+ end
548
+ nil
549
+ end
550
+
551
+ def try_func(func, libs, headers = nil, &b)
552
+ headers = cpp_include(headers)
553
+ try_link(<<"SRC", libs, &b) or
554
+ #{headers}
555
+ /*top*/
556
+ #{MAIN_DOES_NOTHING}
557
+ int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
558
+ SRC
559
+ try_link(<<"SRC", libs, &b)
560
+ #{headers}
561
+ /*top*/
562
+ #{MAIN_DOES_NOTHING}
563
+ int t() { #{func}(); return 0; }
564
+ SRC
565
+ end
566
+
567
+ def try_var(var, headers = nil, &b)
568
+ headers = cpp_include(headers)
569
+ try_compile(<<"SRC", &b)
570
+ #{headers}
571
+ /*top*/
572
+ #{MAIN_DOES_NOTHING}
573
+ int t() { const volatile void *volatile p; p = &(&#{var})[0]; return 0; }
574
+ SRC
575
+ end
576
+
577
+ def egrep_cpp(pat, src, opt = "", &b)
578
+ src = create_tmpsrc(src, &b)
579
+ xpopen(cpp_command('', opt)) do |f|
580
+ if Regexp === pat
581
+ puts(" ruby -ne 'print if #{pat.inspect}'")
582
+ f.grep(pat) {|l|
583
+ puts "#{f.lineno}: #{l}"
584
+ return true
585
+ }
586
+ false
587
+ else
588
+ puts(" egrep '#{pat}'")
589
+ begin
590
+ stdin = $stdin.dup
591
+ $stdin.reopen(f)
592
+ system("egrep", pat)
593
+ ensure
594
+ $stdin.reopen(stdin)
595
+ end
596
+ end
597
+ end
598
+ ensure
599
+ rm_f "conftest*"
600
+ log_src(src)
601
+ end
602
+
603
+ # This is used internally by the have_macro? method.
604
+ def macro_defined?(macro, src, opt = "", &b)
605
+ src = src.sub(/[^\n]\z/, "\\&\n")
606
+ try_compile(src + <<"SRC", opt, &b)
607
+ /*top*/
608
+ #ifndef #{macro}
609
+ # error
610
+ >>>>>> #{macro} undefined <<<<<<
611
+ #endif
612
+ SRC
613
+ end
614
+
615
+ def try_run(src, opt = "", &b)
616
+ if try_link0(src, opt, &b)
617
+ xsystem("./conftest")
618
+ else
619
+ nil
620
+ end
621
+ ensure
622
+ rm_f "conftest*"
623
+ end
624
+
625
+ def install_files(mfile, ifiles, map = nil, srcprefix = nil)
626
+ ifiles or return
627
+ ifiles.empty? and return
628
+ srcprefix ||= "$(srcdir)/#{srcprefix}".chomp('/')
629
+ RbConfig::expand(srcdir = srcprefix.dup)
630
+ dirs = []
631
+ path = Hash.new {|h, i| h[i] = dirs.push([i])[-1]}
632
+ ifiles.each do |files, dir, prefix|
633
+ dir = map_dir(dir, map)
634
+ prefix &&= %r|\A#{Regexp.quote(prefix)}/?|
635
+ if /\A\.\// =~ files
636
+ # install files which are in current working directory.
637
+ files = files[2..-1]
638
+ len = nil
639
+ else
640
+ # install files which are under the $(srcdir).
641
+ files = File.join(srcdir, files)
642
+ len = srcdir.size
643
+ end
644
+ f = nil
645
+ Dir.glob(files) do |fx|
646
+ f = fx
647
+ f[0..len] = "" if len
648
+ case File.basename(f)
649
+ when *$NONINSTALLFILES
650
+ next
651
+ end
652
+ d = File.dirname(f)
653
+ d.sub!(prefix, "") if prefix
654
+ d = (d.empty? || d == ".") ? dir : File.join(dir, d)
655
+ f = File.join(srcprefix, f) if len
656
+ path[d] << f
657
+ end
658
+ unless len or f
659
+ d = File.dirname(files)
660
+ d.sub!(prefix, "") if prefix
661
+ d = (d.empty? || d == ".") ? dir : File.join(dir, d)
662
+ path[d] << files
663
+ end
664
+ end
665
+ dirs
666
+ end
667
+
668
+ def install_rb(mfile, dest, srcdir = nil)
669
+ install_files(mfile, [["lib/**/*.rb", dest, "lib"]], nil, srcdir)
670
+ end
671
+
672
+ def append_library(libs, lib) # :no-doc:
673
+ format(LIBARG, lib) + " " + libs
674
+ end
675
+
676
+ def message(*s)
677
+ unless Logging.quiet and not $VERBOSE
678
+ printf(*s)
679
+ $stdout.flush
680
+ end
681
+ end
682
+
683
+ # This emits a string to stdout that allows users to see the results of the
684
+ # various have* and find* methods as they are tested.
685
+ #
686
+ # Internal use only.
687
+ #
688
+ def checking_for(m, fmt = nil)
689
+ f = caller[0][/in `([^<].*)'$/, 1] and f << ": " #` for vim #'
690
+ m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... "
691
+ message "%s", m
692
+ a = r = nil
693
+ Logging::postpone do
694
+ r = yield
695
+ a = (fmt ? fmt % r : r ? "yes" : "no") << "\n"
696
+ "#{f}#{m}-------------------- #{a}\n"
697
+ end
698
+ message(a)
699
+ Logging::message "--------------------\n\n"
700
+ r
701
+ end
702
+
703
+ def checking_message(target, place = nil, opt = nil)
704
+ [["in", place], ["with", opt]].inject("#{target}") do |msg, (pre, noun)|
705
+ if noun
706
+ [[:to_str], [:join, ","], [:to_s]].each do |meth, *args|
707
+ if noun.respond_to?(meth)
708
+ break noun = noun.send(meth, *args)
709
+ end
710
+ end
711
+ msg << " #{pre} #{noun}" unless noun.empty?
712
+ end
713
+ msg
714
+ end
715
+ end
716
+
717
+ # :startdoc:
718
+
719
+ # Returns whether or not +macro+ is defined either in the common header
720
+ # files or within any +headers+ you provide.
721
+ #
722
+ # Any options you pass to +opt+ are passed along to the compiler.
723
+ #
724
+ def have_macro(macro, headers = nil, opt = "", &b)
725
+ checking_for checking_message(macro, headers, opt) do
726
+ macro_defined?(macro, cpp_include(headers), opt, &b)
727
+ end
728
+ end
729
+
730
+ # Returns whether or not the given entry point +func+ can be found within
731
+ # +lib+. If +func+ is nil, the 'main()' entry point is used by default.
732
+ # If found, it adds the library to list of libraries to be used when linking
733
+ # your extension.
734
+ #
735
+ # If +headers+ are provided, it will include those header files as the
736
+ # header files it looks in when searching for +func+.
737
+ #
738
+ # The real name of the library to be linked can be altered by
739
+ # '--with-FOOlib' configuration option.
740
+ #
741
+ def have_library(lib, func = nil, headers = nil, &b)
742
+ func = "main" if !func or func.empty?
743
+ lib = with_config(lib+'lib', lib)
744
+ checking_for checking_message("#{func}()", LIBARG%lib) do
745
+ if COMMON_LIBS.include?(lib)
746
+ true
747
+ else
748
+ libs = append_library($libs, lib)
749
+ if try_func(func, libs, headers, &b)
750
+ $libs = libs
751
+ true
752
+ else
753
+ false
754
+ end
755
+ end
756
+ end
757
+ end
758
+
759
+ # Returns whether or not the entry point +func+ can be found within the library
760
+ # +lib+ in one of the +paths+ specified, where +paths+ is an array of strings.
761
+ # If +func+ is nil , then the main() function is used as the entry point.
762
+ #
763
+ # If +lib+ is found, then the path it was found on is added to the list of
764
+ # library paths searched and linked against.
765
+ #
766
+ def find_library(lib, func, *paths, &b)
767
+ func = "main" if !func or func.empty?
768
+ lib = with_config(lib+'lib', lib)
769
+ paths = paths.collect {|path| path.split(File::PATH_SEPARATOR)}.flatten
770
+ checking_for "#{func}() in #{LIBARG%lib}" do
771
+ libpath = $LIBPATH
772
+ libs = append_library($libs, lib)
773
+ begin
774
+ until r = try_func(func, libs, &b) or paths.empty?
775
+ $LIBPATH = libpath | [paths.shift]
776
+ end
777
+ if r
778
+ $libs = libs
779
+ libpath = nil
780
+ end
781
+ ensure
782
+ $LIBPATH = libpath if libpath
783
+ end
784
+ r
785
+ end
786
+ end
787
+
788
+ # Returns whether or not the function +func+ can be found in the common
789
+ # header files, or within any +headers+ that you provide. If found, a
790
+ # macro is passed as a preprocessor constant to the compiler using the
791
+ # function name, in uppercase, prepended with 'HAVE_'.
792
+ #
793
+ # For example, if have_func('foo') returned true, then the HAVE_FOO
794
+ # preprocessor macro would be passed to the compiler.
795
+ #
796
+ def have_func(func, headers = nil, &b)
797
+ checking_for checking_message("#{func}()", headers) do
798
+ if try_func(func, $libs, headers, &b)
799
+ $defs.push(format("-DHAVE_%s", func.tr_cpp))
800
+ true
801
+ else
802
+ false
803
+ end
804
+ end
805
+ end
806
+
807
+ # Returns whether or not the variable +var+ can be found in the common
808
+ # header files, or within any +headers+ that you provide. If found, a
809
+ # macro is passed as a preprocessor constant to the compiler using the
810
+ # variable name, in uppercase, prepended with 'HAVE_'.
811
+ #
812
+ # For example, if have_var('foo') returned true, then the HAVE_FOO
813
+ # preprocessor macro would be passed to the compiler.
814
+ #
815
+ def have_var(var, headers = nil, &b)
816
+ checking_for checking_message(var, headers) do
817
+ if try_var(var, headers, &b)
818
+ $defs.push(format("-DHAVE_%s", var.tr_cpp))
819
+ true
820
+ else
821
+ false
822
+ end
823
+ end
824
+ end
825
+
826
+ # Returns whether or not the given +header+ file can be found on your system.
827
+ # If found, a macro is passed as a preprocessor constant to the compiler using
828
+ # the header file name, in uppercase, prepended with 'HAVE_'.
829
+ #
830
+ # For example, if have_header('foo.h') returned true, then the HAVE_FOO_H
831
+ # preprocessor macro would be passed to the compiler.
832
+ #
833
+ def have_header(header, preheaders = nil, &b)
834
+ checking_for header do
835
+ if try_header(cpp_include(preheaders)+cpp_include(header), &b)
836
+ $defs.push(format("-DHAVE_%s", header.tr_cpp))
837
+ true
838
+ else
839
+ false
840
+ end
841
+ end
842
+ end
843
+
844
+ # Instructs mkmf to search for the given +header+ in any of the +paths+
845
+ # provided, and returns whether or not it was found in those paths.
846
+ #
847
+ # If the header is found then the path it was found on is added to the list
848
+ # of included directories that are sent to the compiler (via the -I switch).
849
+ #
850
+ def find_header(header, *paths)
851
+ message = checking_message(header, paths)
852
+ header = cpp_include(header)
853
+ checking_for message do
854
+ if try_header(header)
855
+ true
856
+ else
857
+ found = false
858
+ paths.each do |dir|
859
+ opt = "-I#{dir}".quote
860
+ if try_header(header, opt)
861
+ $INCFLAGS << " " << opt
862
+ found = true
863
+ break
864
+ end
865
+ end
866
+ found
867
+ end
868
+ end
869
+ end
870
+
871
+ # Returns whether or not the struct of type +type+ contains +member+. If
872
+ # it does not, or the struct type can't be found, then false is returned. You
873
+ # may optionally specify additional +headers+ in which to look for the struct
874
+ # (in addition to the common header files).
875
+ #
876
+ # If found, a macro is passed as a preprocessor constant to the compiler using
877
+ # the type name and the member name, in uppercase, prepended with 'HAVE_'.
878
+ #
879
+ # For example, if have_struct_member('struct foo', 'bar') returned true, then the
880
+ # HAVE_STRUCT_FOO_BAR preprocessor macro would be passed to the compiler.
881
+ #
882
+ # HAVE_ST_BAR is also defined for backward compatibility.
883
+ #
884
+ def have_struct_member(type, member, headers = nil, &b)
885
+ checking_for checking_message("#{type}.#{member}", headers) do
886
+ if try_compile(<<"SRC", &b)
887
+ #{cpp_include(headers)}
888
+ /*top*/
889
+ #{MAIN_DOES_NOTHING}
890
+ int s = (char *)&((#{type}*)0)->#{member} - (char *)0;
891
+ SRC
892
+ $defs.push(format("-DHAVE_%s_%s", type.tr_cpp, member.tr_cpp))
893
+ $defs.push(format("-DHAVE_ST_%s", member.tr_cpp)) # backward compatibility
894
+ true
895
+ else
896
+ false
897
+ end
898
+ end
899
+ end
900
+
901
+ def try_type(type, headers = nil, opt = "", &b)
902
+ if try_compile(<<"SRC", opt, &b)
903
+ #{cpp_include(headers)}
904
+ /*top*/
905
+ typedef #{type} conftest_type;
906
+ int conftestval[sizeof(conftest_type)?1:-1];
907
+ SRC
908
+ $defs.push(format("-DHAVE_TYPE_%s", type.tr_cpp))
909
+ true
910
+ else
911
+ false
912
+ end
913
+ end
914
+
915
+ # Returns whether or not the static type +type+ is defined. You may
916
+ # optionally pass additional +headers+ to check against in addition to the
917
+ # common header files.
918
+ #
919
+ # You may also pass additional flags to +opt+ which are then passed along to
920
+ # the compiler.
921
+ #
922
+ # If found, a macro is passed as a preprocessor constant to the compiler using
923
+ # the type name, in uppercase, prepended with 'HAVE_TYPE_'.
924
+ #
925
+ # For example, if have_type('foo') returned true, then the HAVE_TYPE_FOO
926
+ # preprocessor macro would be passed to the compiler.
927
+ #
928
+ def have_type(type, headers = nil, opt = "", &b)
929
+ checking_for checking_message(type, headers, opt) do
930
+ try_type(type, headers, opt, &b)
931
+ end
932
+ end
933
+
934
+ # Returns where the static type +type+ is defined.
935
+ #
936
+ # You may also pass additional flags to +opt+ which are then passed along to
937
+ # the compiler.
938
+ #
939
+ # See also +have_type+.
940
+ #
941
+ def find_type(type, opt, *headers, &b)
942
+ opt ||= ""
943
+ fmt = "not found"
944
+ def fmt.%(x)
945
+ x ? x.respond_to?(:join) ? x.join(",") : x : self
946
+ end
947
+ checking_for checking_message(type, nil, opt), fmt do
948
+ headers.find do |h|
949
+ try_type(type, h, opt, &b)
950
+ end
951
+ end
952
+ end
953
+
954
+ def try_const(const, headers = nil, opt = "", &b)
955
+ const, type = *const
956
+ if try_compile(<<"SRC", opt, &b)
957
+ #{cpp_include(headers)}
958
+ /*top*/
959
+ typedef #{type || 'int'} conftest_type;
960
+ conftest_type conftestval = #{type ? '' : '(int)'}#{const};
961
+ SRC
962
+ $defs.push(format("-DHAVE_CONST_%s", const.tr_cpp))
963
+ true
964
+ else
965
+ false
966
+ end
967
+ end
968
+
969
+ # Returns whether or not the constant +const+ is defined. You may
970
+ # optionally pass the +type+ of +const+ as <code>[const, type]</code>,
971
+ # like as:
972
+ #
973
+ # have_const(%w[PTHREAD_MUTEX_INITIALIZER pthread_mutex_t], "pthread.h")
974
+ #
975
+ # You may also pass additional +headers+ to check against in addition
976
+ # to the common header files, and additional flags to +opt+ which are
977
+ # then passed along to the compiler.
978
+ #
979
+ # If found, a macro is passed as a preprocessor constant to the compiler using
980
+ # the type name, in uppercase, prepended with 'HAVE_CONST_'.
981
+ #
982
+ # For example, if have_const('foo') returned true, then the HAVE_CONST_FOO
983
+ # preprocessor macro would be passed to the compiler.
984
+ #
985
+ def have_const(const, headers = nil, opt = "", &b)
986
+ checking_for checking_message([*const].compact.join(' '), headers, opt) do
987
+ try_const(const, headers, opt, &b)
988
+ end
989
+ end
990
+
991
+ STRING_OR_FAILED_FORMAT = "%s"
992
+ # :stopdoc:
993
+ def STRING_OR_FAILED_FORMAT.%(x)
994
+ x ? super : "failed"
995
+ end
996
+ # :startdoc:
997
+
998
+ # Returns the size of the given +type+. You may optionally specify additional
999
+ # +headers+ to search in for the +type+.
1000
+ #
1001
+ # If found, a macro is passed as a preprocessor constant to the compiler using
1002
+ # the type name, in uppercase, prepended with 'SIZEOF_', followed by the type
1003
+ # name, followed by '=X' where 'X' is the actual size.
1004
+ #
1005
+ # For example, if check_sizeof('mystruct') returned 12, then the
1006
+ # SIZEOF_MYSTRUCT=12 preprocessor macro would be passed to the compiler.
1007
+ #
1008
+ def check_sizeof(type, headers = nil, opts = "", &b)
1009
+ typename, member = type.split('.', 2)
1010
+ prelude = cpp_include(headers).split(/$/)
1011
+ prelude << "typedef #{typename} rbcv_typedef_;\n"
1012
+ prelude << "static rbcv_typedef_ *rbcv_ptr_;\n"
1013
+ prelude = [prelude]
1014
+ expr = "sizeof((*rbcv_ptr_)#{"." << member if member})"
1015
+ fmt = STRING_OR_FAILED_FORMAT
1016
+ checking_for checking_message("size of #{type}", headers), fmt do
1017
+ if UNIVERSAL_INTS.include?(type)
1018
+ type
1019
+ elsif size = UNIVERSAL_INTS.find {|t|
1020
+ try_static_assert("#{expr} == sizeof(#{t})", prelude, opts, &b)
1021
+ }
1022
+ $defs.push(format("-DSIZEOF_%s=SIZEOF_%s", type.tr_cpp, size.tr_cpp))
1023
+ size
1024
+ elsif size = try_constant(expr, prelude, opts, &b)
1025
+ $defs.push(format("-DSIZEOF_%s=%s", type.tr_cpp, size))
1026
+ size
1027
+ end
1028
+ end
1029
+ end
1030
+
1031
+ # Returns the signedness of the given +type+. You may optionally
1032
+ # specify additional +headers+ to search in for the +type+.
1033
+ #
1034
+ # If the +type+ is found and is a numeric type, a macro is passed as a
1035
+ # preprocessor constant to the compiler using the +type+ name, in
1036
+ # uppercase, prepended with 'SIGNEDNESS_OF_', followed by the +type+
1037
+ # name, followed by '=X' where 'X' is positive integer if the +type+ is
1038
+ # unsigned, or negative integer if the +type+ is signed.
1039
+ #
1040
+ # For example, if size_t is defined as unsigned, then
1041
+ # check_signedness('size_t') would returned +1 and the
1042
+ # SIGNEDNESS_OF_SIZE_T=+1 preprocessor macro would be passed to the
1043
+ # compiler, and SIGNEDNESS_OF_INT=-1 if check_signedness('int') is
1044
+ # done.
1045
+ #
1046
+ def check_signedness(type, headers = nil)
1047
+ signed = nil
1048
+ checking_for("signedness of #{type}", STRING_OR_FAILED_FORMAT) do
1049
+ if try_static_assert("(#{type})-1 < 0")
1050
+ signed = -1
1051
+ elsif try_static_assert("(#{type})-1 > 0")
1052
+ signed = +1
1053
+ else
1054
+ next nil
1055
+ end
1056
+ $defs.push("-DSIGNEDNESS_OF_%s=%+d" % [type.tr_cpp, signed])
1057
+ signed < 0 ? "signed" : "unsigned"
1058
+ end
1059
+ signed
1060
+ end
1061
+
1062
+ # :stopdoc:
1063
+
1064
+ # Used internally by the what_type? method to determine if +type+ is a scalar
1065
+ # pointer.
1066
+ def scalar_ptr_type?(type, member = nil, headers = nil, &b)
1067
+ try_compile(<<"SRC", &b) # pointer
1068
+ #{cpp_include(headers)}
1069
+ /*top*/
1070
+ volatile #{type} conftestval;
1071
+ #{MAIN_DOES_NOTHING}
1072
+ int t() {return (int)(1-*(conftestval#{member ? ".#{member}" : ""}));}
1073
+ SRC
1074
+ end
1075
+
1076
+ # Used internally by the what_type? method to determine if +type+ is a scalar
1077
+ # pointer.
1078
+ def scalar_type?(type, member = nil, headers = nil, &b)
1079
+ try_compile(<<"SRC", &b) # pointer
1080
+ #{cpp_include(headers)}
1081
+ /*top*/
1082
+ volatile #{type} conftestval;
1083
+ #{MAIN_DOES_NOTHING}
1084
+ int t() {return (int)(1-(conftestval#{member ? ".#{member}" : ""}));}
1085
+ SRC
1086
+ end
1087
+
1088
+ # Used internally by the what_type? method to check if _typeof_ GCC
1089
+ # extension is available.
1090
+ def have_typeof?
1091
+ return $typeof if defined?($typeof)
1092
+ $typeof = %w[__typeof__ typeof].find do |t|
1093
+ try_compile(<<SRC)
1094
+ int rbcv_foo;
1095
+ #{t}(rbcv_foo) rbcv_bar;
1096
+ SRC
1097
+ end
1098
+ end
1099
+
1100
+ def what_type?(type, member = nil, headers = nil, &b)
1101
+ m = "#{type}"
1102
+ var = val = "*rbcv_var_"
1103
+ func = "rbcv_func_(void)"
1104
+ if member
1105
+ m << "." << member
1106
+ else
1107
+ type, member = type.split('.', 2)
1108
+ end
1109
+ if member
1110
+ val = "(#{var}).#{member}"
1111
+ end
1112
+ prelude = [cpp_include(headers).split(/^/)]
1113
+ prelude << ["typedef #{type} rbcv_typedef_;\n",
1114
+ "extern rbcv_typedef_ *#{func};\n",
1115
+ "static rbcv_typedef_ #{var};\n",
1116
+ ]
1117
+ type = "rbcv_typedef_"
1118
+ fmt = member && !(typeof = have_typeof?) ? "seems %s" : "%s"
1119
+ if typeof
1120
+ var = "*rbcv_member_"
1121
+ func = "rbcv_mem_func_(void)"
1122
+ member = nil
1123
+ type = "rbcv_mem_typedef_"
1124
+ prelude[-1] << "typedef #{typeof}(#{val}) #{type};\n"
1125
+ prelude[-1] << "extern #{type} *#{func};\n"
1126
+ prelude[-1] << "static #{type} #{var};\n"
1127
+ val = var
1128
+ end
1129
+ def fmt.%(x)
1130
+ x ? super : "unknown"
1131
+ end
1132
+ checking_for checking_message(m, headers), fmt do
1133
+ if scalar_ptr_type?(type, member, prelude, &b)
1134
+ if try_static_assert("sizeof(*#{var}) == 1", prelude)
1135
+ return "string"
1136
+ end
1137
+ ptr = "*"
1138
+ elsif scalar_type?(type, member, prelude, &b)
1139
+ unless member and !typeof or try_static_assert("(#{type})-1 < 0", prelude)
1140
+ unsigned = "unsigned"
1141
+ end
1142
+ ptr = ""
1143
+ else
1144
+ next
1145
+ end
1146
+ type = UNIVERSAL_INTS.find do |t|
1147
+ pre = prelude
1148
+ unless member
1149
+ pre += [["static #{unsigned} #{t} #{ptr}#{var};\n",
1150
+ "extern #{unsigned} #{t} #{ptr}*#{func};\n"]]
1151
+ end
1152
+ try_static_assert("sizeof(#{ptr}#{val}) == sizeof(#{unsigned} #{t})", pre)
1153
+ end
1154
+ type or next
1155
+ [unsigned, type, ptr].join(" ").strip
1156
+ end
1157
+ end
1158
+
1159
+ # This method is used internally by the find_executable method.
1160
+ #
1161
+ # Internal use only.
1162
+ #
1163
+ def find_executable0(bin, path = nil)
1164
+ exts = config_string('EXECUTABLE_EXTS') {|s| s.split} || config_string('EXEEXT') {|s| [s]}
1165
+ if File.expand_path(bin) == bin
1166
+ return bin if File.executable?(bin)
1167
+ if exts
1168
+ exts.each {|ext| File.executable?(file = bin + ext) and return file}
1169
+ end
1170
+ return nil
1171
+ end
1172
+ if path ||= ENV['PATH']
1173
+ path = path.split(File::PATH_SEPARATOR)
1174
+ else
1175
+ path = %w[/usr/local/bin /usr/ucb /usr/bin /bin]
1176
+ end
1177
+ file = nil
1178
+ path.each do |dir|
1179
+ return file if File.executable?(file = File.join(dir, bin))
1180
+ if exts
1181
+ exts.each {|ext| File.executable?(ext = file + ext) and return ext}
1182
+ end
1183
+ end
1184
+ nil
1185
+ end
1186
+
1187
+ # :startdoc:
1188
+
1189
+ # Searches for the executable +bin+ on +path+. The default path is your
1190
+ # PATH environment variable. If that isn't defined, it will resort to
1191
+ # searching /usr/local/bin, /usr/ucb, /usr/bin and /bin.
1192
+ #
1193
+ # If found, it will return the full path, including the executable name,
1194
+ # of where it was found.
1195
+ #
1196
+ # Note that this method does not actually affect the generated Makefile.
1197
+ #
1198
+ def find_executable(bin, path = nil)
1199
+ checking_for checking_message(bin, path) do
1200
+ find_executable0(bin, path)
1201
+ end
1202
+ end
1203
+
1204
+ # :stopdoc:
1205
+
1206
+ def arg_config(config, default=nil, &block)
1207
+ $arg_config << [config, default]
1208
+ defaults = []
1209
+ if default
1210
+ defaults << default
1211
+ elsif !block
1212
+ defaults << nil
1213
+ end
1214
+ $configure_args.fetch(config.tr('_', '-'), *defaults, &block)
1215
+ end
1216
+
1217
+ # :startdoc:
1218
+
1219
+ # Tests for the presence of a --with-<tt>config</tt> or --without-<tt>config</tt>
1220
+ # option. Returns true if the with option is given, false if the without
1221
+ # option is given, and the default value otherwise.
1222
+ #
1223
+ # This can be useful for adding custom definitions, such as debug information.
1224
+ #
1225
+ # Example:
1226
+ #
1227
+ # if with_config("debug")
1228
+ # $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
1229
+ # end
1230
+ #
1231
+ def with_config(config, default=nil)
1232
+ config = config.sub(/^--with[-_]/, '')
1233
+ val = arg_config("--with-"+config) do
1234
+ if arg_config("--without-"+config)
1235
+ false
1236
+ elsif block_given?
1237
+ yield(config, default)
1238
+ else
1239
+ break default
1240
+ end
1241
+ end
1242
+ case val
1243
+ when "yes"
1244
+ true
1245
+ when "no"
1246
+ false
1247
+ else
1248
+ val
1249
+ end
1250
+ end
1251
+
1252
+ # Tests for the presence of an --enable-<tt>config</tt> or
1253
+ # --disable-<tt>config</tt> option. Returns true if the enable option is given,
1254
+ # false if the disable option is given, and the default value otherwise.
1255
+ #
1256
+ # This can be useful for adding custom definitions, such as debug information.
1257
+ #
1258
+ # Example:
1259
+ #
1260
+ # if enable_config("debug")
1261
+ # $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
1262
+ # end
1263
+ #
1264
+ def enable_config(config, default=nil)
1265
+ if arg_config("--enable-"+config)
1266
+ true
1267
+ elsif arg_config("--disable-"+config)
1268
+ false
1269
+ elsif block_given?
1270
+ yield(config, default)
1271
+ else
1272
+ return default
1273
+ end
1274
+ end
1275
+
1276
+ # Generates a header file consisting of the various macro definitions generated
1277
+ # by other methods such as have_func and have_header. These are then wrapped in
1278
+ # a custom #ifndef based on the +header+ file name, which defaults to
1279
+ # 'extconf.h'.
1280
+ #
1281
+ # For example:
1282
+ #
1283
+ # # extconf.rb
1284
+ # require 'mkmf'
1285
+ # have_func('realpath')
1286
+ # have_header('sys/utime.h')
1287
+ # create_header
1288
+ # create_makefile('foo')
1289
+ #
1290
+ # The above script would generate the following extconf.h file:
1291
+ #
1292
+ # #ifndef EXTCONF_H
1293
+ # #define EXTCONF_H
1294
+ # #define HAVE_REALPATH 1
1295
+ # #define HAVE_SYS_UTIME_H 1
1296
+ # #endif
1297
+ #
1298
+ # Given that the create_header method generates a file based on definitions
1299
+ # set earlier in your extconf.rb file, you will probably want to make this
1300
+ # one of the last methods you call in your script.
1301
+ #
1302
+ def create_header(header = "extconf.h")
1303
+ message "creating %s\n", header
1304
+ sym = header.tr_cpp
1305
+ hdr = ["#ifndef #{sym}\n#define #{sym}\n"]
1306
+ for line in $defs
1307
+ case line
1308
+ when /^-D([^=]+)(?:=(.*))?/
1309
+ hdr << "#define #$1 #{$2 ? Shellwords.shellwords($2)[0].gsub(/(?=\t+)/, "\\\n") : 1}\n"
1310
+ when /^-U(.*)/
1311
+ hdr << "#undef #$1\n"
1312
+ end
1313
+ end
1314
+ hdr << "#endif\n"
1315
+ hdr = hdr.join
1316
+ unless (IO.read(header) == hdr rescue false)
1317
+ open(header, "wb") do |hfile|
1318
+ hfile.write(hdr)
1319
+ end
1320
+ end
1321
+ $extconf_h = header
1322
+ end
1323
+
1324
+ # Sets a +target+ name that the user can then use to configure various 'with'
1325
+ # options with on the command line by using that name. For example, if the
1326
+ # target is set to "foo", then the user could use the --with-foo-dir command
1327
+ # line option.
1328
+ #
1329
+ # You may pass along additional 'include' or 'lib' defaults via the +idefault+
1330
+ # and +ldefault+ parameters, respectively.
1331
+ #
1332
+ # Note that dir_config only adds to the list of places to search for libraries
1333
+ # and include files. It does not link the libraries into your application.
1334
+ #
1335
+ def dir_config(target, idefault=nil, ldefault=nil)
1336
+ if dir = with_config(target + "-dir", (idefault unless ldefault))
1337
+ defaults = Array === dir ? dir : dir.split(File::PATH_SEPARATOR)
1338
+ idefault = ldefault = nil
1339
+ end
1340
+
1341
+ idir = with_config(target + "-include", idefault)
1342
+ $arg_config.last[1] ||= "${#{target}-dir}/include"
1343
+ ldir = with_config(target + "-lib", ldefault)
1344
+ $arg_config.last[1] ||= "${#{target}-dir}/lib"
1345
+
1346
+ idirs = idir ? Array === idir ? idir.dup : idir.split(File::PATH_SEPARATOR) : []
1347
+ if defaults
1348
+ idirs.concat(defaults.collect {|d| d + "/include"})
1349
+ idir = ([idir] + idirs).compact.join(File::PATH_SEPARATOR)
1350
+ end
1351
+ unless idirs.empty?
1352
+ idirs.collect! {|d| "-I" + d}
1353
+ idirs -= Shellwords.shellwords($CPPFLAGS)
1354
+ unless idirs.empty?
1355
+ $CPPFLAGS = (idirs.quote << $CPPFLAGS).join(" ")
1356
+ end
1357
+ end
1358
+
1359
+ ldirs = ldir ? Array === ldir ? ldir.dup : ldir.split(File::PATH_SEPARATOR) : []
1360
+ if defaults
1361
+ ldirs.concat(defaults.collect {|d| d + "/lib"})
1362
+ ldir = ([ldir] + ldirs).compact.join(File::PATH_SEPARATOR)
1363
+ end
1364
+ $LIBPATH = ldirs | $LIBPATH
1365
+
1366
+ [idir, ldir]
1367
+ end
1368
+
1369
+ # :stopdoc:
1370
+
1371
+ # Handles meta information about installed libraries. Uses your platform's
1372
+ # pkg-config program if it has one.
1373
+ def pkg_config(pkg)
1374
+ if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
1375
+ # iff package specific config command is given
1376
+ get = proc {|opt| `#{pkgconfig} --#{opt}`.chomp}
1377
+ elsif ($PKGCONFIG ||=
1378
+ (pkgconfig = with_config("pkg-config", ("pkg-config" unless CROSS_COMPILING))) &&
1379
+ find_executable0(pkgconfig) && pkgconfig) and
1380
+ system("#{$PKGCONFIG} --exists #{pkg}")
1381
+ # default to pkg-config command
1382
+ get = proc {|opt| `#{$PKGCONFIG} --#{opt} #{pkg}`.chomp}
1383
+ elsif find_executable0(pkgconfig = "#{pkg}-config")
1384
+ # default to package specific config command, as a last resort.
1385
+ get = proc {|opt| `#{pkgconfig} --#{opt}`.chomp}
1386
+ end
1387
+ if get
1388
+ cflags = get['cflags']
1389
+ ldflags = get['libs']
1390
+ libs = get['libs-only-l']
1391
+ ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ")
1392
+ $CFLAGS += " " << cflags
1393
+ $LDFLAGS += " " << ldflags
1394
+ $libs += " " << libs
1395
+ Logging::message "package configuration for %s\n", pkg
1396
+ Logging::message "cflags: %s\nldflags: %s\nlibs: %s\n\n",
1397
+ cflags, ldflags, libs
1398
+ [cflags, ldflags, libs]
1399
+ else
1400
+ Logging::message "package configuration for %s is not found\n", pkg
1401
+ nil
1402
+ end
1403
+ end
1404
+
1405
+ def with_destdir(dir)
1406
+ dir = dir.sub($dest_prefix_pattern, '')
1407
+ /\A\$[\(\{]/ =~ dir ? dir : "$(DESTDIR)"+dir
1408
+ end
1409
+
1410
+ # Converts forward slashes to backslashes. Aimed at MS Windows.
1411
+ #
1412
+ # Internal use only.
1413
+ #
1414
+ def winsep(s)
1415
+ s.tr('/', '\\')
1416
+ end
1417
+
1418
+ # Converts native path to format acceptable in Makefile
1419
+ #
1420
+ # Internal use only.
1421
+ #
1422
+ if !CROSS_COMPILING
1423
+ case CONFIG['build_os']
1424
+ when 'mingw32'
1425
+ def mkintpath(path)
1426
+ # mingw uses make from msys and it needs special care
1427
+ # converts from C:\some\path to /C/some/path
1428
+ path = path.dup
1429
+ path.tr!('\\', '/')
1430
+ path.sub!(/\A([A-Za-z]):(?=\/)/, '/\1')
1431
+ return File.expand_path( path ) unless $use_relative_paths
1432
+ return path
1433
+ end
1434
+ end
1435
+ end
1436
+ unless defined?(mkintpath)
1437
+ def mkintpath(path)
1438
+ return File.expand_path( path ) unless $use_relative_paths
1439
+ return path
1440
+ end
1441
+ end
1442
+
1443
+ def configuration(srcdir)
1444
+ mk = []
1445
+ vpath = $VPATH.dup
1446
+ if !CROSS_COMPILING
1447
+ case CONFIG['build_os']
1448
+ when 'cygwin'
1449
+ if CONFIG['target_os'] != 'cygwin'
1450
+ vpath = vpath.map {|p| p.sub(/.*/, '$(shell cygpath -u \&)')}
1451
+ end
1452
+ end
1453
+ end
1454
+ CONFIG["hdrdir"] ||= $hdrdir
1455
+ mk << %{
1456
+ SHELL = /bin/sh
1457
+
1458
+ #### Start of system configuration section. ####
1459
+ #{"top_srcdir = " + $top_srcdir.sub(%r"\A#{Regexp.quote($topdir)}/", "$(topdir)/") if $extmk}
1460
+ srcdir = #{srcdir.gsub(/\$\((srcdir)\)|\$\{(srcdir)\}/) {mkintpath(CONFIG[$1||$2])}.quote}
1461
+ topdir = #{mkintpath($extmk ? CONFIG["topdir"] : $topdir).quote}
1462
+ hdrdir = #{mkintpath(CONFIG["hdrdir"]).quote}
1463
+ arch_hdrdir = #{$arch_hdrdir}
1464
+ VPATH = #{vpath.join(CONFIG['PATH_SEPARATOR'])}:#{$file_directories.collect{ |directory| File.expand_path( directory )}.join(':')}
1465
+ }
1466
+ if $extmk
1467
+ mk << "RUBYLIB = -\nRUBYOPT = -r$(top_srcdir)/ext/purelib.rb\n"
1468
+ end
1469
+ if destdir = CONFIG["prefix"][$dest_prefix_pattern, 1]
1470
+ mk << "\nDESTDIR = #{destdir}\n"
1471
+ end
1472
+ CONFIG.each do |key, var|
1473
+ next unless /prefix$/ =~ key
1474
+ mk << "#{key} = #{with_destdir(var)}\n"
1475
+ end
1476
+ CONFIG.each do |key, var|
1477
+ next if /^abs_/ =~ key
1478
+ next if /^(?:src|top|hdr)dir$/ =~ key
1479
+ next unless /dir$/ =~ key
1480
+ mk << "#{key} = #{with_destdir(var)}\n"
1481
+ end
1482
+ if !$extmk and !$configure_args.has_key?('--ruby') and
1483
+ sep = config_string('BUILD_FILE_SEPARATOR')
1484
+ sep = ":/=#{sep}"
1485
+ else
1486
+ sep = ""
1487
+ end
1488
+ possible_command = (proc {|s| s if /top_srcdir/ !~ s} unless $extmk)
1489
+ extconf_h = $extconf_h ? "-DRUBY_EXTCONF_H=\\\"$(RUBY_EXTCONF_H)\\\" " : $defs.join(" ") << " "
1490
+ mk << %{
1491
+ CC = #{CONFIG['CC']}
1492
+ CXX = #{CONFIG['CXX']}
1493
+ LIBRUBY = #{CONFIG['LIBRUBY']}
1494
+ LIBRUBY_A = #{CONFIG['LIBRUBY_A']}
1495
+ LIBRUBYARG_SHARED = #$LIBRUBYARG_SHARED
1496
+ LIBRUBYARG_STATIC = #$LIBRUBYARG_STATIC
1497
+ OUTFLAG = #{OUTFLAG}
1498
+ COUTFLAG = #{COUTFLAG}
1499
+
1500
+ RUBY_EXTCONF_H = #{$extconf_h}
1501
+ cflags = #{CONFIG['cflags']}
1502
+ optflags = #{CONFIG['optflags']}
1503
+ debugflags = #{CONFIG['debugflags']}
1504
+ warnflags = #{CONFIG['warnflags']}
1505
+ CFLAGS = #{$static ? '' : CONFIG['CCDLFLAGS']} #$CFLAGS #$ARCH_FLAG
1506
+ INCFLAGS = -I. #$INCFLAGS#{$include_directories.collect{ |directory| ' -I' + directory}.join(' ')}
1507
+ DEFS = #{CONFIG['DEFS']}
1508
+ CPPFLAGS = #{extconf_h}#{$CPPFLAGS}
1509
+ CXXFLAGS = $(CFLAGS) #{CONFIG['CXXFLAGS']}
1510
+ ldflags = #{$LDFLAGS}
1511
+ dldflags = #{$DLDFLAGS}
1512
+ ARCH_FLAG = #{$ARCH_FLAG}
1513
+ DLDFLAGS = $(ldflags) $(dldflags)
1514
+ LDSHARED = #{CONFIG['LDSHARED']}
1515
+ LDSHAREDXX = #{config_string('LDSHAREDXX') || '$(LDSHARED)'}
1516
+ AR = #{CONFIG['AR']}
1517
+ EXEEXT = #{CONFIG['EXEEXT']}
1518
+
1519
+ RUBY_BASE_NAME = #{CONFIG['RUBY_BASE_NAME']}
1520
+ RUBY_INSTALL_NAME = #{CONFIG['RUBY_INSTALL_NAME']}
1521
+ RUBY_SO_NAME = #{CONFIG['RUBY_SO_NAME']}
1522
+ arch = #{CONFIG['arch']}
1523
+ sitearch = #{CONFIG['sitearch']}
1524
+ ruby_version = #{RbConfig::CONFIG['ruby_version']}
1525
+ ruby = #{$ruby}
1526
+ RUBY = $(ruby#{sep})
1527
+ RM = #{config_string('RM', &possible_command) || '$(RUBY) -run -e rm -- -f'}
1528
+ RM_RF = #{'$(RUBY) -run -e rm -- -rf'}
1529
+ RMDIRS = #{config_string('RMDIRS', &possible_command) || '$(RUBY) -run -e rmdir -- -p'}
1530
+ MAKEDIRS = #{config_string('MAKEDIRS', &possible_command) || '@$(RUBY) -run -e mkdir -- -p'}
1531
+ INSTALL = #{config_string('INSTALL', &possible_command) || '@$(RUBY) -run -e install -- -vp'}
1532
+ INSTALL_PROG = #{config_string('INSTALL_PROG') || '$(INSTALL) -m 0755'}
1533
+ INSTALL_DATA = #{config_string('INSTALL_DATA') || '$(INSTALL) -m 0644'}
1534
+ COPY = #{config_string('CP', &possible_command) || '@$(RUBY) -run -e cp -- -v'}
1535
+
1536
+ #### End of system configuration section. ####
1537
+
1538
+ preload = #{defined?($preload) && $preload ? $preload.join(' ') : ''}
1539
+ }
1540
+ if $nmake == ?b
1541
+ mk.each do |x|
1542
+ x.gsub!(/^(MAKEDIRS|INSTALL_(?:PROG|DATA))+\s*=.*\n/) do
1543
+ "!ifndef " + $1 + "\n" +
1544
+ $& +
1545
+ "!endif\n"
1546
+ end
1547
+ end
1548
+ end
1549
+ mk
1550
+ end
1551
+ # :startdoc:
1552
+
1553
+ def dummy_makefile(srcdir)
1554
+ configuration(srcdir) << <<RULES << CLEANINGS
1555
+ CLEANFILES = #{$cleanfiles.join(' ')}
1556
+ DISTCLEANFILES = #{$distcleanfiles.join(' ')}
1557
+
1558
+ all install static install-so install-rb: Makefile
1559
+ .PHONY: all install static install-so install-rb
1560
+ .PHONY: clean clean-so clean-rb
1561
+
1562
+ RULES
1563
+ end
1564
+
1565
+ def depend_rules(depend)
1566
+ suffixes = []
1567
+ depout = []
1568
+ cont = implicit = nil
1569
+ impconv = proc do
1570
+ COMPILE_RULES.each {|rule| depout << (rule % implicit[0]) << implicit[1]}
1571
+ implicit = nil
1572
+ end
1573
+ ruleconv = proc do |line|
1574
+ if implicit
1575
+ if /\A\t/ =~ line
1576
+ implicit[1] << line
1577
+ next
1578
+ else
1579
+ impconv[]
1580
+ end
1581
+ end
1582
+ if m = /\A\.(\w+)\.(\w+)(?:\s*:)/.match(line)
1583
+ suffixes << m[1] << m[2]
1584
+ implicit = [[m[1], m[2]], [m.post_match]]
1585
+ next
1586
+ elsif RULE_SUBST and /\A(?!\s*\w+\s*=)[$\w][^#]*:/ =~ line
1587
+ line.gsub!(%r"(\s)(?!\.)([^$(){}+=:\s\/\\,]+)(?=\s|\z)") {$1 + RULE_SUBST % $2}
1588
+ end
1589
+ depout << line
1590
+ end
1591
+ depend.each_line do |line|
1592
+ line.gsub!(/\.o\b/, ".#{$OBJEXT}")
1593
+ line.gsub!(/\$\((?:hdr|top)dir\)\/config.h/, $config_h)
1594
+ line.gsub!(%r"\$\(hdrdir\)/(?!ruby(?![^:;/\s]))(?=[-\w]+\.h)", '\&ruby/')
1595
+ if $nmake && /\A\s*\$\(RM|COPY\)/ =~ line
1596
+ line.gsub!(%r"[-\w\./]{2,}"){$&.tr("/", "\\")}
1597
+ line.gsub!(/(\$\((?!RM|COPY)[^:)]+)(?=\))/, '\1:/=\\')
1598
+ end
1599
+ if /(?:^|[^\\])(?:\\\\)*\\$/ =~ line
1600
+ (cont ||= []) << line
1601
+ next
1602
+ elsif cont
1603
+ line = (cont << line).join
1604
+ cont = nil
1605
+ end
1606
+ ruleconv.call(line)
1607
+ end
1608
+ if cont
1609
+ ruleconv.call(cont.join)
1610
+ elsif implicit
1611
+ impconv.call
1612
+ end
1613
+ unless suffixes.empty?
1614
+ depout.unshift(".SUFFIXES: ." + suffixes.uniq.join(" .") + "\n\n")
1615
+ end
1616
+ depout.unshift("$(OBJS): $(RUBY_EXTCONF_H)\n\n") if $extconf_h
1617
+ depout.flatten!
1618
+ depout
1619
+ end
1620
+
1621
+ def use_relative_paths
1622
+ $use_relative_paths = true
1623
+ yield if block_given?
1624
+ end
1625
+
1626
+ def all_headers_files_and_directories_with_subdirectories_for( directory )
1627
+
1628
+ headers = Dir.glob( directory + '/**/*.h' )
1629
+ files = Array.new
1630
+ SRC_EXT.each do |this_ext|
1631
+ files.concat( Dir.glob( directory + '/**/*.' + this_ext ) )
1632
+ end
1633
+
1634
+ include_directories = headers.collect { |file| File.dirname( file ) }.uniq
1635
+ file_directories = files.collect { |file| File.dirname( file ) }.uniq
1636
+
1637
+ [ headers, files, include_directories ].each do |this_pathset|
1638
+ this_pathset.collect { |path| File.expand_path( path ) }
1639
+ end
1640
+
1641
+ return headers, files, file_directories, include_directories
1642
+
1643
+ end
1644
+
1645
+ # Generates the Makefile for your extension, passing along any options and
1646
+ # preprocessor constants that you may have generated through other methods.
1647
+ #
1648
+ # The +target+ name should correspond the name of the global function name
1649
+ # defined within your C extension, minus the 'Init_'. For example, if your
1650
+ # C extension is defined as 'Init_foo', then your target would simply be 'foo'.
1651
+ #
1652
+ # If any '/' characters are present in the target name, only the last name
1653
+ # is interpreted as the target name, and the rest are considered toplevel
1654
+ # directory names, and the generated Makefile will be altered accordingly to
1655
+ # follow that directory structure.
1656
+ #
1657
+ # For example, if you pass 'test/foo' as a target name, your extension will
1658
+ # be installed under the 'test' directory. This means that in order to
1659
+ # load the file within a Ruby program later, that directory structure will
1660
+ # have to be followed, e.g. "require 'test/foo'".
1661
+ #
1662
+ # The +srcprefix+ should be used when your source files are not in the same
1663
+ # directory as your build script. This will not only eliminate the need for
1664
+ # you to manually copy the source files into the same directory as your build
1665
+ # script, but it also sets the proper +target_prefix+ in the generated
1666
+ # Makefile.
1667
+ #
1668
+ # Setting the +target_prefix+ will, in turn, install the generated binary in
1669
+ # a directory under your RbConfig::CONFIG['sitearchdir'] that mimics your local
1670
+ # filesystem when you run 'make install'.
1671
+ #
1672
+ # For example, given the following file tree:
1673
+ #
1674
+ # ext/
1675
+ # extconf.rb
1676
+ # test/
1677
+ # foo.c
1678
+ #
1679
+ # And given the following code:
1680
+ #
1681
+ # create_makefile('test/foo', 'test')
1682
+ #
1683
+ # That will set the +target_prefix+ in the generated Makefile to 'test'. That,
1684
+ # in turn, will create the following file tree when installed via the
1685
+ # 'make install' command:
1686
+ #
1687
+ # /path/to/ruby/sitearchdir/test/foo.so
1688
+ #
1689
+ # It is recommended that you use this approach to generate your makefiles,
1690
+ # instead of copying files around manually, because some third party
1691
+ # libraries may depend on the +target_prefix+ being set properly.
1692
+ #
1693
+ # The +srcprefix+ argument can be used to override the default source
1694
+ # directory, i.e. the current directory . It is included as part of the VPATH
1695
+ # and added to the list of INCFLAGS.
1696
+ #
1697
+ def create_makefile(target, srcprefix = nil)
1698
+ $target = target
1699
+ libpath = $DEFLIBPATH|$LIBPATH
1700
+ message "creating Makefile\n"
1701
+ rm_f "conftest*"
1702
+ if CONFIG["DLEXT"] == $OBJEXT
1703
+ for lib in libs = $libs.split
1704
+ lib.sub!(/-l(.*)/, %%"lib\\1.#{$LIBEXT}"%)
1705
+ end
1706
+ $defs.push(format("-DEXTLIB='%s'", libs.join(",")))
1707
+ end
1708
+
1709
+ if target.include?('/')
1710
+ target_prefix, target = File.split(target)
1711
+ target_prefix[0,0] = '/'
1712
+ else
1713
+ target_prefix = ""
1714
+ end
1715
+
1716
+ srcprefix ||= "$(srcdir)/#{srcprefix}".chomp('/')
1717
+ RbConfig.expand(srcdir = srcprefix.dup)
1718
+
1719
+ ext = ".#{$OBJEXT}"
1720
+ if not $objs
1721
+ # get sources - we want anything with our SRC_EXT in ext/target or any subdirectory
1722
+
1723
+ headers, files, $file_directories, $include_directories = all_headers_files_and_directories_with_subdirectories_for( srcdir )
1724
+ srcs = $srcs || files
1725
+
1726
+ # srcs = $srcs || Dir[File.join(srcdir, "*.{#{SRC_EXT.join(%q{,})}}")]
1727
+
1728
+ objs = srcs.inject(Hash.new {[]}) {|h, f| h[File.dirname( f ) + '/' + File.basename(f, ".*") << ext] <<= f; h}
1729
+ $objs = objs.keys
1730
+ # unless objs.delete_if {|b, f| f.size == 1}.empty?
1731
+ # dups = objs.sort.map {|b, f|
1732
+ # "#{b[/.*\./]}{#{f.collect {|n| n[/([^.]+)\z/]}.join(',')}}"
1733
+ # }
1734
+ # abort "source files duplication - #{dups.join(", ")}"
1735
+ # end
1736
+ else
1737
+ $objs.collect! {|o| File.basename(o, ".*") << ext} unless $OBJEXT == "o"
1738
+ srcs = $srcs || $objs.collect {|o| o.chomp(ext) << ".c"}
1739
+ end
1740
+ $srcs = srcs
1741
+
1742
+ target = nil if $objs.empty?
1743
+
1744
+ if target and EXPORT_PREFIX
1745
+ if File.exist?(File.join(srcdir, target + '.def'))
1746
+ deffile = "$(srcdir)/$(TARGET).def"
1747
+ unless EXPORT_PREFIX.empty?
1748
+ makedef = %{-pe "$_.sub!(/^(?=\\w)/,'#{EXPORT_PREFIX}') unless 1../^EXPORTS$/i"}
1749
+ end
1750
+ else
1751
+ makedef = %{-e "puts 'EXPORTS', '#{EXPORT_PREFIX}Init_$(TARGET)'"}
1752
+ end
1753
+ if makedef
1754
+ $cleanfiles << '$(DEFFILE)'
1755
+ origdef = deffile
1756
+ deffile = "$(TARGET)-$(arch).def"
1757
+ end
1758
+ end
1759
+ origdef ||= ''
1760
+
1761
+ if $extout and $INSTALLFILES
1762
+ $cleanfiles.concat($INSTALLFILES.collect {|files, dir|File.join(dir, files.sub(/\A\.\//, ''))})
1763
+ $distcleandirs.concat($INSTALLFILES.collect {|files, dir| dir})
1764
+ end
1765
+
1766
+ if $extmk and not $extconf_h
1767
+ create_header
1768
+ end
1769
+
1770
+ libpath = libpathflag(libpath)
1771
+
1772
+ dllib = target ? "$(TARGET).#{CONFIG['DLEXT']}" : ""
1773
+ staticlib = target ? "$(TARGET).#$LIBEXT" : ""
1774
+ mfile = open("Makefile", "wb")
1775
+ conf = configuration(srcprefix)
1776
+ conf = yield(conf) if block_given?
1777
+ mfile.puts(conf)
1778
+ mfile.print "
1779
+ libpath = #{($DEFLIBPATH|$LIBPATH).join(" ")}
1780
+ LIBPATH = #{libpath}
1781
+ DEFFILE = #{deffile}
1782
+
1783
+ CLEANFILES = #{$cleanfiles.join(' ')}
1784
+ DISTCLEANFILES = #{$distcleanfiles.join(' ')}
1785
+ DISTCLEANDIRS = #{$distcleandirs.join(' ')}
1786
+
1787
+ extout = #{$extout && $extout.quote}
1788
+ extout_prefix = #{$extout_prefix}
1789
+ target_prefix = #{target_prefix}
1790
+ LOCAL_LIBS = #{$LOCAL_LIBS}
1791
+ LIBS = #{$LIBRUBYARG} #{$libs} #{$LIBS}
1792
+ SRCS = #{srcs.collect(&File.method(:basename)).join(' ')}
1793
+ OBJS = #{$objs.collect(&File.method(:basename)).join(' ')}
1794
+ TARGET = #{target}
1795
+ DLLIB = #{dllib}
1796
+ EXTSTATIC = #{$static || ""}
1797
+ STATIC_LIB = #{staticlib unless $static.nil?}
1798
+ #{!$extout && defined?($installed_list) ? "INSTALLED_LIST = #{$installed_list}\n" : ""}
1799
+ " #"
1800
+ # TODO: fixme
1801
+ install_dirs.each {|d| mfile.print("%-14s= %s\n" % d) if /^[[:upper:]]/ =~ d[0]}
1802
+ n = ($extout ? '$(RUBYARCHDIR)/' : '') + '$(TARGET)'
1803
+ mfile.print "
1804
+ TARGET_SO = #{($extout ? '$(RUBYARCHDIR)/' : '')}$(DLLIB)
1805
+ CLEANLIBS = #{n}.#{CONFIG['DLEXT']} #{config_string('cleanlibs') {|t| t.gsub(/\$\*/) {n}}}
1806
+ CLEANOBJS = *.#{$OBJEXT} #{config_string('cleanobjs') {|t| t.gsub(/\$\*/, "$(TARGET)#{deffile ? '-$(arch)': ''}")} if target} *.bak
1807
+
1808
+ all: #{$extout ? "install" : target ? "$(DLLIB)" : "Makefile"}
1809
+ static: $(STATIC_LIB)#{$extout ? " install-rb" : ""}
1810
+ .PHONY: all install static install-so install-rb
1811
+ .PHONY: clean clean-so clean-rb
1812
+ "
1813
+ mfile.print CLEANINGS
1814
+ fsep = config_string('BUILD_FILE_SEPARATOR') {|s| s unless s == "/"}
1815
+ if fsep
1816
+ sep = ":/=#{fsep}"
1817
+ fseprepl = proc {|s|
1818
+ s = s.gsub("/", fsep)
1819
+ s = s.gsub(/(\$\(\w+)(\))/) {$1+sep+$2}
1820
+ s = s.gsub(/(\$\{\w+)(\})/) {$1+sep+$2}
1821
+ }
1822
+ else
1823
+ fseprepl = proc {|s| s}
1824
+ sep = ""
1825
+ end
1826
+ dirs = []
1827
+ mfile.print "install: install-so install-rb\n\n"
1828
+ sodir = (dir = "$(RUBYARCHDIR)").dup
1829
+ mfile.print("install-so: ")
1830
+ if target
1831
+ f = "$(DLLIB)"
1832
+ dest = "#{dir}/#{f}"
1833
+ mfile.puts dir, "install-so: #{dest}"
1834
+ if $extout
1835
+ mfile.print "clean-so::\n"
1836
+ mfile.print "\t@-$(RM) #{fseprepl[dest]}\n"
1837
+ mfile.print "\t@-$(RMDIRS) #{fseprepl[dir]}\n"
1838
+ else
1839
+ mfile.print "#{dest}: #{f}\n\t@-$(MAKEDIRS) $(@D#{sep})\n"
1840
+ mfile.print "\t$(INSTALL_PROG) #{fseprepl[f]} $(@D#{sep})\n"
1841
+ if defined?($installed_list)
1842
+ mfile.print "\t@echo #{dir}/#{File.basename(f)}>>$(INSTALLED_LIST)\n"
1843
+ end
1844
+ end
1845
+ else
1846
+ mfile.puts "Makefile"
1847
+ end
1848
+ mfile.print("install-rb: pre-install-rb install-rb-default\n")
1849
+ mfile.print("install-rb-default: pre-install-rb-default\n")
1850
+ mfile.print("pre-install-rb: Makefile\n")
1851
+ mfile.print("pre-install-rb-default: Makefile\n")
1852
+ for sfx, i in [["-default", [["lib/**/*.rb", "$(RUBYLIBDIR)", "lib"]]], ["", $INSTALLFILES]]
1853
+ files = install_files(mfile, i, nil, srcprefix) or next
1854
+ for dir, *files in files
1855
+ unless dirs.include?(dir)
1856
+ dirs << dir
1857
+ mfile.print "pre-install-rb#{sfx}: #{dir}\n"
1858
+ end
1859
+ for f in files
1860
+ dest = "#{dir}/#{File.basename(f)}"
1861
+ mfile.print("install-rb#{sfx}: #{dest}\n")
1862
+ mfile.print("#{dest}: #{f}\n\t@-$(MAKEDIRS) $(@D#{sep})\n")
1863
+ mfile.print("\t$(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $(@D#{sep})\n")
1864
+ if defined?($installed_list) and !$extout
1865
+ mfile.print("\t@echo #{dest}>>$(INSTALLED_LIST)\n")
1866
+ end
1867
+ if $extout
1868
+ mfile.print("clean-rb#{sfx}::\n")
1869
+ mfile.print("\t@-$(RM) #{fseprepl[dest]}\n")
1870
+ end
1871
+ end
1872
+ end
1873
+ if $extout
1874
+ dirs.uniq!
1875
+ unless dirs.empty?
1876
+ mfile.print("clean-rb#{sfx}::\n")
1877
+ for dir in dirs.sort_by {|d| -d.count('/')}
1878
+ mfile.print("\t@-$(RMDIRS) #{fseprepl[dir]}\n")
1879
+ end
1880
+ end
1881
+ end
1882
+ end
1883
+ dirs.unshift(sodir) if target and !dirs.include?(sodir)
1884
+ dirs.each {|d| mfile.print "#{d}:\n\t$(MAKEDIRS) $@\n"}
1885
+
1886
+ mfile.print <<-SITEINSTALL
1887
+
1888
+ site-install: site-install-so site-install-rb
1889
+ site-install-so: install-so
1890
+ site-install-rb: install-rb
1891
+
1892
+ SITEINSTALL
1893
+
1894
+ return unless target
1895
+
1896
+ mfile.puts SRC_EXT.collect {|e| ".path.#{e} = $(VPATH)"} if $nmake == ?b
1897
+ mfile.print ".SUFFIXES: .#{SRC_EXT.join(' .')} .#{$OBJEXT}\n"
1898
+ mfile.print "\n"
1899
+
1900
+ CXX_EXT.each do |e|
1901
+ COMPILE_RULES.each do |rule|
1902
+ mfile.printf(rule, e, $OBJEXT)
1903
+ mfile.printf("\n\t%s\n\n", COMPILE_CXX)
1904
+ end
1905
+ end
1906
+ %w[c].each do |e|
1907
+ COMPILE_RULES.each do |rule|
1908
+ mfile.printf(rule, e, $OBJEXT)
1909
+ mfile.printf("\n\t%s\n\n", COMPILE_C)
1910
+ end
1911
+ end
1912
+
1913
+ mfile.print "$(RUBYARCHDIR)/" if $extout
1914
+ mfile.print "$(DLLIB): "
1915
+ mfile.print "$(DEFFILE) " if makedef
1916
+ mfile.print "$(OBJS) Makefile\n"
1917
+ mfile.print "\t@-$(RM) $(@#{sep})\n"
1918
+ mfile.print "\t@-$(MAKEDIRS) $(@D)\n" if $extout
1919
+ link_so = LINK_SO.gsub(/^/, "\t")
1920
+ if srcs.any?(&%r"\.(?:#{CXX_EXT.join('|')})\z".method(:===))
1921
+ link_so = link_so.sub(/\bLDSHARED\b/, '\&XX')
1922
+ end
1923
+ mfile.print link_so, "\n\n"
1924
+ unless $static.nil?
1925
+ mfile.print "$(STATIC_LIB): $(OBJS)\n\t@-$(RM) $(@#{sep})\n\t"
1926
+ mfile.print "$(AR) #{config_string('ARFLAGS') || 'cru '}$@ $(OBJS)"
1927
+ config_string('RANLIB') do |ranlib|
1928
+ mfile.print "\n\t@-#{ranlib} $(DLLIB) 2> /dev/null || true"
1929
+ end
1930
+ end
1931
+ mfile.print "\n\n"
1932
+ if makedef
1933
+ mfile.print "$(DEFFILE): #{origdef}\n"
1934
+ mfile.print "\t$(RUBY) #{makedef} #{origdef} > $@\n\n"
1935
+ end
1936
+
1937
+ depend = File.join(srcdir, "depend")
1938
+ if File.exist?(depend)
1939
+ mfile.print("###\n", *depend_rules(File.read(depend)))
1940
+ else
1941
+ headers = %w[$(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h]
1942
+ if RULE_SUBST
1943
+ headers.each {|h| h.sub!(/.*/, &RULE_SUBST.method(:%))}
1944
+ end
1945
+ headers << $config_h
1946
+ headers << '$(RUBY_EXTCONF_H)' if $extconf_h
1947
+ mfile.print "$(OBJS): ", headers.join(' '), "\n"
1948
+ end
1949
+
1950
+ $makefile_created = true
1951
+ ensure
1952
+ mfile.close if mfile
1953
+ end
1954
+
1955
+ # :stopdoc:
1956
+
1957
+ def init_mkmf(config = CONFIG)
1958
+ $makefile_created = false
1959
+ $arg_config = []
1960
+ $enable_shared = config['ENABLE_SHARED'] == 'yes'
1961
+ $defs = []
1962
+ $extconf_h = nil
1963
+ $CFLAGS = with_config("cflags", arg_config("CFLAGS", config["CFLAGS"])).dup
1964
+ $ARCH_FLAG = with_config("arch_flag", arg_config("ARCH_FLAG", config["ARCH_FLAG"])).dup
1965
+ $CPPFLAGS = with_config("cppflags", arg_config("CPPFLAGS", config["CPPFLAGS"])).dup
1966
+ $LDFLAGS = with_config("ldflags", arg_config("LDFLAGS", config["LDFLAGS"])).dup
1967
+ $INCFLAGS = "-I$(arch_hdrdir)"
1968
+ $INCFLAGS << " -I$(hdrdir)/ruby/backward" unless $extmk
1969
+ $INCFLAGS << " -I$(hdrdir) -I$(srcdir)"
1970
+ $DLDFLAGS = with_config("dldflags", arg_config("DLDFLAGS", config["DLDFLAGS"])).dup
1971
+ $LIBEXT = config['LIBEXT'].dup
1972
+ $OBJEXT = config["OBJEXT"].dup
1973
+ $LIBS = "#{config['LIBS']} #{config['DLDLIBS']}"
1974
+ $LIBRUBYARG = ""
1975
+ $LIBRUBYARG_STATIC = config['LIBRUBYARG_STATIC']
1976
+ $LIBRUBYARG_SHARED = config['LIBRUBYARG_SHARED']
1977
+ $DEFLIBPATH = [$extmk ? "$(topdir)" : "$(libdir)"]
1978
+ $DEFLIBPATH.unshift(".")
1979
+ $LIBPATH = []
1980
+ $INSTALLFILES = []
1981
+ $NONINSTALLFILES = [/~\z/, /\A#.*#\z/, /\A\.#/, /\.bak\z/i, /\.orig\z/, /\.rej\z/, /\.l[ao]\z/, /\.o\z/]
1982
+ $VPATH = %w[$(srcdir) $(arch_hdrdir)/ruby $(hdrdir)/ruby]
1983
+
1984
+ $objs = nil
1985
+ $srcs = nil
1986
+ $libs = ""
1987
+ if $enable_shared or RbConfig.expand(config["LIBRUBY"].dup) != RbConfig.expand(config["LIBRUBY_A"].dup)
1988
+ $LIBRUBYARG = config['LIBRUBYARG']
1989
+ end
1990
+
1991
+ $LOCAL_LIBS = ""
1992
+
1993
+ $cleanfiles = config_string('CLEANFILES') {|s| Shellwords.shellwords(s)} || []
1994
+ $cleanfiles << "mkmf.log"
1995
+ $distcleanfiles = config_string('DISTCLEANFILES') {|s| Shellwords.shellwords(s)} || []
1996
+ $distcleandirs = config_string('DISTCLEANDIRS') {|s| Shellwords.shellwords(s)} || []
1997
+
1998
+ $extout ||= nil
1999
+ $extout_prefix ||= nil
2000
+
2001
+ $arg_config.clear
2002
+ dir_config("opt")
2003
+ end
2004
+
2005
+ FailedMessage = <<MESSAGE
2006
+ Could not create Makefile due to some reason, probably lack of
2007
+ necessary libraries and/or headers. Check the mkmf.log file for more
2008
+ details. You may need configuration options.
2009
+
2010
+ Provided configuration options:
2011
+ MESSAGE
2012
+
2013
+ # Returns whether or not the Makefile was successfully generated. If not,
2014
+ # the script will abort with an error message.
2015
+ #
2016
+ # Internal use only.
2017
+ #
2018
+ def mkmf_failed(path)
2019
+ unless $makefile_created or File.exist?("Makefile")
2020
+ opts = $arg_config.collect {|t, n| "\t#{t}#{n ? "=#{n}" : ""}\n"}
2021
+ abort "*** #{path} failed ***\n" + FailedMessage + opts.join
2022
+ end
2023
+ end
2024
+
2025
+ # :startdoc:
2026
+
2027
+ init_mkmf
2028
+
2029
+ $make = with_config("make-prog", ENV["MAKE"] || "make")
2030
+ make, = Shellwords.shellwords($make)
2031
+ $nmake = nil
2032
+ case
2033
+ when $mswin
2034
+ $nmake = ?m if /nmake/i =~ make
2035
+ when $bccwin
2036
+ $nmake = ?b if /Borland/i =~ `#{make} -h`
2037
+ end
2038
+
2039
+ RbConfig::CONFIG["srcdir"] = CONFIG["srcdir"] =
2040
+ $srcdir = arg_config("--srcdir", File.dirname($0))
2041
+ $configure_args["--topsrcdir"] ||= $srcdir
2042
+ if $curdir = arg_config("--curdir")
2043
+ RbConfig.expand(curdir = $curdir.dup)
2044
+ else
2045
+ curdir = $curdir = "."
2046
+ end
2047
+ unless File.expand_path(RbConfig::CONFIG["topdir"]) == File.expand_path(curdir)
2048
+ CONFIG["topdir"] = $curdir
2049
+ RbConfig::CONFIG["topdir"] = curdir
2050
+ end
2051
+ $configure_args["--topdir"] ||= $curdir
2052
+ $ruby = arg_config("--ruby", File.join(RbConfig::CONFIG["bindir"], CONFIG["ruby_install_name"]))
2053
+
2054
+ split = Shellwords.method(:shellwords).to_proc
2055
+
2056
+ EXPORT_PREFIX = config_string('EXPORT_PREFIX') {|s| s.strip}
2057
+
2058
+ hdr = ['#include "ruby.h"' "\n"]
2059
+ config_string('COMMON_MACROS') do |s|
2060
+ Shellwords.shellwords(s).each do |w|
2061
+ hdr << "#define " + w.split(/=/, 2).join(" ")
2062
+ end
2063
+ end
2064
+ config_string('COMMON_HEADERS') do |s|
2065
+ Shellwords.shellwords(s).each {|w| hdr << "#include <#{w}>"}
2066
+ end
2067
+ COMMON_HEADERS = hdr.join("\n")
2068
+ COMMON_LIBS = config_string('COMMON_LIBS', &split) || []
2069
+
2070
+ COMPILE_RULES = config_string('COMPILE_RULES', &split) || %w[.%s.%s:]
2071
+ RULE_SUBST = config_string('RULE_SUBST')
2072
+ COMPILE_C = config_string('COMPILE_C') || '$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<'
2073
+ COMPILE_CXX = config_string('COMPILE_CXX') || '$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<'
2074
+ TRY_LINK = config_string('TRY_LINK') ||
2075
+ "$(CC) #{OUTFLAG}conftest $(INCFLAGS) $(CPPFLAGS) " \
2076
+ "$(CFLAGS) $(src) $(LIBPATH) $(LDFLAGS) $(ARCH_FLAG) $(LOCAL_LIBS) $(LIBS)"
2077
+ LINK_SO = config_string('LINK_SO') ||
2078
+ if CONFIG["DLEXT"] == $OBJEXT
2079
+ "ld $(DLDFLAGS) -r -o $@ $(OBJS)\n"
2080
+ else
2081
+ "$(LDSHARED) #{OUTFLAG}$@ $(OBJS) " \
2082
+ "$(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)"
2083
+ end
2084
+ LIBPATHFLAG = config_string('LIBPATHFLAG') || ' -L"%s"'
2085
+ RPATHFLAG = config_string('RPATHFLAG') || ''
2086
+ LIBARG = config_string('LIBARG') || '-l%s'
2087
+ MAIN_DOES_NOTHING = config_string('MAIN_DOES_NOTHING') || 'int main() {return 0;}'
2088
+ UNIVERSAL_INTS = config_string('UNIVERSAL_INTS') {|s| Shellwords.shellwords(s)} ||
2089
+ %w[int short long long\ long]
2090
+
2091
+ sep = config_string('BUILD_FILE_SEPARATOR') {|s| ":/=#{s}" if s != "/"} || ""
2092
+ CLEANINGS = "
2093
+ clean-rb-default::
2094
+ clean-rb::
2095
+ clean-so::
2096
+ clean: clean-so clean-rb-default clean-rb
2097
+ \t\t@-$(RM) $(CLEANLIBS#{sep}) $(CLEANOBJS#{sep}) $(CLEANFILES#{sep})
2098
+
2099
+ distclean-rb-default::
2100
+ distclean-rb::
2101
+ distclean-so::
2102
+ distclean: clean distclean-so distclean-rb-default distclean-rb
2103
+ \t\t@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
2104
+ \t\t@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES#{sep})
2105
+ \t\t@-$(RMDIRS) $(DISTCLEANDIRS#{sep})
2106
+
2107
+ realclean: distclean
2108
+ "
2109
+
2110
+ if not $extmk and /\A(extconf|makefile).rb\z/ =~ File.basename($0)
2111
+ END {mkmf_failed($0)}
2112
+ end