1#! /usr/local/bin/ruby
2# -*- mode: ruby; coding: us-ascii -*-
3# frozen_string_literal: false
4
5# :stopdoc:
6$extension = nil
7$extstatic = nil
8$force_static = nil
9$destdir = nil
10$dryrun = false
11$nodynamic = nil
12$extobjs = []
13$extflags = ""
14$extlibs = nil
15$extpath = nil
16$message = nil
17$command_output = nil
18$subconfigure = false
19
20$progname = $0
21alias $PROGRAM_NAME $0
22alias $0 $progname
23
24$extlist = []
25
26DUMMY_SIGNATURE = "***DUMMY MAKEFILE***"
27
28srcdir = File.dirname(File.dirname(__FILE__))
29unless defined?(CROSS_COMPILING) and CROSS_COMPILING
30  $:.replace([File.expand_path("lib", srcdir), Dir.pwd])
31end
32$:.unshift(srcdir)
33require 'rbconfig'
34
35$topdir = "."
36$top_srcdir = srcdir
37
38$" << "mkmf.rb"
39load File.expand_path("lib/mkmf.rb", srcdir)
40require 'optparse/shellwords'
41
42if defined?(File::NULL)
43  @null = File::NULL
44elsif !File.chardev?(@null = "/dev/null")
45  @null = "nul"
46end
47
48def verbose?
49  $mflags.defined?("V") == "1"
50end
51
52def system(*args)
53  if verbose?
54    if args.size == 1
55      puts args
56    else
57      puts Shellwords.join(args)
58    end
59  end
60  super
61end
62
63def atomic_write_open(filename)
64  filename_new = filename + ".new.#$$"
65  open(filename_new, "wb") do |f|
66    yield f
67  end
68  if File.binread(filename_new) != (File.binread(filename) rescue nil)
69    File.rename(filename_new, filename)
70  else
71    File.unlink(filename_new)
72  end
73end
74
75def extract_makefile(makefile, keep = true)
76  m = File.read(makefile)
77  s = m[/^CLEANFILES[ \t]*=[ \t](.*)/, 1] and $cleanfiles = s.split
78  s = m[/^DISTCLEANFILES[ \t]*=[ \t](.*)/, 1] and $distcleanfiles = s.split
79  s = m[/^EXTSO[ \t]*=[ \t](.*)/, 1] and $extso = s.split
80  if !(target = m[/^TARGET[ \t]*=[ \t]*(\S*)/, 1])
81    return keep
82  end
83  installrb = {}
84  m.scan(/^(?:do-)?install-rb-default:.*[ \t](\S+)(?:[ \t].*)?\n\1:[ \t]*(\S+)/) {installrb[$2] = $1}
85  oldrb = installrb.keys.sort
86  newrb = install_rb(nil, "").collect {|d, *f| f}.flatten.sort
87  if target_prefix = m[/^target_prefix[ \t]*=[ \t]*\/(.*)/, 1]
88    target = "#{target_prefix}/#{target}"
89  end
90  unless oldrb == newrb
91    if $extout
92      newrb.each {|f| installrb.delete(f)}
93      unless installrb.empty?
94        config = CONFIG.dup
95        install_dirs(target_prefix).each {|var, val| config[var] = val}
96        FileUtils.rm_f(installrb.values.collect {|f| RbConfig.expand(f, config)},
97                       :verbose => verbose?)
98      end
99    end
100    return false
101  end
102  srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")].map {|fn| File.basename(fn)}.sort
103  if !srcs.empty?
104    old_srcs = m[/^ORIG_SRCS[ \t]*=[ \t](.*)/, 1] or return false
105    (old_srcs.split - srcs).empty? or return false
106  end
107  $target = target
108  $extconf_h = m[/^RUBY_EXTCONF_H[ \t]*=[ \t]*(\S+)/, 1]
109  if $static.nil?
110    $static ||= m[/^EXTSTATIC[ \t]*=[ \t]*(\S+)/, 1] || false
111    /^STATIC_LIB[ \t]*=[ \t]*\S+/ =~ m or $static = false
112  end
113  $preload = Shellwords.shellwords(m[/^preload[ \t]*=[ \t]*(.*)/, 1] || "")
114  if dldflags = m[/^dldflags[ \t]*=[ \t]*(.*)/, 1] and !$DLDFLAGS.include?(dldflags)
115    $DLDFLAGS += " " + dldflags
116  end
117  if s = m[/^LIBS[ \t]*=[ \t]*(.*)/, 1]
118    s.sub!(/^#{Regexp.quote($LIBRUBYARG)} */, "")
119    s.sub!(/ *#{Regexp.quote($LIBS)}$/, "")
120    $libs = s
121  end
122  $objs = (m[/^OBJS[ \t]*=[ \t](.*)/, 1] || "").split
123  $srcs = (m[/^SRCS[ \t]*=[ \t](.*)/, 1] || "").split
124  $headers = (m[/^LOCAL_HDRS[ \t]*=[ \t](.*)/, 1] || "").split
125  $LOCAL_LIBS = m[/^LOCAL_LIBS[ \t]*=[ \t]*(.*)/, 1] || ""
126  $LIBPATH = Shellwords.shellwords(m[/^libpath[ \t]*=[ \t]*(.*)/, 1] || "") - %w[$(libdir) $(topdir)]
127  true
128end
129
130def extmake(target, basedir = 'ext', maybestatic = true)
131  FileUtils.mkpath target unless File.directory?(target)
132  begin
133    # don't build if parent library isn't build
134    parent = true
135    d = target
136    until (d = File.dirname(d)) == '.'
137      if File.exist?("#{$top_srcdir}/#{basedir}/#{d}/extconf.rb")
138        parent = (/^all:\s*install/ =~ IO.read("#{d}/Makefile") rescue false)
139        break
140      end
141    end
142
143    dir = Dir.pwd
144    FileUtils.mkpath target unless File.directory?(target)
145    Dir.chdir target
146    top_srcdir = $top_srcdir
147    topdir = $topdir
148    hdrdir = $hdrdir
149    prefix = "../" * (target.count("/")+1)
150    $top_srcdir = relative_from(top_srcdir, prefix)
151    $hdrdir = relative_from(hdrdir, prefix)
152    $topdir = prefix + $topdir
153    $target = target
154    $mdir = target
155    $srcdir = File.join($top_srcdir, basedir, $mdir)
156    $preload = nil
157    $objs = []
158    $srcs = []
159    $extso = []
160    makefile = "./Makefile"
161    static = $static
162    $static = nil if noinstall = File.fnmatch?("-*", target)
163    ok = parent && File.exist?(makefile)
164    if parent
165      rbconfig0 = RbConfig::CONFIG
166      mkconfig0 = CONFIG
167      rbconfig = {
168	"hdrdir" => $hdrdir,
169	"srcdir" => $srcdir,
170	"topdir" => $topdir,
171      }
172      mkconfig = {
173	"hdrdir" => ($hdrdir == top_srcdir) ? top_srcdir : "$(top_srcdir)/include",
174	"srcdir" => "$(top_srcdir)/#{basedir}/#{$mdir}",
175	"topdir" => $topdir,
176      }
177      rbconfig0.each_pair {|key, val| rbconfig[key] ||= val.dup}
178      mkconfig0.each_pair {|key, val| mkconfig[key] ||= val.dup}
179      RbConfig.module_eval {
180	remove_const(:CONFIG)
181	const_set(:CONFIG, rbconfig)
182	remove_const(:MAKEFILE_CONFIG)
183	const_set(:MAKEFILE_CONFIG, mkconfig)
184      }
185      MakeMakefile.class_eval {
186	remove_const(:CONFIG)
187	const_set(:CONFIG, mkconfig)
188      }
189      begin
190	$extconf_h = nil
191	ok &&= extract_makefile(makefile)
192	old_objs = $objs
193	old_cleanfiles = $distcleanfiles | $cleanfiles
194	conf = ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb"].find {|f| File.exist?(f)}
195	if (!ok || ($extconf_h && !File.exist?($extconf_h)) ||
196	    !(t = modified?(makefile, MTIMES)) ||
197	    [conf, "#{$srcdir}/depend"].any? {|f| modified?(f, [t])})
198        then
199	  ok = false
200          if verbose?
201            print "#{conf}\n" if conf
202          else
203            print "#{$message} #{target}\n"
204          end
205          $stdout.flush
206          init_mkmf
207	  Logging::logfile 'mkmf.log'
208	  rm_f makefile
209	  if conf
210            Logging.open do
211              unless verbose?
212                $stderr.reopen($stdout.reopen(@null))
213              end
214              load $0 = conf
215            end
216	  else
217	    create_makefile(target)
218	  end
219	  $defs << "-DRUBY_EXPORT" if $static
220	  ok = File.exist?(makefile)
221	end
222      rescue SystemExit
223	# ignore
224      rescue => error
225        ok = false
226      ensure
227	rm_f "conftest*"
228	$0 = $PROGRAM_NAME
229      end
230    end
231    ok &&= File.open(makefile){|f| s = f.gets and !s[DUMMY_SIGNATURE]}
232    unless ok
233      mf = ["# #{DUMMY_SIGNATURE}\n", *dummy_makefile(CONFIG["srcdir"])].join("")
234      atomic_write_open(makefile) do |f|
235        f.print(mf)
236      end
237
238      return true if !error and target.start_with?("-")
239
240      message = nil
241      if error
242        loc = error.backtrace_locations[0]
243        message = "#{loc.absolute_path}:#{loc.lineno}: #{error.message}"
244        if Logging.log_opened?
245          Logging::message("#{message}\n\t#{error.backtrace.join("\n\t")}\n")
246        end
247      end
248
249      return [parent, message]
250    end
251    args = $mflags
252    unless $destdir.to_s.empty? or $mflags.defined?("DESTDIR")
253      args += ["DESTDIR=" + relative_from($destdir, "../"+prefix)]
254    end
255    if $static and ok and !$objs.empty? and !noinstall
256      args += ["static"]
257      $extlist.push [(maybestatic ? $static : false), target, $target, $preload]
258    end
259    FileUtils.rm_f(old_cleanfiles - $distcleanfiles - $cleanfiles)
260    FileUtils.rm_f(old_objs - $objs)
261    if $static
262      $extflags ||= ""
263      $extlibs ||= []
264      $extpath ||= []
265      unless $mswin
266        $extflags = split_libs($extflags, $DLDFLAGS, $LDFLAGS).uniq.join(" ")
267      end
268      $extlibs = merge_libs($extlibs, split_libs($libs, $LOCAL_LIBS).map {|lib| lib.sub(/\A\.\//, "ext/#{target}/")})
269      $extpath |= $LIBPATH
270    end
271  ensure
272    Logging::log_close
273    if rbconfig0
274      RbConfig.module_eval {
275	remove_const(:CONFIG)
276	const_set(:CONFIG, rbconfig0)
277	remove_const(:MAKEFILE_CONFIG)
278	const_set(:MAKEFILE_CONFIG, mkconfig0)
279      }
280    end
281    if mkconfig0
282      MakeMakefile.class_eval {
283	remove_const(:CONFIG)
284	const_set(:CONFIG, mkconfig0)
285      }
286    end
287    $top_srcdir = top_srcdir
288    $topdir = topdir
289    $hdrdir = hdrdir
290    $static = static
291    Dir.chdir dir
292  end
293  begin
294    Dir.rmdir target
295    target = File.dirname(target)
296  rescue SystemCallError
297    break
298  end while true
299  true
300end
301
302def parse_args()
303  $mflags = []
304  $makeflags = [] # for make command to build ruby, so quoted
305
306  $optparser ||= OptionParser.new do |opts|
307    opts.on('-n') {$dryrun = true}
308    opts.on('--[no-]extension [EXTS]', Array) do |v|
309      $extension = (v == false ? [] : v)
310    end
311    opts.on('--[no-]extstatic [STATIC]', Array) do |v|
312      if ($extstatic = v) == false
313        $extstatic = []
314      elsif v
315        $force_static = true if $extstatic.delete("static")
316        $extstatic = nil if $extstatic.empty?
317      end
318    end
319    opts.on('--dest-dir=DIR') do |v|
320      $destdir = v
321    end
322    opts.on('--extout=DIR') do |v|
323      $extout = (v unless v.empty?)
324    end
325    opts.on('--make=MAKE') do |v|
326      $make = v || 'make'
327    end
328    opts.on('--make-flags=FLAGS', '--mflags', Shellwords) do |v|
329      v.grep(/\A([-\w]+)=(.*)/) {$configure_args["--#{$1}"] = $2}
330      if arg = v.first
331        arg.insert(0, '-') if /\A[^-][^=]*\Z/ =~ arg
332      end
333      $makeflags.concat(v.reject {|arg2| /\AMINIRUBY=/ =~ arg2}.quote)
334      $mflags.concat(v)
335    end
336    opts.on('--message [MESSAGE]', String) do |v|
337      $message = v
338    end
339    opts.on('--command-output=FILE', String) do |v|
340      $command_output = v
341    end
342    opts.on('--gnumake=yes|no', true) do |v|
343      $gnumake = v
344    end
345    opts.on('--extflags=FLAGS') do |v|
346      $extflags = v || ""
347    end
348  end
349  begin
350    $optparser.parse!(ARGV)
351  rescue OptionParser::InvalidOption => e
352    retry if /^--/ =~ e.args[0]
353    $optparser.warn(e)
354    abort $optparser.to_s
355  end
356  $command_output or abort "--command-output option is mandatory"
357
358  $destdir ||= ''
359
360  $make, *rest = Shellwords.shellwords($make)
361  $mflags.unshift(*rest) unless rest.empty?
362
363  def $mflags.set?(flag)
364    grep(/\A-(?!-).*#{flag.chr}/i) { return true }
365    false
366  end
367  def $mflags.defined?(var)
368    grep(/\A#{var}=(.*)/) {return $1}
369    false
370  end
371
372  if $mflags.set?(?n)
373    $dryrun = true
374  else
375    $mflags.unshift '-n' if $dryrun
376  end
377
378  $continue = $mflags.set?(?k)
379  if $extout
380    $extout = '$(topdir)/'+$extout
381    RbConfig::CONFIG["extout"] = CONFIG["extout"] = $extout
382    $extout_prefix = $extout ? "$(extout)$(target_prefix)/" : ""
383    $mflags << "extout=#$extout" << "extout_prefix=#$extout_prefix"
384  end
385end
386
387parse_args()
388
389if target = ARGV.shift and /^[a-z-]+$/ =~ target
390  $mflags.push(target)
391  case target
392  when /^(dist|real)?(clean)$/, /^install\b/
393    abort "#{target} is obsolete"
394  when /configure/
395    $subconfigure = !ARGV.empty?
396  end
397end
398unless $message
399  if target
400    $message = target.sub(/^(\w+?)e?\b/, '\1ing').tr('-', ' ')
401  else
402    $message = "compiling"
403  end
404end
405
406EXEEXT = CONFIG['EXEEXT']
407if CROSS_COMPILING
408  $ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY']
409elsif sep = config_string('BUILD_FILE_SEPARATOR')
410  $ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT
411else
412  $ruby = '$(topdir)/miniruby' + EXEEXT
413end
414$ruby = [$ruby]
415$ruby << "-I'$(topdir)'"
416unless CROSS_COMPILING
417  $ruby << "-I'$(top_srcdir)/lib'"
418  $ruby << "-I'$(extout)/$(arch)'" << "-I'$(extout)/common'" if $extout
419  ENV["RUBYLIB"] = "-"
420end
421topruby = $ruby
422$ruby = topruby.join(' ')
423$mflags << "ruby=#$ruby"
424
425MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)}
426
427# get static-link modules
428$static_ext = {}
429if $extstatic
430  $extstatic.each do |t|
431    target = t
432    target = target.downcase if File::FNM_SYSCASE.nonzero?
433    $static_ext[target] = $static_ext.size
434  end
435end
436for dir in ["ext", File::join($top_srcdir, "ext")]
437  setup = File::join(dir, CONFIG['setup'])
438  if File.file? setup
439    f = open(setup)
440    while line = f.gets()
441      line.chomp!
442      line.sub!(/#.*$/, '')
443      next if /^\s*$/ =~ line
444      target, opt = line.split(nil, 3)
445      if target == 'option'
446	case opt
447	when 'nodynamic'
448	  $nodynamic = true
449	end
450	next
451      end
452      target = target.downcase if File::FNM_SYSCASE.nonzero?
453      $static_ext[target] = $static_ext.size
454    end
455    MTIMES << f.mtime
456    $setup = setup
457    f.close
458    break
459  end
460end unless $extstatic
461
462@gemname = nil
463if ARGV[0]
464  ext_prefix, exts = ARGV.shift.split('/', 2)
465  $extension = [exts] if exts
466  @gemname = exts if ext_prefix == 'gems'
467end
468ext_prefix = "#{$top_srcdir}/#{ext_prefix || 'ext'}"
469exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t}
470default_exclude_exts =
471  case
472  when $cygwin
473    %w''
474  when $mswin, $mingw
475    %w'pty syslog'
476  else
477    %w'*win32*'
478  end
479mandatory_exts = {}
480withes, withouts = [["--with", nil], ["--without", default_exclude_exts]].collect {|w, d|
481  if !(w = %w[-extensions -ext].collect {|o|arg_config(w+o)}).any?
482    d ? proc {|c1| d.any?(&c1)} : proc {true}
483  elsif (w = w.grep(String)).empty?
484    proc {true}
485  else
486    w = w.collect {|o| o.split(/,/)}.flatten
487    w.collect! {|o| o == '+' ? d : o}.flatten!
488    proc {|c1| w.any?(&c1)}
489  end
490}
491cond = proc {|ext, *|
492  withes.call(proc {|n|
493                !n or (mandatory_exts[ext] = true if File.fnmatch(n, ext))
494              }) and
495    !withouts.call(proc {|n| File.fnmatch(n, ext)})
496}
497($extension || %w[*]).each do |e|
498  e = e.sub(/\A(?:\.\/)+/, '')
499  incl, excl = Dir.glob("#{ext_prefix}/#{e}/**/extconf.rb").collect {|d|
500    d = File.dirname(d)
501    d.slice!(0, ext_prefix.length + 1)
502    d
503  }.partition {|ext|
504    with_config(ext, &cond)
505  }
506  incl.sort!
507  excl.sort!.collect! {|d| d+"/"}
508  nil while incl.reject! {|d| excl << d+"/" if excl.any? {|x| d.start_with?(x)}}
509  exts |= incl
510  if $LIBRUBYARG_SHARED.empty? and CONFIG["EXTSTATIC"] == "static"
511    exts.delete_if {|d| File.fnmatch?("-*", d)}
512  end
513end
514ext_prefix = File.basename(ext_prefix)
515
516extend Module.new {
517  def timestamp_file(name, target_prefix = nil)
518    if @gemname and name == '$(TARGET_SO_DIR)'
519      name = "$(arch)/gems/#{@gemname}#{target_prefix}"
520    end
521    super.sub(%r[/\.extout\.(?:-\.)?], '/.')
522  end
523
524  def configuration(srcdir)
525    super << "EXTSO #{['=', $extso].join(' ')}\n"
526  end
527
528  def create_makefile(*args, &block)
529    return super unless @gemname
530    super(*args) do |conf|
531      conf.find do |s|
532        s.sub!(/^(TARGET_SO_DIR *= *)\$\(RUBYARCHDIR\)/) {
533          "TARGET_GEM_DIR = $(extout)/gems/$(arch)/#{@gemname}\n"\
534          "#{$1}$(TARGET_GEM_DIR)$(target_prefix)"
535        }
536      end
537      conf.any? {|s| /^TARGET *= *\S/ =~ s} and conf << %{
538
539# default target
540all:
541
542build_complete = $(TARGET_GEM_DIR)/gem.build_complete
543install-so: build_complete
544build_complete: $(build_complete)
545$(build_complete): $(TARGET_SO)
546	$(Q) $(TOUCH) $@
547
548clean-so::
549	-$(Q)$(RM) $(build_complete)
550}
551      conf
552    end
553  end
554}
555
556dir = Dir.pwd
557FileUtils::makedirs(ext_prefix)
558Dir::chdir(ext_prefix)
559
560hdrdir = $hdrdir
561$hdrdir = ($top_srcdir = relative_from(srcdir, $topdir = "..")) + "/include"
562extso = []
563fails = []
564exts.each do |d|
565  $static = $force_static ? true : $static_ext[d]
566
567  if !$nodynamic or $static
568    result = extmake(d, ext_prefix, !@gemname) or abort
569    extso |= $extso
570    fails << [d, result] unless result == true
571  end
572end
573
574$top_srcdir = srcdir
575$topdir = "."
576$hdrdir = hdrdir
577
578extinit = Struct.new(:c, :o) {
579  def initialize(src)
580    super("#{src}.c", "#{src}.#{$OBJEXT}")
581  end
582}.new("extinit")
583
584$extobjs ||= []
585$extpath ||= []
586$extflags ||= ""
587$extlibs ||= []
588extinits = []
589unless $extlist.empty?
590  list = $extlist.dup
591  built = []
592  while e = list.shift
593    static, target, feature, required = e
594    next unless static
595    if required and !(required -= built).empty?
596      l = list.size
597      if (while l > 0; break true if required.include?(list[l-=1][1]) end)
598        list.insert(l + 1, e)
599      end
600      next
601    end
602    base = File.basename(feature)
603    extinits << feature
604    $extobjs << format("ext/%s/%s.%s", target, base, $LIBEXT)
605    built << target
606  end
607
608  $extpath.delete("$(topdir)")
609  $extflags = libpathflag($extpath) << " " << $extflags.strip
610  conf = [
611    ['LIBRUBY_SO_UPDATE', '$(LIBRUBY_EXTS)'],
612    ['SETUP', $setup],
613    ['EXTLIBS', $extlibs.join(' ')], ['EXTLDFLAGS', $extflags]
614  ].map {|n, v|
615    "#{n}=#{v}" if v &&= v[/\S(?:.*\S)?/]
616  }.compact
617  puts(*conf) unless $subconfigure
618  $stdout.flush
619  $mflags.concat(conf)
620  $makeflags.concat(conf)
621else
622  FileUtils.rm_f(extinit.to_a)
623end
624rubies = []
625%w[RUBY RUBYW STATIC_RUBY].each {|n|
626  r = n
627  if r = arg_config("--"+r.downcase) || config_string(r+"_INSTALL_NAME")
628    rubies << RbConfig.expand(r+=EXEEXT)
629    $mflags << "#{n}=#{r}"
630  end
631}
632
633Dir.chdir ".."
634unless $destdir.to_s.empty?
635  $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}"
636end
637$makeflags.uniq!
638
639$mflags.unshift("topdir=#$topdir")
640ENV.delete("RUBYOPT")
641exts.map! {|d| "#{ext_prefix}/#{d}/."}
642FileUtils.makedirs(File.dirname($command_output))
643begin
644  atomic_write_open($command_output) do |mf|
645    mf.puts "V = 0"
646    mf.puts "Q1 = $(V:1=)"
647    mf.puts "Q = $(Q1:0=@)"
648    mf.puts "ECHO1 = $(V:1=@:)"
649    mf.puts "ECHO = $(ECHO1:0=@echo)"
650    mf.puts "MFLAGS = -$(MAKEFLAGS)" if $nmake
651    mf.puts
652
653    def mf.macro(name, values, max = 70)
654      print name, " ="
655      w = w0 = name.size + 2
656      h = " \\\n" + "\t" * (w / 8) + " " * (w % 8)
657      values.each do |s|
658        if s.size + w > max
659          print h
660          w = w0
661        end
662        print " ", s
663        w += s.size + 1
664      end
665      puts
666    end
667
668    mf.macro "ruby", topruby
669    mf.macro "RUBY", ["$(ruby)"]
670    mf.macro "extensions", exts
671    mf.macro "EXTOBJS", $extlist.empty? ? ["dmyext.#{$OBJEXT}"] : ["ext/extinit.#{$OBJEXT}", *$extobjs]
672    mf.macro "EXTLIBS", $extlibs
673    mf.macro "EXTSO", extso
674    mf.macro "EXTLDFLAGS", $extflags.split
675    mf.macro "EXTINITS", extinits
676    submakeopts = []
677    if enable_config("shared", $enable_shared)
678      submakeopts << 'DLDOBJS="$(EXTOBJS) $(EXTENCS)"'
679      submakeopts << 'EXTOBJS='
680      submakeopts << 'EXTSOLIBS="$(EXTLIBS)"'
681      submakeopts << 'LIBRUBY_SO_UPDATE=$(LIBRUBY_EXTS)'
682    else
683      submakeopts << 'EXTOBJS="$(EXTOBJS) $(EXTENCS)"'
684      submakeopts << 'EXTLIBS="$(EXTLIBS)"'
685    end
686    submakeopts << 'EXTLDFLAGS="$(EXTLDFLAGS)"'
687    submakeopts << 'EXTINITS="$(EXTINITS)"'
688    submakeopts << 'UPDATE_LIBRARIES="$(UPDATE_LIBRARIES)"'
689    submakeopts << 'SHOWFLAGS='
690    mf.macro "SUBMAKEOPTS", submakeopts
691    mf.macro "NOTE_MESG", %w[$(RUBY) $(top_srcdir)/tool/colorize.rb skip]
692    mf.macro "NOTE_NAME", %w[$(RUBY) $(top_srcdir)/tool/colorize.rb fail]
693    mf.puts
694    targets = %w[all install static install-so install-rb clean distclean realclean]
695    targets.each do |tgt|
696      mf.puts "#{tgt}: $(extensions:/.=/#{tgt})"
697      mf.puts "#{tgt}: note" unless /clean\z/ =~ tgt
698    end
699    mf.puts
700    mf.puts "clean:\n\t-$(Q)$(RM) ext/extinit.#{$OBJEXT}"
701    mf.puts "distclean:\n\t-$(Q)$(RM) ext/extinit.c"
702    mf.puts
703    mf.puts "#{rubies.join(' ')}: $(extensions:/.=/#{$force_static ? 'static' : 'all'})"
704    submake = "$(Q)$(MAKE) $(MFLAGS) $(SUBMAKEOPTS)"
705    mf.puts "all static: #{rubies.join(' ')}\n"
706    $extobjs.each do |tgt|
707      mf.puts "#{tgt}: #{File.dirname(tgt)}/static"
708    end
709    mf.puts "#{rubies.join(' ')}: $(EXTOBJS)#{' libencs' if CONFIG['ENCSTATIC'] == 'static'}"
710    rubies.each do |tgt|
711      mf.puts "#{tgt}:\n\t#{submake} $@"
712    end
713    mf.puts "libencs:\n\t$(Q)$(MAKE) -f enc.mk V=$(V) $@"
714    mf.puts "ext/extinit.#{$OBJEXT}:\n\t$(Q)$(MAKE) $(MFLAGS) V=$(V) EXTINITS=\"$(EXTINITS)\" $@" if $static
715    mf.puts
716    if $gnumake == "yes"
717      submake = "$(MAKE) -C $(@D)"
718    else
719      submake = "cd $(@D) && "
720      config_string("exec") {|str| submake << str << " "}
721      submake << "$(MAKE)"
722    end
723    targets.each do |tgt|
724      exts.each do |d|
725        d = d[0..-2]
726        t = "#{d}#{tgt}"
727        if  /^(dist|real)?clean$/ =~ tgt
728          deps = exts.select {|e|e.start_with?(d)}.map {|e|"#{e[0..-2]}#{tgt}"} - [t]
729          pd = ' ' + deps.join(' ') unless deps.empty?
730        else
731          pext = File.dirname(d)
732          pd = " #{pext}/#{tgt}" if exts.include?("#{pext}/.")
733        end
734        mf.puts "#{t}:#{pd}\n\t$(Q)#{submake} $(MFLAGS) V=$(V) $(@F)"
735      end
736    end
737    mf.puts "\n""extso:\n"
738    mf.puts "\t@echo EXTSO=$(EXTSO)"
739
740    mf.puts "\n""note:\n"
741    unless fails.empty?
742      abandon = false
743      mf.puts "note: note-body\n"
744      mf.puts "note-body:: note-header\n"
745      mf.puts "note-header:\n"
746      mf.puts %Q<\t@$(NOTE_MESG) "*** Following extensions are not compiled:">
747      mf.puts "note-body:: note-header\n"
748      fails.each do |ext, (parent, err)|
749        abandon ||= mandatory_exts[ext]
750        mf.puts %Q<\t@$(NOTE_NAME) "#{ext}:">
751        if parent
752          mf.puts %Q<\t@echo "\tCould not be configured. It will not be installed.">
753          err and err.scan(/.+/) do |ee|
754            mf.puts %Q<\t@echo "\t#{ee.gsub(/["`$^]/, '\\\\\\&')}">
755          end
756          mf.puts %Q<\t@echo "\tCheck #{ext_prefix}/#{ext}/mkmf.log for more details.">
757        else
758          mf.puts %Q<\t@echo "\tSkipped because its parent was not configured.">
759        end
760      end
761      mf.puts "note:\n"
762      mf.puts %Q<\t@$(NOTE_MESG) "*** Fix the problems, then remove these directories and try again if you want.">
763      if abandon
764        mf.puts "\t""@exit 1"
765      end
766    end
767  end
768end
769# :startdoc:
770
771#Local variables:
772# mode: ruby
773#end:
774