1#!./miniruby -sI. 2 3$name = $library = $description = nil 4 5module RbConfig 6 autoload :CONFIG, "./rbconfig" 7end 8 9class Exports 10 @@subclass = [] 11 def self.inherited(klass) 12 @@subclass << [/#{klass.name.sub(/.*::/, '').downcase}/i, klass] 13 end 14 15 def self.create(*args, &block) 16 platform = RUBY_PLATFORM 17 pat, klass = @@subclass.find {|p, k| p =~ platform} 18 unless klass 19 raise ArgumentError, "unsupported platform: #{platform}" 20 end 21 klass.new(*args, &block) 22 end 23 24 def self.extract(objs, *rest) 25 create(objs).exports(*rest) 26 end 27 28 def self.output(output = $output, &block) 29 if output 30 open(output, 'wb', &block) 31 else 32 yield STDOUT 33 end 34 end 35 36 def initialize(objs) 37 syms = {} 38 winapis = {} 39 syms["ruby_sysinit_real"] = "ruby_sysinit" 40 each_export(objs) do |internal, export| 41 syms[internal] = export 42 winapis[$1] = internal if /^_?(rb_w32_\w+)(?:@\d+)?$/ =~ internal 43 end 44 incdir = File.join(File.dirname(File.dirname(__FILE__)), "include/ruby") 45 read_substitution(incdir+"/win32.h", syms, winapis) 46 read_substitution(incdir+"/subst.h", syms, winapis) 47 syms["rb_w32_vsnprintf"] ||= "ruby_vsnprintf" 48 syms["rb_w32_snprintf"] ||= "ruby_snprintf" 49 @syms = syms 50 end 51 52 def read_substitution(header, syms, winapis) 53 IO.foreach(header) do |line| 54 if /^#define (\w+)\((.*?)\)\s+(?:\(void\))?(rb_w32_\w+)\((.*?)\)\s*$/ =~ line and 55 $2.delete(" ") == $4.delete(" ") 56 export, internal = $1, $3 57 if syms[internal] or internal = winapis[internal] 58 syms[forwarding(internal, export)] = internal 59 end 60 end 61 end 62 end 63 64 def exports(name = $name, library = $library, description = $description) 65 exports = [] 66 if name 67 exports << "Name " + name 68 elsif library 69 exports << "Library " + library 70 end 71 exports << "Description " + description.dump if description 72 exports << "VERSION #{RbConfig::CONFIG['MAJOR']}.#{RbConfig::CONFIG['MINOR']}" 73 exports << "EXPORTS" << symbols() 74 exports 75 end 76 77 private 78 def forwarding(internal, export) 79 internal.sub(/^[^@]+/, "\\1#{export}") 80 end 81 82 def each_export(objs) 83 end 84 85 def objdump(objs, &block) 86 if objs.empty? 87 $stdin.each_line(&block) 88 else 89 each_line(objs, &block) 90 end 91 end 92 93 def symbols() 94 @syms.sort.collect {|k, v| v ? v == true ? "#{k} DATA" : "#{k}=#{v}" : k} 95 end 96end 97 98class Exports::Mswin < Exports 99 def each_line(objs, &block) 100 IO.popen(%w"dumpbin -symbols -exports" + objs) do |f| 101 f.each(&block) 102 end 103 end 104 105 def each_export(objs) 106 noprefix = ($arch ||= nil and /^(sh|i\d86)/ !~ $arch) 107 objs = objs.collect {|s| s.tr('/', '\\')} 108 filetype = nil 109 objdump(objs) do |l| 110 if (filetype = l[/^File Type: (.+)/, 1])..(/^\f/ =~ l) 111 case filetype 112 when /OBJECT/, /LIBRARY/ 113 next if /^[[:xdigit:]]+ 0+ UNDEF / =~ l 114 next unless /External/ =~ l 115 next unless l.sub!(/.*?\s(\(\)\s+)?External\s+\|\s+/, '') 116 is_data = !$1 117 if noprefix or /^[@_]/ =~ l 118 next if /(?!^)@.*@/ =~ l || /@[[:xdigit:]]{8,32}$/ =~ l || 119 /^_?(?:Init_|.*_threadptr_|DllMain\b)/ =~ l 120 l.sub!(/^[@_]/, '') if /@\d+$/ !~ l 121 elsif !l.sub!(/^(\S+) \([^@?\`\']*\)$/, '\1') 122 next 123 end 124 when /DLL/ 125 next unless l.sub!(/^\s*\d+\s+[[:xdigit:]]+\s+[[:xdigit:]]+\s+/, '') 126 else 127 next 128 end 129 yield l.strip, is_data 130 end 131 end 132 yield "strcasecmp", "msvcrt.stricmp" 133 yield "strncasecmp", "msvcrt.strnicmp" 134 end 135end 136 137class Exports::Cygwin < Exports 138 def self.nm 139 @@nm ||= RbConfig::CONFIG["NM"] 140 end 141 142 def exports(*) 143 super() 144 end 145 146 def each_line(objs, &block) 147 IO.foreach("|#{self.class.nm} --extern --defined #{objs.join(' ')}", &block) 148 end 149 150 def each_export(objs) 151 symprefix = RbConfig::CONFIG["SYMBOL_PREFIX"] 152 symprefix.strip! if symprefix 153 re = /\s(?:(T)|[[:upper:]])\s#{symprefix}((?!Init_|.*_threadptr_|DllMain\b).*)$/ 154 objdump(objs) do |l| 155 next if /@.*@/ =~ l 156 yield $2, !$1 if re =~ l 157 end 158 end 159end 160 161class Exports::Mingw < Exports::Cygwin 162 def each_export(objs) 163 super 164 yield "strcasecmp", "_stricmp" 165 yield "strncasecmp", "_strnicmp" 166 end 167end 168 169END { 170 exports = Exports.extract(ARGV) 171 Exports.output {|f| f.puts(*exports)} 172} 173