21 alias $PROGRAM_NAME $0
27 srcdir = File.dirname(File.dirname(__FILE__))
28 unless defined?(CROSS_COMPILING) and CROSS_COMPILING
29 $:.replace([File.expand_path("lib", srcdir), Dir.pwd])
38 load File.expand_path("lib/mkmf.rb", srcdir)
39 require 'optparse/shellwords'
42 @quote ||= /human|os2|macos/ =~ (CROSS_COMPILING || RUBY_PLATFORM)
46 def extract_makefile(makefile, keep = true)
47 m = File.read(makefile)
48 if !(target = m[/^TARGET[ \t]*=[ \t]*(\S*)/, 1])
52 m.scan(/^install-rb-default:[ \t]*(\S+)\n\1:[ \t]*(\S+)/) {installrb[$2] = $1}
53 oldrb = installrb.keys.sort
54 newrb = install_rb(nil, "").collect {|d, *f| f}.flatten.sort
55 if target_prefix = m[/^target_prefix[ \t]*=[ \t]*\/(.*)/, 1]
56 target = "#{target_prefix}/#{target}"
60 newrb.each {|f| installrb.delete(f)}
61 unless installrb.empty?
63 install_dirs(target_prefix).each {|var, val| config[var] = val}
64 FileUtils.rm_f(installrb.values.collect {|f| RbConfig.expand(f, config)}, :verbose => true)
70 $extconf_h = m[/^RUBY_EXTCONF_H[ \t]*=[ \t]*(\S+)/, 1]
71 $static ||= m[/^EXTSTATIC[ \t]*=[ \t]*(\S+)/, 1] || false
72 /^STATIC_LIB[ \t]*=[ \t]*\S+/ =~ m or $static = nil
73 $preload = Shellwords.shellwords(m[/^preload[ \t]*=[ \t]*(.*)/, 1] || "")
74 $DLDFLAGS += " " + (m[/^dldflags[ \t]*=[ \t]*(.*)/, 1] || "")
75 if s = m[/^LIBS[ \t]*=[ \t]*(.*)/, 1]
76 s.sub!(/^#{Regexp.quote($LIBRUBYARG)} */, "")
77 s.sub!(/ *#{Regexp.quote($LIBS)}$/, "")
80 $objs = (m[/^OBJS[ \t]*=[ \t](.*)/, 1] || "").split
81 $srcs = (m[/^SRCS[ \t]*=[ \t](.*)/, 1] || "").split
82 $LOCAL_LIBS = m[/^LOCAL_LIBS[ \t]*=[ \t]*(.*)/, 1] || ""
83 $LIBPATH = Shellwords.shellwords(m[/^libpath[ \t]*=[ \t]*(.*)/, 1] || "") - %w[$(libdir) $(topdir)]
88 print "#{$message} #{target}\n"
91 FileUtils.mkpath target unless File.directory?(target)
94 FileUtils.mkpath target unless File.directory?(target)
96 top_srcdir = $top_srcdir
99 prefix = "../" * (target.count("/")+1)
100 $top_srcdir = relative_from(top_srcdir, prefix)
101 $hdrdir = relative_from(hdrdir, prefix)
102 $topdir = prefix + $topdir
105 $srcdir = File.join($top_srcdir, "ext", $mdir)
109 $compiled[target] = false
110 makefile = "./Makefile"
111 ok = File.exist?(makefile)
113 rbconfig0 = RbConfig::CONFIG
121 "hdrdir" => ($hdrdir == top_srcdir) ? top_srcdir : "$(top_srcdir)/include",
122 "srcdir" => "$(top_srcdir)/ext/#{$mdir}",
125 rbconfig0.each_pair {|key, val| rbconfig[key] ||= val.dup}
126 mkconfig0.each_pair {|key, val| mkconfig[key] ||= val.dup}
127 RbConfig.module_eval {
128 remove_const(:CONFIG)
129 const_set(:CONFIG, rbconfig)
130 remove_const(:MAKEFILE_CONFIG)
131 const_set(:MAKEFILE_CONFIG, mkconfig)
134 remove_const(:CONFIG)
135 const_set(:CONFIG, mkconfig)
139 ok &&= extract_makefile(makefile)
140 if (($extconf_h && !File.exist?($extconf_h)) ||
141 !(t = modified?(makefile, MTIMES)) ||
142 ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb", "#{$srcdir}/depend"].any? {|f| modified?(f, [t])})
146 Logging::logfile 'mkmf.log'
148 if File.exist?($0 = "#{$srcdir}/makefile.rb")
150 elsif File.exist?($0 = "#{$srcdir}/extconf.rb")
153 create_makefile(target)
155 $defs << "-DRUBY_EXPORT" if $static
156 ok = File.exist?(makefile)
166 ok = yield(ok) if block_given?
168 open(makefile, "w") do |f|
169 f.print(*dummy_makefile(CONFIG["srcdir"]))
173 args = sysquote($mflags)
174 unless $destdir.to_s.empty? or $mflags.include?("DESTDIR")
175 args += [sysquote("DESTDIR=" + relative_from($destdir, "../"+prefix))]
178 args += ["static"] unless $clean
179 $extlist.push [$static, $target, File.basename($target), $preload]
181 unless system($make, *args)
182 $ignore or $continue or return false
184 $compiled[target] = true
186 FileUtils.rm_f("mkmf.log")
188 FileUtils.rm_f([makefile, $extconf_h || "extconf.h"])
196 $extflags = ($extflags.split | $DLDFLAGS.split | $LDFLAGS.split).join(" ")
198 $extlibs = merge_libs($extlibs, $libs.split, $LOCAL_LIBS.split)
203 RbConfig.module_eval {
204 remove_const(:CONFIG)
205 const_set(:CONFIG, rbconfig0)
206 remove_const(:MAKEFILE_CONFIG)
207 const_set(:MAKEFILE_CONFIG, mkconfig0)
210 remove_const(:CONFIG)
211 const_set(:CONFIG, mkconfig0)
214 $top_srcdir = top_srcdir
221 target = File.dirname(target)
222 rescue SystemCallError
228 def compiled?(target)
235 $optparser ||= OptionParser.new do |opts|
236 opts.on('-n') {$dryrun = true}
237 opts.on('--[no-]extension [EXTS]', Array) do |v|
238 $extension = (v == false ? [] : v)
240 opts.on('--[no-]extstatic [STATIC]', Array) do |v|
241 if ($extstatic = v) == false
244 $force_static = true if $extstatic.delete("static")
245 $extstatic = nil if $extstatic.empty?
248 opts.on('--dest-dir=DIR') do |v|
251 opts.on('--extout=DIR') do |v|
252 $extout = (v unless v.empty?)
254 opts.on('--make=MAKE') do |v|
257 opts.on('--make-flags=FLAGS', '--mflags', Shellwords) do |v|
258 v.grep(/\A([-\w]+)=(.*)/) {$configure_args["--#{$1}"] = $2}
260 arg.insert(0, '-') if /\A[^-][^=]*\Z/ =~ arg
264 opts.on('--message [MESSAGE]', String) do |v|
269 $optparser.parse!(ARGV)
270 rescue OptionParser::InvalidOption => e
271 retry if /^--/ =~ e.args[0]
273 abort $optparser.to_s
278 $make, *rest = Shellwords.shellwords($make)
279 $mflags.unshift(*rest) unless rest.empty?
281 def $mflags.set?(flag)
282 grep(/\A-(?!-).*#{flag.chr}/i) { return true }
285 def $mflags.defined?(var)
286 grep(/\A#{var}=(.*)/) {return $1}
293 $mflags.unshift '-n' if $dryrun
296 $continue = $mflags.set?(?k)
298 $extout = '$(topdir)/'+$extout
299 RbConfig::CONFIG["extout"] = CONFIG["extout"] = $extout
300 $extout_prefix = $extout ? "$(extout)$(target_prefix)/" : ""
301 $mflags << "extout=#$extout" << "extout_prefix=#$extout_prefix"
307 if target = ARGV.shift and /^[a-z-]+$/ =~ target
310 when /^(dist|real)?(clean)$/
313 $clean = $1 ? $1[0] : true
317 $mflags.unshift("INSTALL_PROG=install -c -p -m 0755",
318 "INSTALL_DATA=install -c -p -m 0644",
319 "MAKEDIRS=mkdir -p") if $dryrun
324 $message = target.sub(/^(\w+)e?\b/, '\1ing').tr('-', ' ')
326 $message = "compiling"
330 EXEEXT = CONFIG['EXEEXT']
332 $ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY']
333 elsif sep = config_string('BUILD_FILE_SEPARATOR')
334 $ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT
336 $ruby = '$(topdir)/miniruby' + EXEEXT
338 $ruby << " -I'$(topdir)'"
339 unless CROSS_COMPILING
340 $ruby << " -I'$(top_srcdir)/lib'"
341 $ruby << " -I'$(extout)/$(arch)' -I'$(extout)/common'" if $extout
342 $ruby << " -I./- -I'$(top_srcdir)/ext' -rpurelib.rb"
344 ENV["RUBYOPT"] = "-r#{File.expand_path('ext/purelib.rb', $top_srcdir)}"
346 $config_h = '$(arch_hdrdir)/ruby/config.h'
347 $mflags << "ruby=#$ruby"
349 MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)}
351 # get static-link modules
354 $extstatic.each do |t|
356 target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM
357 $static_ext[target] = $static_ext.size
360 for dir in ["ext", File::join($top_srcdir, "ext")]
361 setup = File::join(dir, CONFIG['setup'])
364 while line = f.gets()
366 line.sub!(/#.*$/, '')
367 next if /^\s*$/ =~ line
368 target, opt = line.split(nil, 3)
369 if target == 'option'
376 target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM
377 $static_ext[target] = $static_ext.size
384 end unless $extstatic
386 ext_prefix = "#{$top_srcdir}/ext"
387 exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t}
389 exts |= $extension.select {|d| File.directory?("#{ext_prefix}/#{d}")}
391 withes, withouts = %w[--with --without].collect {|w|
392 if not (w = %w[-extensions -ext].collect {|o|arg_config(w+o)}).any?
394 elsif (w = w.grep(String)).empty?
397 proc {|c1| w.collect {|o| o.split(/,/)}.flatten.any?(&c1)}
401 withouts ||= proc {true}
403 withes = proc {false}
406 cond = proc {|ext, *|
407 cond1 = proc {|n| File.fnmatch(n, ext)}
408 withes.call(cond1) or !withouts.call(cond1)
410 exts |= Dir.glob("#{ext_prefix}/*/**/extconf.rb").collect {|d|
412 d.slice!(0, ext_prefix.length + 1)
415 with_config(ext, &cond)
420 extout = RbConfig.expand("#{$extout}", RbConfig::CONFIG.merge("topdir"=>$topdir))
422 FileUtils.mkpath(extout)
427 FileUtils::makedirs('ext')
431 $hdrdir = ($top_srcdir = relative_from(srcdir, $topdir = "..")) + "/include"
433 $static = $force_static ? $static_ext[target] : false
435 if $ignore or !$nodynamic or $static
443 extinit = Struct.new(:c, :o) {
445 super("#{src}.c", "#{src}.#{$OBJEXT}")
449 FileUtils.rm_f(extinit.to_a) if $clean
452 Dir.rmdir('ext') rescue nil
454 FileUtils.rm_rf([extout+"/common", extout+"/include/ruby", extout+"/rdoc"])
455 FileUtils.rm_rf(extout+"/"+CONFIG["arch"])
457 FileUtils.rm_rf(extout+"/include/"+CONFIG["arch"])
458 FileUtils.rm_f($mflags.defined?("INSTALLED_LIST")||ENV["INSTALLED_LIST"]||".installed.list")
459 Dir.rmdir(extout+"/include") rescue nil
460 Dir.rmdir(extout) rescue nil
472 unless $extlist.empty?
473 $extinit << "\n" unless $extinit.empty?
478 if r and !(r -= built).empty?
480 if (while l > 0; break true if r.include?(list[l-=1][1]) end)
481 list.insert(l + 1, e)
485 f = format("%s/%s.%s", s, i, $LIBEXT)
487 $extinit << " init(Init_#{i}, \"#{t}.so\");\n"
488 $extobjs << "ext/#{f} "
496 #define init(func, name) { \\
497 extern void func _((void)); \\
498 ruby_init_ext(name, func); \\
501 void ruby_init_ext _((const char *name, void (*init)(void)));
503 void Init_ext _((void))\n{\n#$extinit}
505 if !modified?(extinit.c, MTIMES) || IO.read(extinit.c) != src
506 open(extinit.c, "w") {|fe| fe.print src}
509 $extobjs = "ext/#{extinit.o} #{$extobjs}"
510 if RUBY_PLATFORM =~ /m68k-human|beos/
511 $extflags.delete("-L/usr/local/lib")
513 $extpath.delete("$(topdir)")
514 $extflags = libpathflag($extpath) << " " << $extflags.strip
516 ['LIBRUBY_SO_UPDATE', '$(LIBRUBY_EXTS)'],
518 [enable_config("shared", $enable_shared) ? 'DLDOBJS' : 'EXTOBJS', $extobjs],
519 ['EXTLIBS', $extlibs.join(' ')], ['EXTLDFLAGS', $extflags]
521 "#{n}=#{v}" if v and !(v = v.strip).empty?
527 FileUtils.rm_f(extinit.to_a)
530 %w[RUBY RUBYW STATIC_RUBY].each {|n|
532 if r = arg_config("--"+r.downcase) || config_string(r+"_INSTALL_NAME")
533 rubies << Config.expand(r+=EXEEXT)
534 $mflags << "#{n}=#{r}"
539 unless $destdir.to_s.empty?
540 $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}"
542 puts "making #{rubies.join(', ')}"
544 $mflags.concat(rubies)
547 unless (vars = $mflags.grep(/\A\w+=/n)).empty?
548 open(mkf = "libruby.mk", "wb") do |tmf|
549 tmf.puts("!include Makefile")
551 tmf.puts(*vars.map {|v| v.sub(/=/, " = ")})
552 tmf.puts("PRE_LIBRUBY_UPDATE = del #{mkf}")
554 $mflags.unshift("-f#{mkf}")
555 vars.each {|flag| flag.sub!(/\A/, "-D")}
558 $mflags.unshift("topdir=#$topdir")
559 ENV.delete("RUBYOPT")
560 system($make, *sysquote($mflags)) or exit($?.exitstatus)