21 alias $PROGRAM_NAME $0
30 srcdir = File.dirname(File.dirname(__FILE__))
32 $:.unshift(srcdir, File.expand_path("lib", srcdir))
38 require 'optparse/shellwords'
41 @quote ||= /human|os2|macos/ =~ (CROSS_COMPILING || RUBY_PLATFORM)
45 def relative_from(path, base)
46 dir = File.join(path, "")
47 if File.expand_path(dir) == File.expand_path(dir, base)
54 def extract_makefile(makefile, keep = true)
55 m = File.read(makefile)
56 if !(target = m[/^TARGET[ \t]*=[ \t]*(\S*)/, 1])
60 m.scan(/^install-rb-default:[ \t]*(\S+)\n\1:[ \t]*(\S+)/) {installrb[$2] = $1}
61 oldrb = installrb.keys.sort
62 newrb = install_rb(nil, "").collect {|d, *f| f}.flatten.sort
63 if target_prefix = m[/^target_prefix[ \t]*=[ \t]*\/(.*)/, 1]
64 target = "#{target_prefix}/#{target}"
68 newrb.each {|f| installrb.delete(f)}
69 unless installrb.empty?
71 install_dirs(target_prefix).each {|var, val| config[var] = val}
72 FileUtils.rm_f(installrb.values.collect {|f| Config.expand(f, config)}, :verbose => true)
78 $extconf_h = m[/^RUBY_EXTCONF_H[ \t]*=[ \t]*(\S+)/, 1]
79 $static ||= m[/^EXTSTATIC[ \t]*=[ \t]*(\S+)/, 1] || false
80 /^STATIC_LIB[ \t]*=[ \t]*\S+/ =~ m or $static = nil
81 $preload = Shellwords.shellwords(m[/^preload[ \t]*=[ \t]*(.*)/, 1] || "")
82 $DLDFLAGS += " " + (m[/^DLDFLAGS[ \t]*=[ \t]*(.*)/, 1] || "")
83 if s = m[/^LIBS[ \t]*=[ \t]*(.*)/, 1]
84 s.sub!(/^#{Regexp.quote($LIBRUBYARG)} */, "")
85 s.sub!(/ *#{Regexp.quote($LIBS)}$/, "")
88 $objs = (m[/^OBJS[ \t]*=[ \t](.*)/, 1] || "").split
89 $srcs = (m[/^SRCS[ \t]*=[ \t](.*)/, 1] || "").split
90 $LOCAL_LIBS = m[/^LOCAL_LIBS[ \t]*=[ \t]*(.*)/, 1] || ""
91 $LIBPATH = Shellwords.shellwords(m[/^libpath[ \t]*=[ \t]*(.*)/, 1] || "") - %w[$(libdir) $(topdir)]
96 print "#{$message} #{target}\n"
98 if $force_static or $static_ext[target]
105 return true if $nodynamic and not $static
108 FileUtils.mkpath target unless File.directory?(target)
111 FileUtils.mkpath target unless File.directory?(target)
113 top_srcdir = $top_srcdir
115 mk_srcdir = CONFIG["srcdir"]
116 mk_topdir = CONFIG["topdir"]
117 prefix = "../" * (target.count("/")+1)
118 $hdrdir = $top_srcdir = relative_from(top_srcdir, prefix)
119 $topdir = prefix + $topdir
122 $srcdir = File.join($top_srcdir, "ext", $mdir)
126 $compiled[target] = false
127 makefile = "./Makefile"
128 ok = File.exist?(makefile)
130 Config::CONFIG["hdrdir"] = $hdrdir
131 Config::CONFIG["srcdir"] = $srcdir
132 Config::CONFIG["topdir"] = $topdir
133 CONFIG["hdrdir"] = ($hdrdir == top_srcdir) ? top_srcdir : "$(topdir)"+top_srcdir[2..-1]
134 CONFIG["srcdir"] = "$(hdrdir)/ext/#{$mdir}"
135 CONFIG["topdir"] = $topdir
138 ok &&= extract_makefile(makefile)
139 if (($extconf_h && !File.exist?($extconf_h)) ||
140 !(t = modified?(makefile, MTIMES)) ||
141 ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb", "#{$srcdir}/depend"].any? {|f| modified?(f, [t])})
145 Logging::logfile 'mkmf.log'
147 if File.exist?($0 = "#{$srcdir}/makefile.rb")
149 elsif File.exist?($0 = "#{$srcdir}/extconf.rb")
152 create_makefile(target)
154 $defs << "-DRUBY_EXPORT" if $static
155 ok = File.exist?(makefile)
165 ok = yield(ok) if block_given?
167 open(makefile, "w") do |f|
168 f.print dummy_makefile(CONFIG["srcdir"])
172 args = sysquote($mflags)
173 unless $destdir.to_s.empty? or $mflags.include?("DESTDIR")
174 args += [sysquote("DESTDIR=" + relative_from($destdir, "../"+prefix))]
177 args += ["static"] unless $clean
178 $extlist.push [$static, $target, File.basename($target), $preload]
180 unless system($make, *args)
181 $ignore or $continue or return false
183 $compiled[target] = true
184 if $clean and $clean != true
185 File.unlink(makefile) rescue nil
192 $extflags = ($extflags.split | $DLDFLAGS.split | $LDFLAGS.split).join(" ")
194 $extlibs = merge_libs($extlibs, $libs.split, $LOCAL_LIBS.split)
198 Config::CONFIG["srcdir"] = $top_srcdir
199 Config::CONFIG["topdir"] = topdir
200 CONFIG["srcdir"] = mk_srcdir
201 CONFIG["topdir"] = mk_topdir
202 CONFIG.delete("hdrdir")
203 $hdrdir = $top_srcdir = top_srcdir
209 target = File.dirname(target)
210 rescue SystemCallError
216 def compiled?(target)
224 $optparser ||= OptionParser.new do |opts|
225 opts.on('-n') {$dryrun = true}
226 opts.on('--[no-]extension [EXTS]', Array) do |v|
227 $extension = (v == false ? [] : v)
229 opts.on('--[no-]extstatic [STATIC]', Array) do |v|
230 if ($extstatic = v) == false
233 $force_static = true if $extstatic.delete("static")
234 $extstatic = nil if $extstatic.empty?
237 opts.on('--dest-dir=DIR') do |v|
240 opts.on('--extout=DIR') do |v|
241 $extout = (v unless v.empty?)
243 opts.on('--make=MAKE') do |v|
246 opts.on('--make-flags=FLAGS', '--mflags', Shellwords) do |v|
247 v.grep(/\A([-\w]+)=(.*)/) {$configure_args["--#{$1}"] = $2}
249 arg.insert(0, '-') if /\A[^-][^=]*\Z/ =~ arg
253 opts.on('--message [MESSAGE]', String) do |v|
258 $optparser.parse!(ARGV)
259 rescue OptionParser::InvalidOption => e
260 retry if /^--/ =~ e.args[0]
267 $make, *rest = Shellwords.shellwords($make)
268 $mflags.unshift(*rest) unless rest.empty?
270 def $mflags.set?(flag)
271 grep(/\A-(?!-).*#{'%c' % flag}/i) { return true }
274 def $mflags.defined?(var)
275 grep(/\A#{var}=(.*)/) {return $1}
282 $mflags.unshift '-n' if $dryrun
285 $continue = $mflags.set?(?k)
287 $extout = '$(topdir)/'+$extout
288 $extout_prefix = $extout ? "$(extout)$(target_prefix)/" : ""
289 $mflags << "extout=#$extout" << "extout_prefix=#$extout_prefix"
295 if target = ARGV.shift and /^[a-z-]+$/ =~ target
297 target = target.sub(/^(dist|real)(?=(?:clean)?$)/, '')
301 $clean = $1 ? $1[0] : true
305 $mflags.unshift("INSTALL_PROG=install -c -p -m 0755",
306 "INSTALL_DATA=install -c -p -m 0644",
307 "MAKEDIRS=mkdir -p") if $dryrun
312 $message = target.sub(/^(\w+)e?\b/, '\1ing').tr('-', ' ')
314 $message = "compiling"
318 EXEEXT = CONFIG['EXEEXT']
320 $ruby = CONFIG['MINIRUBY']
321 elsif sep = config_string('BUILD_FILE_SEPARATOR')
322 $ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT
324 $ruby = '$(topdir)/miniruby' + EXEEXT
326 $ruby << " -I'$(topdir)' -I'$(hdrdir)/lib'"
327 $config_h = '$(topdir)/config.h'
329 MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)}
331 # get static-link modules
334 $extstatic.each do |target|
335 target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM
336 $static_ext[target] = $static_ext.size
339 for dir in ["ext", File::join($top_srcdir, "ext")]
340 setup = File::join(dir, CONFIG['setup'])
343 while line = f.gets()
345 line.sub!(/#.*$/, '')
346 next if /^\s*$/ =~ line
347 target, opt = line.split(nil, 3)
348 if target == 'option'
355 target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM
356 $static_ext[target] = $static_ext.size
363 end unless $extstatic
365 ext_prefix = "#{$top_srcdir}/ext"
366 exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t}
368 exts |= $extension.select {|d| File.directory?("#{ext_prefix}/#{d}")}
370 withes, withouts = %w[--with --without].collect {|w|
371 if not (w = %w[-extensions -ext].collect {|opt|arg_config(w+opt)}).any?
373 elsif (w = w.grep(String)).empty?
376 proc {|c1| w.collect {|opt| opt.split(/,/)}.flatten.any?(&c1)}
380 cond1 = proc {|n| File.fnmatch(n, ext, File::FNM_PATHNAME)}
381 withes.call(cond1) or !withouts.call(cond1)
383 exts |= Dir.glob("#{ext_prefix}/*/**/extconf.rb").collect {|d|
385 d.slice!(0, ext_prefix.length + 1)
388 with_config(ext, &cond)
393 extout = Config.expand("#{$extout}", Config::CONFIG.merge("topdir"=>$topdir))
395 FileUtils.mkpath(extout)
400 FileUtils::makedirs('ext')
403 $hdrdir = $top_srcdir = relative_from(srcdir, $topdir = "..")
407 $hdrdir = $top_srcdir = srcdir
410 extinit = Struct.new(:c, :o) {
412 super("#{src}.c", "#{src}.#{$OBJEXT}")
416 FileUtils.rm_f(extinit.to_a) if $clean
419 Dir.rmdir('ext') rescue nil
420 FileUtils.rm_rf(extout) if $extout
430 unless $extlist.empty?
431 $extinit << "\n" unless $extinit.empty?
436 if r and !(r -= built).empty?
438 if (while l > 0; break true if r.include?(list[l-=1][1]) end)
439 list.insert(l + 1, e)
443 f = format("%s/%s.%s", s, i, $LIBEXT)
445 $extinit << " init(Init_#{i}, \"#{t}.so\");\n"
446 $extobjs << "ext/#{f} "
454 #define init(func, name) {void func _((void)); ruby_init_ext(name, func);}
456 void ruby_init_ext _((const char *name, void (*init)(void)));
458 void Init_ext _((void))\n{\n#$extinit}
460 if !modified?(extinit.c, MTIMES) || IO.read(extinit.c) != src
461 open(extinit.c, "w") {|f| f.print src}
464 $extobjs = "ext/#{extinit.o} #{$extobjs}"
465 if RUBY_PLATFORM =~ /m68k-human|beos/
466 $extflags.delete("-L/usr/local/lib")
468 $extpath.delete("$(topdir)")
469 $extflags = libpathflag($extpath) << " " << $extflags.strip
471 ['LIBRUBY_SO_UPDATE', '$(LIBRUBY_EXTS)'],
473 [enable_config("shared", $enable_shared) ? 'DLDOBJS' : 'EXTOBJS', $extobjs],
474 ['EXTLIBS', $extlibs.join(' ')], ['EXTLDFLAGS', $extflags]
476 "#{n}=#{v}" if v and !(v = v.strip).empty?
482 FileUtils.rm_f(extinit.to_a)
485 %w[RUBY RUBYW STATIC_RUBY].each {|r|
487 if r = arg_config("--"+r.downcase) || config_string(r+"_INSTALL_NAME")
488 rubies << Config.expand(r+=EXEEXT)
489 $mflags << "#{n}=#{r}"
494 unless $destdir.to_s.empty?
495 $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}"
497 puts "making #{rubies.join(', ')}"
499 $mflags.concat(rubies)
502 unless (vars = $mflags.grep(/\A\w+=/n)).empty?
503 open(mkf = "libruby.mk", "wb") do |tmf|
504 tmf.puts("!include Makefile")
506 tmf.puts(*vars.map {|v| v.sub(/=/, " = ")})
507 tmf.puts("PRE_LIBRUBY_UPDATE = del #{mkf}")
509 $mflags.unshift("-f#{mkf}")
510 vars.each {|flag| flag.sub!(/\A/, "-D")}
513 system($make, *sysquote($mflags)) or exit($?.exitstatus)