diff options
Diffstat (limited to 'ext/extmk.rb')
| -rwxr-xr-x[-rw-r--r--] | ext/extmk.rb | 739 |
1 files changed, 531 insertions, 208 deletions
diff --git a/ext/extmk.rb b/ext/extmk.rb index cf7944679c..f5244f72c8 100644..100755 --- a/ext/extmk.rb +++ b/ext/extmk.rb @@ -1,63 +1,99 @@ #! /usr/local/bin/ruby -# -*- ruby -*- +# -*- mode: ruby; coding: us-ascii -*- +# frozen_string_literal: false +module Gem + # Used by Gem::Platform.local + def self.target_rbconfig + RbConfig::CONFIG + end +end + +# :stopdoc: $extension = nil $extstatic = nil $force_static = nil -$install = nil $destdir = nil $dryrun = false -$clean = nil $nodynamic = nil -$extinit = nil -$extobjs = nil +$extobjs = [] $extflags = "" $extlibs = nil $extpath = nil -$ignore = nil $message = nil +$command_output = nil +$subconfigure = false $progname = $0 alias $PROGRAM_NAME $0 alias $0 $progname $extlist = [] -$compiled = {} -$:.replace([Dir.pwd]) -require 'rbconfig' +DUMMY_SIGNATURE = "***DUMMY MAKEFILE***" srcdir = File.dirname(File.dirname(__FILE__)) +unless defined?(CROSS_COMPILING) and CROSS_COMPILING + $:.replace([Dir.pwd, File.expand_path("lib", srcdir)]) +end +require 'rbconfig' -$:.unshift(srcdir, File.expand_path("lib", srcdir)) +# only needs Gem::Platform +require 'rubygems/platform' $topdir = "." $top_srcdir = srcdir +$extmk = true +inplace = File.identical?($top_srcdir, $topdir) -require 'mkmf' +$" << "mkmf.rb" +load File.expand_path("lib/mkmf.rb", srcdir) require 'optparse/shellwords' -def sysquote(x) - @quote ||= /human|os2|macos/ =~ (CROSS_COMPILING || RUBY_PLATFORM) - @quote ? x.quote : x +@null = File::NULL + +def verbose? + $mflags.defined?("V") == "1" end -def relative_from(path, base) - dir = File.join(path, "") - if File.expand_path(dir) == File.expand_path(dir, base) - path - else - File.join(base, path) +def system(*args) + if verbose? + if args.size == 1 + puts args + else + puts Shellwords.join(args) + end + end + super +end + +def atomic_write_open(filename) + filename_new = filename + ".new.#$$" + clean = false + File.open(filename_new, "wbx") do |f| + clean = true + yield f + end + if File.binread(filename_new) != (File.binread(filename) rescue nil) + File.rename(filename_new, filename) + clean = false + end +ensure + if clean + File.unlink(filename_new) end end def extract_makefile(makefile, keep = true) m = File.read(makefile) + s = m[/^CLEANFILES[ \t]*=[ \t](.*)/, 1] and $cleanfiles = s.split + s = m[/^DISTCLEANFILES[ \t]*=[ \t](.*)/, 1] and $distcleanfiles = s.split + s = m[/^EXTSO[ \t]*=[ \t](.*)/, 1] and $extso = s.split if !(target = m[/^TARGET[ \t]*=[ \t]*(\S*)/, 1]) return keep end installrb = {} - m.scan(/^install-rb-default:[ \t]*(\S+)\n\1:[ \t]*(\S+)/) {installrb[$2] = $1} + m.scan(/^(?:do-)?install-rb-default:.*[ \t](\S+)(?:[ \t].*)?\n\1:[ \t]*(\S+)/) {installrb[$2] = $1} oldrb = installrb.keys.sort newrb = install_rb(nil, "").collect {|d, *f| f}.flatten.sort if target_prefix = m[/^target_prefix[ \t]*=[ \t]*\/(.*)/, 1] @@ -69,17 +105,27 @@ def extract_makefile(makefile, keep = true) unless installrb.empty? config = CONFIG.dup install_dirs(target_prefix).each {|var, val| config[var] = val} - FileUtils.rm_f(installrb.values.collect {|f| Config.expand(f, config)}, :verbose => true) + FileUtils.rm_f(installrb.values.collect {|f| RbConfig.expand(f, config)}, + :verbose => verbose?) end end return false end + srcs = Dir[*SRC_EXT.map {|e| "*.#{e}"}, base: $srcdir].map {|fn| File.basename(fn)}.sort + if !srcs.empty? + old_srcs = m[/^ORIG_SRCS[ \t]*=[ \t](.*)/, 1] or return false + (old_srcs.split - srcs).empty? or return false + end $target = target $extconf_h = m[/^RUBY_EXTCONF_H[ \t]*=[ \t]*(\S+)/, 1] - $static ||= m[/^EXTSTATIC[ \t]*=[ \t]*(\S+)/, 1] || false - /^STATIC_LIB[ \t]*=[ \t]*\S+/ =~ m or $static = nil + if $static.nil? + $static ||= m[/^EXTSTATIC[ \t]*=[ \t]*(\S+)/, 1] || false + /^STATIC_LIB[ \t]*=[ \t]*\S+/ =~ m or $static = false + end $preload = Shellwords.shellwords(m[/^preload[ \t]*=[ \t]*(.*)/, 1] || "") - $DLDFLAGS += " " + (m[/^DLDFLAGS[ \t]*=[ \t]*(.*)/, 1] || "") + if dldflags = m[/^dldflags[ \t]*=[ \t]*(.*)/, 1] and !$DLDFLAGS.include?(dldflags) + $DLDFLAGS += " " + dldflags + end if s = m[/^LIBS[ \t]*=[ \t]*(.*)/, 1] s.sub!(/^#{Regexp.quote($LIBRUBYARG)} */, "") s.sub!(/ *#{Regexp.quote($LIBS)}$/, "") @@ -87,47 +133,46 @@ def extract_makefile(makefile, keep = true) end $objs = (m[/^OBJS[ \t]*=[ \t](.*)/, 1] || "").split $srcs = (m[/^SRCS[ \t]*=[ \t](.*)/, 1] || "").split + $headers = (m[/^LOCAL_HDRS[ \t]*=[ \t](.*)/, 1] || "").split $LOCAL_LIBS = m[/^LOCAL_LIBS[ \t]*=[ \t]*(.*)/, 1] || "" $LIBPATH = Shellwords.shellwords(m[/^libpath[ \t]*=[ \t]*(.*)/, 1] || "") - %w[$(libdir) $(topdir)] true end -def extmake(target) - print "#{$message} #{target}\n" - $stdout.flush - if $force_static or $static_ext[target] - $static = target - else - $static = false - end - - unless $ignore - return true if $nodynamic and not $static - end - +def extmake(target, basedir = 'ext', maybestatic = true) FileUtils.mkpath target unless File.directory?(target) begin + # don't build if parent library isn't build + parent = true + d = target + until (d = File.dirname(d)) == '.' + if File.exist?("#{$top_srcdir}/#{basedir}/#{d}/extconf.rb") + parent = (/^all:\s*install/ =~ File.read("#{d}/Makefile") rescue false) + break + end + end + dir = Dir.pwd FileUtils.mkpath target unless File.directory?(target) Dir.chdir target top_srcdir = $top_srcdir topdir = $topdir hdrdir = $hdrdir - prefix = "../" * (target.count("/")+1) + prefix = "../" * (basedir.count("/")+target.count("/")+1) $top_srcdir = relative_from(top_srcdir, prefix) $hdrdir = relative_from(hdrdir, prefix) $topdir = prefix + $topdir $target = target $mdir = target - $srcdir = File.join($top_srcdir, "ext", $mdir) + $srcdir = File.join($top_srcdir, basedir, $mdir) $preload = nil - $objs = "" - $srcs = "" - $compiled[target] = false + $extso = [] makefile = "./Makefile" - ok = File.exist?(makefile) - unless $ignore - rbconfig0 = Config::CONFIG + static = $static + $static = nil if noinstall = File.fnmatch?("-*", target) + ok = parent && File.exist?(makefile) + if parent + rbconfig0 = RbConfig::CONFIG mkconfig0 = CONFIG rbconfig = { "hdrdir" => $hdrdir, @@ -135,38 +180,49 @@ def extmake(target) "topdir" => $topdir, } mkconfig = { - "top_srcdir" => ($hdrdir == top_srcdir) ? top_srcdir : "$(topdir)"+top_srcdir[2..-1], - "hdrdir" => "$(top_srcdir)", - "srcdir" => "$(top_srcdir)/ext/#{$mdir}", + "hdrdir" => ($hdrdir == top_srcdir) ? top_srcdir : "$(top_srcdir)/include", + "srcdir" => "$(top_srcdir)/#{basedir}/#{$mdir}", "topdir" => $topdir, } rbconfig0.each_pair {|key, val| rbconfig[key] ||= val.dup} mkconfig0.each_pair {|key, val| mkconfig[key] ||= val.dup} - Config.module_eval { + RbConfig.module_eval { remove_const(:CONFIG) const_set(:CONFIG, rbconfig) remove_const(:MAKEFILE_CONFIG) const_set(:MAKEFILE_CONFIG, mkconfig) } - Object.class_eval { + MakeMakefile.class_eval { remove_const(:CONFIG) const_set(:CONFIG, mkconfig) } begin $extconf_h = nil ok &&= extract_makefile(makefile) - if (($extconf_h && !File.exist?($extconf_h)) || + old_objs = $objs || [] + old_cleanfiles = $distcleanfiles | $cleanfiles + conf = ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb"].find {|f| File.exist?(f)} + if (!ok || ($extconf_h && !File.exist?($extconf_h)) || !(t = modified?(makefile, MTIMES)) || - ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb", "#{$srcdir}/depend"].any? {|f| modified?(f, [t])}) + [conf, "#{$srcdir}/depend"].any? {|f| modified?(f, [t])}) then ok = false + if verbose? + print "#{conf}\n" if conf + else + print "#{$message} #{target}\n" + end + $stdout.flush init_mkmf Logging::logfile 'mkmf.log' rm_f makefile - if File.exist?($0 = "#{$srcdir}/makefile.rb") - load $0 - elsif File.exist?($0 = "#{$srcdir}/extconf.rb") - load $0 + if conf + Logging.open do + unless verbose? + $stderr.reopen($stdout.reopen(@null)) + end + load $0 = conf + end else create_makefile(target) end @@ -175,57 +231,67 @@ def extmake(target) end rescue SystemExit # ignore + rescue => error + ok = false ensure rm_f "conftest*" - config = $0 $0 = $PROGRAM_NAME end end - ok = yield(ok) if block_given? + ok &&= File.open(makefile){|f| s = f.gets and !s[DUMMY_SIGNATURE]} unless ok - open(makefile, "w") do |f| - f.print dummy_makefile(CONFIG["srcdir"]) + mf = ["# #{DUMMY_SIGNATURE}\n", *dummy_makefile(CONFIG["srcdir"])].join("") + atomic_write_open(makefile) do |f| + f.print(mf) end - return true - end - args = sysquote($mflags) - unless $destdir.to_s.empty? or $mflags.include?("DESTDIR") - args += [sysquote("DESTDIR=" + relative_from($destdir, "../"+prefix))] - end - if $static - args += ["static"] unless $clean - $extlist.push [$static, $target, File.basename($target), $preload] + + return true if !error and target.start_with?("-") + + message = nil + if error + loc = error.backtrace_locations[0] + message = "#{loc.absolute_path}:#{loc.lineno}: #{error.message}" + if Logging.log_opened? + Logging::message("#{message}\n\t#{error.backtrace.join("\n\t")}\n") + end + end + + return [parent, message] end - unless system($make, *args) - $ignore or $continue or return false + args = $mflags + unless $destdir.to_s.empty? or $mflags.defined?("DESTDIR") + args += ["DESTDIR=" + relative_from($destdir, "../"+prefix)] end - $compiled[target] = true - if $clean - FileUtils.rm_f("mkmf.log") - if $clean != true - FileUtils.rm_f([makefile, $extconf_h || "extconf.h"]) - end - File.unlink(makefile) rescue nil + $objs ||= [] + $srcs ||= [] + if $static and ok and !$objs.empty? and !noinstall + args += ["static"] + $extlist.push [(maybestatic ? $static : false), target, $target, $preload] end + FileUtils.rm_f(old_cleanfiles - $distcleanfiles - $cleanfiles) + FileUtils.rm_f(old_objs - $objs) if $static $extflags ||= "" $extlibs ||= [] $extpath ||= [] unless $mswin - $extflags = ($extflags.split | $DLDFLAGS.split | $LDFLAGS.split).join(" ") + $extflags = split_libs($extflags, $DLDFLAGS, $LDFLAGS).uniq.join(" ") end - $extlibs = merge_libs($extlibs, $libs.split, $LOCAL_LIBS.split) + $extlibs = merge_libs($extlibs, split_libs($libs, $LOCAL_LIBS).map {|lib| lib.sub(/\A\.\//, "ext/#{target}/")}) $extpath |= $LIBPATH end ensure - unless $ignore - Config.module_eval { + Logging::log_close + if rbconfig0 + RbConfig.module_eval { remove_const(:CONFIG) const_set(:CONFIG, rbconfig0) remove_const(:MAKEFILE_CONFIG) const_set(:MAKEFILE_CONFIG, mkconfig0) } - Object.class_eval { + end + if mkconfig0 + MakeMakefile.class_eval { remove_const(:CONFIG) const_set(:CONFIG, mkconfig0) } @@ -233,6 +299,7 @@ def extmake(target) $top_srcdir = top_srcdir $topdir = topdir $hdrdir = hdrdir + $static = static Dir.chdir dir end begin @@ -244,14 +311,10 @@ def extmake(target) true end -def compiled?(target) - $compiled[target] -end - def parse_args() $mflags = [] + $makeflags = [] # for make command to build ruby, so quoted - opts = nil $optparser ||= OptionParser.new do |opts| opts.on('-n') {$dryrun = true} opts.on('--[no-]extension [EXTS]', Array) do |v| @@ -279,19 +342,30 @@ def parse_args() if arg = v.first arg.insert(0, '-') if /\A[^-][^=]*\Z/ =~ arg end + $makeflags.concat(v.reject {|arg2| /\AMINIRUBY=/ =~ arg2}.quote) $mflags.concat(v) end opts.on('--message [MESSAGE]', String) do |v| $message = v end + opts.on('--command-output=FILE', String) do |v| + $command_output = v + end + opts.on('--gnumake=yes|no', true) do |v| + $gnumake = v + end + opts.on('--extflags=FLAGS') do |v| + $extflags = v || "" + end end begin $optparser.parse!(ARGV) rescue OptionParser::InvalidOption => e retry if /^--/ =~ e.args[0] $optparser.warn(e) - abort opts.to_s + abort $optparser.to_s end + $command_output or abort "--command-output option is mandatory" $destdir ||= '' @@ -299,7 +373,7 @@ def parse_args() $mflags.unshift(*rest) unless rest.empty? def $mflags.set?(flag) - grep(/\A-(?!-).*#{'%c' % flag}/i) { return true } + grep(/\A-(?!-).*#{flag.chr}/i) { return true } false end def $mflags.defined?(var) @@ -316,7 +390,7 @@ def parse_args() $continue = $mflags.set?(?k) if $extout $extout = '$(topdir)/'+$extout - Config::CONFIG["extout"] = CONFIG["extout"] = $extout + RbConfig::CONFIG["extout"] = CONFIG["extout"] = $extout $extout_prefix = $extout ? "$(extout)$(target_prefix)/" : "" $mflags << "extout=#$extout" << "extout_prefix=#$extout_prefix" end @@ -326,22 +400,16 @@ parse_args() if target = ARGV.shift and /^[a-z-]+$/ =~ target $mflags.push(target) - target = target.sub(/^(dist|real)(?=(?:clean)?$)/, '') case target - when /clean/ - $ignore ||= true - $clean = $1 ? $1[0] : true - when /^install\b/ - $install = true - $ignore ||= true - $mflags.unshift("INSTALL_PROG=install -c -p -m 0755", - "INSTALL_DATA=install -c -p -m 0644", - "MAKEDIRS=mkdir -p") if $dryrun + when /^(dist|real)?(clean)$/, /^install\b/ + abort "#{target} is obsolete" + when /configure/ + $subconfigure = !ARGV.empty? end end unless $message if target - $message = target.sub(/^(\w+)e?\b/, '\1ing').tr('-', ' ') + $message = target.sub(/^(\w+?)e?\b/, '\1ing').tr('-', ' ') else $message = "compiling" end @@ -349,34 +417,41 @@ end EXEEXT = CONFIG['EXEEXT'] if CROSS_COMPILING - $ruby = CONFIG['MINIRUBY'] + $ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY'] elsif sep = config_string('BUILD_FILE_SEPARATOR') $ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT -else +elsif CONFIG['EXTSTATIC'] $ruby = '$(topdir)/miniruby' + EXEEXT +else + $ruby = '$(topdir)/ruby' + EXEEXT +end +$ruby = [$ruby] +$ruby << "-I'$(topdir)'" +unless CROSS_COMPILING + $ruby << "-I'$(top_srcdir)/lib'" + $ruby << "-I'$(extout)/$(arch)'" << "-I'$(extout)/common'" if $extout + ENV["RUBYLIB"] = "-" end -$ruby << " -I'$(topdir)' -I'$(top_srcdir)/lib'" -$ruby << " -I'$(extout)/$(arch)' -I'$(extout)/common'" if $extout -$ruby << " -I'$(hdrdir)/ext' -rpurelib.rb" -$config_h = '$(topdir)/config.h' -ENV["RUBYLIB"] = "-" -ENV["RUBYOPT"] = "-rpurelib.rb" +topruby = $ruby +$ruby = topruby.join(' ') +$mflags << "ruby=#$ruby" +$builtruby = '$(topdir)/miniruby' + EXEEXT # Must be an executable path MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)} # get static-link modules $static_ext = {} if $extstatic - $extstatic.each do |target| - target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM + $extstatic.each do |t| + target = t + target = target.downcase if File::FNM_SYSCASE.nonzero? $static_ext[target] = $static_ext.size end end for dir in ["ext", File::join($top_srcdir, "ext")] setup = File::join(dir, CONFIG['setup']) - if File.file? setup - f = open(setup) - while line = f.gets() + if (f = File.stat(setup) and f.file? rescue next) + File.foreach(setup) do |line| line.chomp! line.sub!(/#.*$/, '') next if /^\s*$/ =~ line @@ -388,59 +463,203 @@ for dir in ["ext", File::join($top_srcdir, "ext")] end next end - target = target.downcase if /mswin32|bccwin32/ =~ RUBY_PLATFORM + target = target.downcase if File::FNM_SYSCASE.nonzero? $static_ext[target] = $static_ext.size end MTIMES << f.mtime $setup = setup - f.close break end end unless $extstatic -ext_prefix = "#{$top_srcdir}/ext" -exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t} -if $extension - exts |= $extension.select {|d| File.directory?("#{ext_prefix}/#{d}")} -else - withes, withouts = %w[--with --without].collect {|w| - if not (w = %w[-extensions -ext].collect {|opt|arg_config(w+opt)}).any? - proc {false} - elsif (w = w.grep(String)).empty? - proc {true} - else - proc {|c1| w.collect {|opt| opt.split(/,/)}.flatten.any?(&c1)} +@gemname = nil +if exts = ARGV.shift + ext_prefix = exts[%r[\A(?>\.bundle/)?[^/]+(?:/(?=(.+)?)|\z)]] + exts = $1 + $extension = [exts] if exts + if ext_prefix.start_with?('.') + @gemname = exts + exts = [] + else + exts &&= $static_ext.select {|t, *| File.fnmatch(t, exts)} + end +end +ext_prefix ||= 'ext' +exts = (exts || $static_ext).sort_by {|t, i| i}.collect {|t, i| t} +default_exclude_exts = + case + when $cygwin + %w'' + when $mswin, $mingw + %w'pty syslog' + else + %w'*win32*' + end +mandatory_exts = {} +withes, withouts = [["--with", nil], ["--without", default_exclude_exts]].collect {|w, d| + if !(w = %w[-extensions -ext].collect {|o|arg_config(w+o)}).any? + d ? proc {|&c1| d.any?(&c1)} : proc {true} + elsif (w = w.grep(String)).empty? + proc {true} + else + w = w.collect {|o| o.split(/,/)}.flatten + w.collect! {|o| o == '+' ? d : o}.flatten! + proc {|&c1| w.any?(&c1)} + end +} +cond = proc {|ext, *| + withes.call {|n| !n or (mandatory_exts[ext] = true if File.fnmatch(n, ext))} and + !withouts.call {|n| File.fnmatch(n, ext)} +} +($extension || %w[*]).each do |e| + e = e.sub(/\A(?:\.\/)+/, '') + incl, excl = Dir.glob("#{e}/**/extconf.rb", base: "#$top_srcdir/#{ext_prefix}").collect {|d| + File.dirname(d) + }.partition {|ext| + if @gemname + ext = ext[%r[\A[^/]+]] # extract gem name + Dir.glob("*.gemspec", base: "#$top_srcdir/#{ext_prefix}/#{ext}") do |g| + break ext = g if ext.start_with?("#{g.chomp!(".gemspec")}-") + end end - } - cond = proc {|ext| - cond1 = proc {|n| File.fnmatch(n, ext, File::FNM_PATHNAME)} - withes.call(cond1) or !withouts.call(cond1) - } - exts |= Dir.glob("#{ext_prefix}/*/**/extconf.rb").collect {|d| - d = File.dirname(d) - d.slice!(0, ext_prefix.length + 1) - d - }.find_all {|ext| with_config(ext, &cond) - }.sort + } + incl.sort! + excl.sort!.collect! {|d| d+"/"} + nil while incl.reject! {|d| excl << d+"/" if excl.any? {|x| d.start_with?(x)}} + exts |= incl + if $LIBRUBYARG_SHARED.empty? and CONFIG["EXTSTATIC"] == "static" + exts.delete_if {|d| File.fnmatch?("-*", d)} + end end +ext_prefix.chomp!("/") + +@ext_prefix = ext_prefix +@inplace = inplace +extend Module.new { + + def timestamp_file(name, target_prefix = nil) + if @gemname and name == '$(TARGET_SO_DIR)' + gem = true + name = "$(gem_platform)/$(ruby_version)/gems/#{@gemname}#{target_prefix}" + end + path = super.sub(%r[/\.extout\.(?:-\.)?], '/.') + if gem + nil while path.sub!(%r[/\.(gem_platform|ruby_version)\.-(?=\.)], '/$(\1)/') + end + path + end -if $extout - extout = Config.expand("#{$extout}", Config::CONFIG.merge("topdir"=>$topdir)) - unless $ignore - FileUtils.mkpath(extout) + def configuration(srcdir) + super << "EXTSO #{['=', $extso].join(' ')}\n" end -end + + def create_makefile(*args, &block) + unless @gemname + if $static and (target = args.first).include?("/") + base = File.basename(target) + $defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}" + $defs << "-DInitVM_#{base}=InitVM_#{target.tr('/', '_')}" + end + return super + end + super(*args) do |conf| + conf.find do |s| + s.sub!(%r(^(srcdir *= *)\$\(top_srcdir\)/\.bundle/gems/[^/]+(?=/))) { + "gem_#{$&}\n" "#{$1}$(gem_srcdir)" + } + s.sub!(/^(TIMESTAMP_DIR *= *)\$\(extout\)/) { + "TARGET_TOPDIR = $(topdir)/.bundle\n" "#{$1}$(TARGET_TOPDIR)" + } + s.sub!(/^(TARGET_SO_DIR *= *)\$\(RUBYARCHDIR\)/) { + "TARGET_GEM_DIR = $(TARGET_TOPDIR)/extensions/$(gem_platform)"\ + "/$(ruby_version)#{$enable_shared ? '' : '-static'}/#{@gemname}\n"\ + "#{$1}$(TARGET_GEM_DIR)$(target_prefix)" + } + end + + conf = yield conf if block + + if conf.any? {|s| /^TARGET *= *\S/ =~ s} + conf << %{ +gem_platform = #{Gem::Platform.local} + +# default target +all: + +gem = #{@gemname} + +build_complete = $(TARGET_GEM_DIR)/gem.build_complete +install-so: build_complete +clean-so:: clean-build_complete +$(build_complete) $(OBJS): $(TARGET_SO_DIR_TIMESTAMP) + +build_complete: $(build_complete) +$(build_complete): $(TARGET_SO) + $(Q) $(TOUCH) $@ + +clean-build_complete: + -$(Q)$(RM) $(build_complete) + +install: gemspec +clean: clean-gemspec + +gemspec = $(TARGET_TOPDIR)/specifications/$(gem).gemspec +$(gemspec): $(gem_srcdir)/.bundled.$(gem).gemspec + $(Q) $(MAKEDIRS) $(@D) + $(Q) $(COPY) $(gem_srcdir)/.bundled.$(gem).gemspec $@ + +gemspec: $(gemspec) + +clean-gemspec: + -$(Q)$(RM) $(gemspec) + +LN_S = #{config_string('LN_S')} +CP_R = #{config_string('CP')} -r +} + unless @inplace + %w[bin lib].each do |d| + next unless File.directory?("#{$top_srcdir}/#{@ext_prefix}/#{@gemname}/#{d}") + conf << %{ +install-rb: gem#{d} +clean-rb:: clean-gem#{d} + +gem#{d} = $(TARGET_TOPDIR)/gems/$(gem)/#{d} +gem#{d}:#{%{ $(gem#{d})\n$(gem#{d}): $(gem_srcdir)/#{d}} if $nmake} + $(Q) $(RUBY) $(top_srcdir)/tool/ln_sr.rb -q -f -T $(gem_srcdir)/#{d} $(gem#{d}) + +clean-gem#{d}: + $(Q) $(RM_RF) $(gem#{d}) +} + end + end + end + + conf + end + end +} dir = Dir.pwd -FileUtils::makedirs('ext') -Dir::chdir('ext') +FileUtils::makedirs(ext_prefix) +Dir::chdir(ext_prefix) hdrdir = $hdrdir -$hdrdir = $top_srcdir = relative_from(srcdir, $topdir = "..") +$hdrdir = ($top_srcdir = relative_from(srcdir, $topdir = "..")) + "/include" +extso = [] +fails = [] exts.each do |d| - extmake(d) or abort + $static = $force_static ? true : $static_ext.fetch(d) do + $static_ext.any? {|t, | File.fnmatch?(t, d)} + end + + if !$nodynamic or $static + result = extmake(d, ext_prefix, !@gemname) or abort + extso |= $extso + fails << [d, result] unless result == true + end end + $top_srcdir = srcdir $topdir = "." $hdrdir = hdrdir @@ -450,105 +669,209 @@ extinit = Struct.new(:c, :o) { super("#{src}.c", "#{src}.#{$OBJEXT}") end }.new("extinit") -if $ignore - FileUtils.rm_f(extinit.to_a) if $clean - Dir.chdir ".." - if $clean - Dir.rmdir('ext') rescue nil - FileUtils.rm_rf(extout) if $extout - end - exit -end -$extinit ||= "" -$extobjs ||= "" +$extobjs ||= [] $extpath ||= [] $extflags ||= "" $extlibs ||= [] +extinits = [] unless $extlist.empty? - $extinit << "\n" unless $extinit.empty? list = $extlist.dup built = [] while e = list.shift - s,t,i,r = e - if r and !(r -= built).empty? + static, target, feature, required = e + next unless static + if required and !(required -= built).empty? l = list.size - if (while l > 0; break true if r.include?(list[l-=1][1]) end) + if (while l > 0; break true if required.include?(list[l-=1][1]) end) list.insert(l + 1, e) end next end - f = format("%s/%s.%s", s, i, $LIBEXT) - if File.exist?(f) - $extinit << " init(Init_#{i}, \"#{t}.so\");\n" - $extobjs << "ext/#{f} " - built << t - end + base = File.basename(feature) + extinits << feature + $extobjs << format("ext/%s/%s.%s", target, base, $LIBEXT) + built << target end - src = %{\ -#include "ruby.h" - -#define init(func, name) {void func _((void)); ruby_init_ext(name, func);} - -void ruby_init_ext _((const char *name, void (*init)(void))); - -void Init_ext _((void))\n{\n#$extinit} -} - if !modified?(extinit.c, MTIMES) || IO.read(extinit.c) != src - open(extinit.c, "w") {|f| f.print src} - end - - $extobjs = "ext/#{extinit.o} #{$extobjs}" - if RUBY_PLATFORM =~ /m68k-human|beos/ - $extflags.delete("-L/usr/local/lib") - end $extpath.delete("$(topdir)") $extflags = libpathflag($extpath) << " " << $extflags.strip conf = [ ['LIBRUBY_SO_UPDATE', '$(LIBRUBY_EXTS)'], ['SETUP', $setup], - [enable_config("shared", $enable_shared) ? 'DLDOBJS' : 'EXTOBJS', $extobjs], ['EXTLIBS', $extlibs.join(' ')], ['EXTLDFLAGS', $extflags] ].map {|n, v| - "#{n}=#{v}" if v and !(v = v.strip).empty? + "#{n}=#{v}" if v &&= v[/\S(?:.*\S)?/] }.compact - puts conf + puts(*conf) unless $subconfigure $stdout.flush $mflags.concat(conf) + $makeflags.concat(conf) else FileUtils.rm_f(extinit.to_a) end rubies = [] -%w[RUBY RUBYW STATIC_RUBY].each {|r| - n = r +%w[RUBY RUBYW STATIC_RUBY].each {|n| + r = n if r = arg_config("--"+r.downcase) || config_string(r+"_INSTALL_NAME") - rubies << Config.expand(r+=EXEEXT) + rubies << RbConfig.expand(r+=EXEEXT) $mflags << "#{n}=#{r}" end } -Dir.chdir ".." +Dir.chdir dir unless $destdir.to_s.empty? $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}" end -puts "making #{rubies.join(', ')}" -$stdout.flush -$mflags.concat(rubies) +$makeflags.uniq! + +$mflags.unshift("topdir=#$topdir") +ENV.delete("RUBYOPT") +exts.map! {|d| "#{ext_prefix}/#{d}/."} +FileUtils.makedirs(File.dirname($command_output)) +begin + atomic_write_open($command_output) do |mf| + mf.puts "V = 0" + mf.puts "V0 = $(V:0=)" + mf.puts "Q1 = $(V:1=)" + mf.puts "Q = $(Q1:0=@)" + mf.puts "ECHO1 = $(V:1=@:)" + mf.puts "ECHO = $(ECHO1:0=@echo)" + mf.puts "MFLAGS = -$(MAKEFLAGS)" if $nmake + mf.puts "override MFLAGS := $(filter-out -j%,$(MFLAGS))" if $gnumake + mf.puts "ext_build_dir = #{File.dirname($command_output)}" + mf.puts + + def mf.macro(name, values, max = 70) + print name, " =" + w = w0 = name.size + 2 + h = " \\\n" + "\t" * (w / 8) + " " * (w % 8) + values.each do |s| + if s.size + w > max + print h + w = w0 + end + print " ", s + w += s.size + 1 + end + puts + end -if $nmake == ?b - unless (vars = $mflags.grep(/\A\w+=/n)).empty? - open(mkf = "libruby.mk", "wb") do |tmf| - tmf.puts("!include Makefile") - tmf.puts - tmf.puts(*vars.map {|v| v.sub(/=/, " = ")}) - tmf.puts("PRE_LIBRUBY_UPDATE = del #{mkf}") + mf.macro "ruby", topruby + mf.macro "RUBY", ["$(ruby)"] + mf.macro "extensions", exts + mf.macro "EXTOBJS", $extlist.empty? ? ["dmyext.#{$OBJEXT}"] : ["ext/extinit.#{$OBJEXT}", *$extobjs] + mf.macro "EXTLIBS", $extlibs + mf.macro "EXTSO", extso + mf.macro "EXTLDFLAGS", $extflags.split + mf.macro "EXTINITS", extinits + submakeopts = [] + if enable_config("shared", $enable_shared) + submakeopts << 'DLDOBJS="$(EXTOBJS) $(EXTENCS)"' + submakeopts << 'EXTOBJS=' + submakeopts << 'EXTSOLIBS="$(EXTLIBS)"' + submakeopts << 'LIBRUBY_SO_UPDATE=$(LIBRUBY_EXTS)' + else + submakeopts << 'EXTOBJS="$(EXTOBJS) $(EXTENCS)"' + submakeopts << 'EXTLIBS="$(EXTLIBS)"' + end + submakeopts << 'EXTLDFLAGS="$(EXTLDFLAGS)"' + submakeopts << 'EXTINITS="$(EXTINITS)"' + submakeopts << 'SHOWFLAGS=' + mf.macro "SUBMAKEOPTS", submakeopts + mf.macro "NOTE_MESG", %w[$(RUBY) $(top_srcdir)/tool/lib/colorize.rb skip] + mf.macro "NOTE_NAME", %w[$(RUBY) $(top_srcdir)/tool/lib/colorize.rb fail] + %w[RM RMDIRS RMDIR RMALL].each {|w| mf.macro w, [RbConfig::CONFIG[w]]} + if $nmake + message = ['@(for %I in (', ') do @echo.%~I)'] + else + message = ['@for line in', '; do echo "$$line"; done'] + end + mf.macro "MESSAGE_BEGIN", [message.first] + mf.macro "MESSAGE_END", [message.last] + mf.puts + targets = %w[all install static install-so install-rb clean distclean realclean] + targets.each do |tgt| + mf.puts "#{tgt}: $(extensions:/.=/#{tgt})" + mf.puts "#{tgt}: note" unless /clean\z/ =~ tgt + end + mf.puts + mf.puts "clean:\n\t-$(Q)$(RM) ext/extinit.#{$OBJEXT}" + mf.puts "distclean:\n\t-$(Q)$(RM) ext/extinit.c" + mf.puts + mf.puts "#{rubies.join(' ')}: $(extensions:/.=/#{$force_static ? 'static' : 'all'})" + submake = "$(Q)$(MAKE) $(MFLAGS) $(SUBMAKEOPTS)" + mf.puts "all static: #{rubies.join(' ')}\n" + $extobjs.each do |tgt| + mf.puts "#{tgt}: #{File.dirname(tgt)}/static" + end + mf.puts "#{rubies.join(' ')}: $(EXTOBJS)#{' libencs' if CONFIG['ENCSTATIC'] == 'static'}" + rubies.each do |tgt| + mf.puts "#{tgt}:\n\t#{submake} $@" + end + mf.puts "libencs:\n\t$(Q)$(MAKE) -f enc.mk V=$(V) $@" + mf.puts "ext/extinit.#{$OBJEXT}:\n\t$(Q)$(MAKE) $(MFLAGS) V=$(V) EXTINITS=\"$(EXTINITS)\" $@" if $static + mf.puts + if $gnumake == "yes" + submake = "$(MAKE) -C $(@D)" + else + submake = ["cd", (sep ? "$(@D:/=#{sep})" : "$(@D)"), "&&"] + config_string("exec") {|str| submake << str} + submake = (submake << "$(MAKE)").join(" ") + end + targets.each do |tgt| + exts.each do |d| + d = d[0..-2] + t = "#{d}#{tgt}" + if clean = /^(dist|real)?clean$/.match(tgt) + deps = exts.select {|e|e.start_with?(d)}.map {|e|"#{e[0..-2]}#{tgt}"} - [t] + pd = [' clean-local', *deps].join(' ') + else + pext = File.dirname(d) + pd = " #{pext}/#{tgt}" if exts.include?("#{pext}/.") + end + mf.puts "#{t}:#{pd}\n\t$(Q)#{submake} $(MFLAGS) V=$(V) $(@F)" + if clean and clean.begin(1) + mf.puts "\t$(Q)$(RM) $(ext_build_dir)/exts.mk\n\t$(Q)$(RMDIRS) $(@D)" + end + end + end + mf.puts "\n""clean-local:\n\t$(Q)$(RM) $(ext_build_dir)/*~ $(ext_build_dir)/*.bak $(ext_build_dir)/core" + mf.puts "\n""extso:\n" + mf.puts "\t@echo EXTSO=$(EXTSO)" + + mf.puts "\n""note:\n" + unless fails.empty? + abandon = false + mf.puts "note: note-body\n" + mf.puts "note-body:: note-header\n" + mf.puts "note-header:\n" + mf.puts %Q<\t@$(NOTE_MESG) "*** Following extensions are not compiled:"> + mf.puts "note-body:: note-header\n" + fails.each do |ext, (parent, err)| + abandon ||= mandatory_exts[ext] + mf.puts %Q<\t@$(NOTE_NAME) "#{ext}:"> + mf.puts "\t$(MESSAGE_BEGIN) \\" + if parent + mf.puts %Q<\t"\tCould not be configured. It will not be installed." \\> + err and err.scan(/.+/) do |ee| + mf.puts %Q<\t"\t#{ee.gsub(/["`$^]/, '\\\\\\&')}" \\> + end + mf.puts %Q<\t"\tCheck #{ext_prefix}/#{ext}/mkmf.log for more details." \\> + else + mf.puts %Q<\t"\tSkipped because its parent was not configured." \\> + end + mf.puts "\t$(MESSAGE_END)" + end + mf.puts "note:\n" + mf.puts %Q<\t@$(NOTE_MESG) "*** Fix the problems, then remove these directories and try again if you want."> + if abandon + mf.puts "\t""@exit 1" + end end - $mflags.unshift("-f#{mkf}") - vars.each {|flag| flag.sub!(/\A/, "-D")} end end -system($make, *sysquote($mflags)) or exit($?.exitstatus) +# :startdoc: #Local variables: # mode: ruby |
