5 # This script takes at least two arguments, a GNU style version script and
6 # a list of object and archive files, and generates a corresponding Sun
7 # style version script as follows:
9 # Each glob pattern, C++ mangled pattern or literal in the input script is
10 # matched against all global symbols in the input objects, emitting those
11 # that matched (or nothing if no match was found).
12 # A comment with the original pattern and its type is left in the output
13 # file to make it easy to understand the matches.
15 # It expects a 'nm' with the POSIX '-P' option, but everyone has one of
17 # It depends on the GNU version of c++filt, since it must understand the
20 use File
::Glob
':glob';
24 # Input version script, GNU style.
28 # Get all the symbols from the library, match them, and add them to a hash.
32 # List of objects and archives to process.
35 # List of shared objects to omit from processing.
38 # Filter out those input archives that have corresponding shared objects to
39 # avoid adding all symbols matched in the archive to the output map.
40 foreach $file (@ARGV) {
41 if (($so = $file) =~ s/\.a$/.so/ && -e
$so) {
42 printf STDERR
"omitted $file -> $so\n";
43 push (@SHAREDOBJS, $so);
45 push (@OBJECTS, $file);
49 # The nm command to use.
50 my $nm = $ENV{'NM_FOR_TARGET'} || "nm";
52 # Process each symbol.
53 open NM
,$nm.' -P '.(join ' ',@OBJECTS).'|' or die $!;
58 # nm prints out stuff at the start, ignore it.
61 # Ignore register (SPARC only), undefined and local symbols. The
62 # symbol name is optional; Sun nm emits none for local or .bss symbols.
63 next if (/^([^ ]+)?[ \t]+[RUa-z][ \t]+/);
64 # Ignore objects without symbol table. Message goes to stdout with Sun
65 # nm, while GNU nm emits the corresponding message to stderr.
66 next if (/.* - No symbol table data/);
68 # $sym is the name of the symbol.
69 die "unknown nm output $_" if (! /^([^ ]+)[ \t]+[A-Z][ \t]+/);
75 close NM
or die "nm error";
78 # The various types of glob patterns.
80 # A glob pattern that is to be applied to the demangled name: 'cxx'.
81 # A glob patterns that applies directly to the name in the .o files: 'glob'.
82 # This pattern is ignored; used for local variables (usually just '*'): 'ign'.
84 # The type of the current pattern.
87 # We're currently inside `extern "C++"', which Sun ld doesn't understand.
90 # We're currently inside a conditional section: just skip it.
93 # The c++filt command to use. This *must* be GNU c++filt; the Sun Studio
94 # c++filt doesn't handle the GNU mangling style.
95 my $cxxfilt = $ENV{'CXXFILT'} || "c++filt";
97 # The current version name.
98 my $current_version = "";
100 # Was there any attempt to match a symbol to this version?
101 my $matches_attempted;
103 # The number of versions which matched this symbol.
106 open F
,$symvers or die $!;
108 # Print information about generating this file
109 print "# This file was generated by make_sunver.pl. DO NOT EDIT!\n";
110 print "# It was generated by:\n";
111 printf "# %s %s %s\n", $0, $symvers, (join ' ',@ARGV);
112 printf "# Omitted archives with corresponding shared libraries: %s\n",
113 (join ' ', @SHAREDOBJS) if $#SHAREDOBJS >= 0;
117 # End of skipped section.
118 if (/^[ \t]*\#endif/) {
123 # Just skip a conditional section.
124 if ($in_ifdef) { next; }
126 # Lines of the form '};'
127 if (/^([ \t]*)(\}[ \t]*;[ \t]*)$/) {
138 # Lines of the form '} SOME_VERSION_NAME_1.0;'
139 if (/^[ \t]*\}[ \tA-Z0-9_.a-z]+;[ \t]*$/) {
141 # We tried to match symbols agains this version, but none matched.
142 # Emit dummy hidden symbol to avoid marking this version WEAK.
143 if ($matches_attempted && $matched_symbols == 0) {
145 print " .force_WEAK_off_$current_version = DATA S0x0 V0x0;\n";
150 # Special comments that look like C preprocessor conditionals.
151 # Just skip the contents for now.
152 # FIXME: Allow passing in conditionals from the command line to really
153 # control the skipping.
154 if (/^[ \t]*\#ifdef/) {
159 # Comment and blank lines
160 if (/^[ \t]*\#/) { print; next; }
161 if (/^[ \t]*$/) { print; next; }
163 # Lines of the form '{'
173 # Lines of the form 'SOME_VERSION_NAME_1.1 {'
174 if (/^([A-Z0-9_.]+)[ \t]+{$/) {
175 # Record version name.
176 $current_version = $1;
177 # Reset match attempts, #matched symbols for this version.
178 $matches_attempted = 0;
179 $matched_symbols = 0;
185 if (/^[ \t]*global:$/) { print; next; }
187 # After 'local:', globs should be ignored, they won't be exported.
188 if (/^[ \t]*local:$/) {
194 # After 'extern "C++"', globs are C++ patterns
195 if (/^([ \t]*)(extern \"C\+\+\"[ \t]*)$/) {
198 # Need to comment, Sun ld cannot handle this.
199 print "$1##$2\n"; next;
202 # Chomp newline now we're done with passing through the input file.
205 # Catch globs. Note that '{}' is not allowed in globs by this script,
206 # so only '*' and '[]' are available.
207 if (/^([ \t]*)([^ \t;{}#]+);?[ \t]*$/) {
210 # Turn the glob into a regex by replacing '*' with '.*'.
211 # Keep $ptn so we can still print the original form.
212 ($pattern = $ptn) =~ s/\*/\.\*/g;
214 if ($glob eq 'ign') {
215 # We're in a local: * section; just continue.
220 # Print the glob commented for human readers.
221 print "$ws##$ptn ($glob)\n";
222 # We tried to match a symbol to this version.
223 $matches_attempted++;
225 if ($glob eq 'glob') {
228 # Match ptn against symbols in %sym_hash.
229 foreach my $sym (keys %sym_hash) {
230 # Maybe it matches one of the patterns based on the symbol in
232 $ptn_syms{$sym}++ if ($sym =~ /^$pattern$/);
235 foreach my $sym (sort keys(%ptn_syms)) {
239 } elsif ($glob eq 'cxx') {
242 # Verify that we're actually using GNU c++filt. Other versions
243 # most likely cannot handle GNU style symbol mangling.
244 my $cxxout = `$cxxfilt --version 2>&1`;
245 $cxxout =~ m/GNU/ or die "$0 requires GNU c++filt to function";
247 # Talk to c++filt through a pair of file descriptors.
248 # Need to start a fresh instance per pattern, otherwise the
249 # process grows to 500+ MB.
250 my $pid = open2
(*FILTIN
, *FILTOUT
, $cxxfilt) or die $!;
252 # Match ptn against symbols in %sym_hash.
253 foreach my $sym (keys %sym_hash) {
254 # No? Well, maybe its demangled form matches one of those
256 printf FILTOUT
"%s\n",$sym;
259 $dem_syms{$sym}++ if ($dem =~ /^$pattern$/);
262 close FILTOUT
or die "c++filt error";
263 close FILTIN
or die "c++filt error";
264 # Need to wait for the c++filt process to avoid lots of zombies.
267 foreach my $sym (sort keys(%dem_syms)) {
272 # No? Well, then ignore it.
276 # Important sanity check. This script can't handle lots of formats
277 # that GNU ld can, so be sure to error out if one is seen!
278 die "strange line `$_'";