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