blob: b378b089e7a1d757c68ec73f9509428054b8d92b [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001#!/usr/bin/perl
2
3#
4#//===----------------------------------------------------------------------===//
5#//
6#// The LLVM Compiler Infrastructure
7#//
8#// This file is dual licensed under the MIT and the University of Illinois Open
9#// Source Licenses. See LICENSE.txt for details.
10#//
11#//===----------------------------------------------------------------------===//
12#
13
14use strict;
15use warnings;
16
17use File::Glob ":glob";
18use Data::Dumper;
19
20use FindBin;
21use lib "$FindBin::Bin/lib";
22
23use tools;
24use Platform ":vars";
25
26our $VERSION = "0.004";
27
28# --------------------------------------------------------------------------------------------------
29# Set of objects: # Ref to hash, keys are names of objects.
30# object0: # Ref to hash of two elements with keys "defined" and "undefined".
31# defined: # Ref to array of symbols defined in object0.
32# - symbol0 # Symbol name.
33# - ...
34# undefined: # Ref to array of symbols referenced in object0.
35# - symbol0
36# - ...
37# object1:
38# ...
39# ...
40# --------------------------------------------------------------------------------------------------
41
42# --------------------------------------------------------------------------------------------------
43# Set of symbols: # Ref to hash, keys are names of symbols.
44# symbol0: # Ref to array of object names where the symbol0 is defined.
45# - object0 # Object file name.
46# - ...
47# symbol1:
48# ...
49# ...
50# --------------------------------------------------------------------------------------------------
51
52sub dump_objects($$$) {
53
54 my ( $title, $objects, $dump ) = @_;
55
56 if ( $dump > 0 ) {
57 STDERR->print( $title, "\n" );
58 foreach my $object ( sort( keys( %$objects ) ) ) {
59 STDERR->print( " $object\n" );
60 if ( $dump > 1 ) {
61 STDERR->print( " Defined symbols:\n" );
62 foreach my $symbol ( sort( @{ $objects->{ $object }->{ defined } } ) ) {
63 STDERR->print( " $symbol\n" );
64 }; # foreach $symbol
65 STDERR->print( " Undefined symbols:\n" );
66 foreach my $symbol ( sort( @{ $objects->{ $object }->{ undefined } } ) ) {
67 STDERR->print( " $symbol\n" );
68 }; # foreach $symbol
69 }; # if
70 }; # foreach $object
71 }; # if
72
73}; # sub dump_objects
74
75sub dump_symbols($$$) {
76
77 my ( $title, $symbols, $dump ) = @_;
78
79 if ( $dump > 0 ) {
80 STDERR->print( $title, "\n" );
81 foreach my $symbol ( sort( keys( %$symbols ) ) ) {
82 STDERR->print( " $symbol\n" );
83 if ( $dump > 1 ) {
84 foreach my $object ( sort( @{ $symbols->{ $symbol } } ) ) {
85 STDERR->print( " $object\n" );
86 }; # foreach
87 }; # if
88 }; # foreach $object
89 }; # if
90
91}; # sub dump_symbols
92
93# --------------------------------------------------------------------------------------------------
94# Name:
Alp Toker8f2d3f02014-02-24 10:40:15 +000095# load_symbols -- Fulfill objects data structure with symbol names.
Jim Cownie5e8470a2013-09-27 10:38:44 +000096# Synopsis:
97# load_symbols( $objects );
98# Arguments:
99# $objects (in/out) -- Set of objects. On enter, it is expected that top-level hash has filled
Alp Toker8f2d3f02014-02-24 10:40:15 +0000100# with object names only. On exit, it is completely fulfilled with lists of symbols
Jim Cownie5e8470a2013-09-27 10:38:44 +0000101# defined or referenced in each object file.
102# Returns:
103# Nothing.
104# Example:
105# my $objects = { foo.o => {} };
106# load_symbols( $objects );
107# # Now $objects is { goo.o => { defined => [ ... ], undefined => [ ... ] } }.
108#
109# --------------------------------------------------------------------------------------------------
110# This version of load_symbols parses output of nm command and works on Linux* OS and OS X*.
111#
112sub _load_symbols_nm($) {
113
114 my $objects = shift( @_ );
115 # It is a ref to hash. Keys are object names, values are empty hashes (for now).
116 my @bulk;
117
118 if ( %$objects ) {
119 # Do not run nm if a set of objects is empty -- nm will try to open a.out in this case.
120 execute(
121 [
122 "nm",
123 "-g", # Display only external (global) symbols.
124 "-o", # Precede each symbol by the name of the input file.
125 keys( %$objects )
126 # Running nm once (rather than once per object) improves performance
127 # drastically.
128 ],
129 -stdout => \@bulk
130 );
131 }; # if
132
133 foreach my $line ( @bulk ) {
134 if ( $line !~ m{^(.*):(?: ?[0-9a-f]*| *) ([A-Za-z]) (.*)$} ) {
135 die "Cannot parse nm output, line:\n $line\n";
136 }; # if
137 my ( $file, $tag, $symbol ) = ( $1, $2, $3 );
138 if ( not exists( $objects->{ $file } ) ) {
139 die "nm reported unknown object file:\n $line\n";
140 }; # if
141 # AC: exclude some libc symbols from renaming, otherwise we have problems
142 # in tests for gfortran + static libiomp on Lin_32.
143 # These symbols came from libtbbmalloc.a
144 if ( $target_os eq "lin" ) {
145 if ( $symbol =~ m{__i686} ) {
146 next;
147 }
148 }
149 # AC: added "w" to tags of undefined symbols, e.g. malloc is weak in libirc v12.1.
150 if ( $tag eq "U" or $tag eq "w" ) { # Symbol not defined.
151 push( @{ $objects->{ $file }->{ undefined } }, $symbol );
152 } else { # Symbol defined.
153 push( @{ $objects->{ $file }->{ defined } }, $symbol );
154 }; # if
155 }; # foreach
156
157 return undef;
158
159}; # sub _load_symbols_nm
160
161# --------------------------------------------------------------------------------------------------
162# This version of load_symbols parses output of link command and works on Windows* OS.
163#
164sub _load_symbols_link($) {
165
166 my $objects = shift( @_ );
167 # It is a ref to hash. Keys are object names, values are empty hashes (for now).
168 my @bulk;
169
170 if ( %$objects ) {
171 # Do not run nm if a set of objects is empty -- nm will try to open a.out in this case.
172 execute(
173 [
174 "link",
175 "/dump",
176 "/symbols",
177 keys( %$objects )
178 # Running nm once (rather than once per object) improves performance
179 # drastically.
180 ],
181 -stdout => \@bulk
182 );
183 }; # if
184
185 my $num_re = qr{[0-9A-F]{3,4}};
186 my $addr_re = qr{[0-9A-F]{8}};
187 my $tag_re = qr{DEBUG|ABS|UNDEF|SECT[0-9A-F]+};
188 my $class_re = qr{Static|External|Filename|Label|BeginFunction|EndFunction|WeakExternal|\.bf or\.ef};
189
190 my $file;
191 foreach my $line ( @bulk ) {
192 if ( $line =~ m{\ADump of file (.*?)\n\z} ) {
193 $file = $1;
194 if ( not exists( $objects->{ $file } ) ) {
195 die "link reported unknown object file:\n $line\n";
196 }; # if
197 } elsif ( $line =~ m{\A$num_re } ) {
198 if ( not defined( $file ) ) {
199 die "link reported symbol of unknown object file:\n $line\n";
200 }; # if
201 if ( $line !~ m{\A$num_re $addr_re ($tag_re)\s+notype(?: \(\))?\s+($class_re)\s+\| (.*?)\n\z} ) {
202 die "Cannot parse link output, line:\n $line\n";
203 }; # if
204 my ( $tag, $class, $symbol ) = ( $1, $2, $3 );
205 # link.exe /dump sometimes prints comments for symbols, e. g.:
206 # ".?0_memcopyA ([Entry] ?0_memcopyA)", or "??_C@_01A@r?$AA@ (`string')".
207 # Strip these comments.
208 $symbol =~ s{ \(.*\)\z}{};
209 if ( $class eq "External" ) {
210 if ( $tag eq "UNDEF" ) { # Symbol not defined.
211 push( @{ $objects->{ $file }->{ undefined } }, $symbol );
212 } else { # Symbol defined.
213 push( @{ $objects->{ $file }->{ defined } }, $symbol );
214 }; # if
215 }; # if
216 } else {
217 # Ignore all other lines.
218 }; # if
219 }; # foreach
220
221 return undef;
222
223}; # sub _load_symbols_link
224
225# --------------------------------------------------------------------------------------------------
226# Name:
227# symbols -- Construct set of symbols with specified tag in the specified set of objects.
228# Synopsis:
229# my $symbols = defined_symbols( $objects, $tag );
230# Arguments:
231# $objects (in) -- Set of objects.
232# $tag (in) -- A tag, "defined" or "undefined".
233# Returns:
234# Set of symbols with the specified tag.
235#
236sub symbols($$) {
237
238 my $objects = shift( @_ );
239 my $tag = shift( @_ );
240
241 my $symbols = {};
242
243 foreach my $object ( keys( %$objects ) ) {
244 foreach my $symbol ( @{ $objects->{ $object }->{ $tag } } ) {
245 push( @{ $symbols->{ $symbol } }, $object );
246 }; # foreach $symbol
247 }; # foreach $object
248
249 return $symbols;
250
251}; # sub symbols
252
253sub defined_symbols($) {
254
255 my $objects = shift( @_ );
256 my $defined = symbols( $objects, "defined" );
257 return $defined;
258
259}; # sub defined_symbols
260
261sub undefined_symbols($) {
262
263 my $objects = shift( @_ );
264 my $defined = symbols( $objects, "defined" );
265 my $undefined = symbols( $objects, "undefined" );
266 foreach my $symbol ( keys( %$defined ) ) {
267 delete( $undefined->{ $symbol } );
268 }; # foreach symbol
269 return $undefined;
270
271}; # sub undefined_symbols
272
273# --------------------------------------------------------------------------------------------------
274# Name:
275# _required_extra_objects -- Select a subset of extra objects required to resolve undefined
276# symbols in a set of objects. It is a helper sub for required_extra_objects().
277# Synopsis:
278# my $required = _required_extra_objects( $objects, $extra, $symbols );
279# Arguments:
280# $objects (in) -- A set of objects to be searched for undefined symbols.
281# $extra (in) -- A set of extra objects to be searched for defined symbols to resolve undefined
282# symbols in objects.
283# $symbols (in/out) -- Set of symbols defined in the set of external objects. At the first call
284# it should consist of all the symbols defined in all the extra objects. Symbols defined in
285# the selected subset of extra objects are removed from set of defined symbols, because
286# they are out of interest for subsequent calls.
287# Returns:
288# A subset of extra objects required by the specified set of objects.
289#
290sub _required_extra_objects($$$$) {
291
292 my $objects = shift( @_ );
293 my $extra = shift( @_ );
294 my $symbols = shift( @_ );
295 my $dump = shift( @_ );
296
297 my $required = {};
298
299 if ( $dump > 0 ) {
300 STDERR->print( "Required extra objects:\n" );
301 }; # if
302 foreach my $object ( keys( %$objects ) ) {
303 foreach my $symbol ( @{ $objects->{ $object }->{ undefined } } ) {
304 if ( exists( $symbols->{ $symbol } ) ) {
305 # Add all objects where the symbol is defined to the required objects.
306 foreach my $req_obj ( @{ $symbols->{ $symbol } } ) {
307 if ( $dump > 0 ) {
308 STDERR->print( " $req_obj\n" );
309 if ( $dump > 1 ) {
310 STDERR->print( " by $object\n" );
311 STDERR->print( " due to $symbol\n" );
312 }; # if
313 }; # if
314 $required->{ $req_obj } = $extra->{ $req_obj };
315 }; # foreach $req_obj
316 # Delete the symbol from list of defined symbols.
317 delete( $symbols->{ $symbol } );
318 }; # if
319 }; # foreach $symbol
320 }; # foreach $object
321
322 return $required;
323
324}; # sub _required_extra_objects
325
326
327# --------------------------------------------------------------------------------------------------
328# Name:
329# required_extra_objects -- Select a subset of extra objects required to resolve undefined
330# symbols in a set of base objects and selected extra objects.
331# Synopsis:
332# my $required = required_extra_objects( $base, $extra );
333# Arguments:
334# $base (in/out) -- A set of base objects to be searched for undefined symbols. On enter, it is
335# expected that top-level hash has filled with object names only. On exit, it is completely
Alp Toker8f2d3f02014-02-24 10:40:15 +0000336# fulfilled with lists of symbols defined and/or referenced in each object file.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000337# $extra (in/out) -- A set of extra objects to be searched for defined symbols required to
338# resolve undefined symbols in a set of base objects. Usage is similar to base objects.
339# Returns:
340# A subset of extra object files.
341#
342sub required_extra_objects($$$) {
343
344 my $base = shift( @_ );
345 my $extra = shift( @_ );
346 my $dump = shift( @_ );
347
348 # Load symbols for each object.
349 load_symbols( $base );
350 load_symbols( $extra );
351 if ( $dump ) {
352 dump_objects( "Base objects:", $base, $dump );
353 dump_objects( "Extra objects:", $extra, $dump );
354 }; # if
355
356 # Collect symbols defined in extra objects.
357 my $symbols = defined_symbols( $extra );
358
359 my $required = {};
360 # Select extra objects required by base objects.
361 my $delta = _required_extra_objects( $base, $extra, $symbols, $dump );
362 while ( %$delta ) {
363 %$required = ( %$required, %$delta );
364 # Probably, just selected objects require some more objects.
365 $delta = _required_extra_objects( $delta, $extra, $symbols, $dump );
366 }; # while
367
368 if ( $dump ) {
369 my $base_undefined = undefined_symbols( $base );
370 my $req_undefined = undefined_symbols( $required );
371 dump_symbols( "Symbols undefined in base objects:", $base_undefined, $dump );
372 dump_symbols( "Symbols undefined in required objects:", $req_undefined, $dump );
373 }; # if
374
375 return $required;
376
377}; # sub required_extra_objects
378
379
380# --------------------------------------------------------------------------------------------------
381# Name:
382# copy_objects -- Copy (and optionally edit) object files to specified directory.
383# Synopsis:
384# copy_objects( $objects, $target, $prefix, @symbols );
385# Arguments:
386# $objects (in) -- A set of object files.
387# $target (in) -- A name of target directory. Directory must exist.
388# $prefix (in) -- A prefix to add to all the symbols listed in @symbols. If prefix is undefined,
389# object files are just copied.
390# @symbols (in) -- List of symbol names to be renamed.
391# Returns:
392# None.
393#
394sub copy_objects($$;$\@) {
395
396 my $objects = shift( @_ );
397 my $target = shift( @_ );
398 my $prefix = shift( @_ );
399 my $symbols = shift( @_ );
400 my @redefine;
401 my @redefine_;
402 my $syms_file = "__kmp_sym_pairs.log";
403
404 if ( not -e $target ) {
405 die "\"$target\" directory does not exist\n";
406 }; # if
407 if ( not -d $target ) {
408 die "\"$target\" is not a directory\n";
409 }; # if
410
411 if ( defined( $prefix ) and @$symbols ) {
412 my %a = map ( ( "$_ $prefix$_" => 1 ), @$symbols );
413 @redefine_ = keys( %a );
414 }; # if
415 foreach my $line ( @redefine_ ) {
416 $line =~ s{$prefix(\W+)}{$1$prefix};
417 push( @redefine, $line );
418 }
419 write_file( $syms_file, \@redefine );
420 foreach my $src ( sort( keys( %$objects ) ) ) {
421 my $dst = cat_file( $target, get_file( $src ) );
422 if ( @redefine ) {
423 execute( [ "objcopy", "--redefine-syms", $syms_file, $src, $dst ] );
424 } else {
425 copy_file( $src, $dst, -overwrite => 1 );
426 }; # if
427 }; # foreach $object
428
429}; # sub copy_objects
430
431
432# --------------------------------------------------------------------------------------------------
433# Main.
434# --------------------------------------------------------------------------------------------------
435
436my $base = {};
437my $extra = {};
438my $switcher = $base;
439my $dump = 0;
440my $print_base;
441my $print_extra;
442my $copy_base;
443my $copy_extra;
444my $prefix;
445
446# Parse command line.
447
448Getopt::Long::Configure( "permute" );
449get_options(
450 Platform::target_options(),
451 "base" => sub { $switcher = $base; },
452 "extra" => sub { $switcher = $extra; },
453 "print-base" => \$print_base,
454 "print-extra" => \$print_extra,
455 "print-all" => sub { $print_base = 1; $print_extra = 1; },
456 "copy-base=s" => \$copy_base,
457 "copy-extra=s" => \$copy_extra,
458 "copy-all=s" => sub { $copy_base = $_[ 1 ]; $copy_extra = $_[ 1 ]; },
459 "dump" => sub { ++ $dump; },
460 "prefix=s" => \$prefix,
461 "<>" =>
462 sub {
463 my $arg = $_[ 0 ];
464 my @args;
465 if ( $^O eq "MSWin32" ) {
466 # Windows* OS does not expand wildcards. Do it...
467 @args = bsd_glob( $arg );
468 } else {
469 @args = ( $arg );
470 }; # if
471 foreach my $object ( @args ) {
472 if ( exists( $base->{ $object } ) or exists( $extra->{ $object } ) ) {
473 die "Object \"$object\" has already been specified.\n";
474 }; # if
475 $switcher->{ $object } = { defined => [], undefined => [] };
476 }; # foreach
477 },
478);
479if ( not %$base ) {
480 cmdline_error( "No base objects specified" );
481}; # if
482
483if ( $target_os eq "win" ) {
484 *load_symbols = \&_load_symbols_link;
485} elsif ( $target_os eq "lin" or $target_os eq "lrb" ) {
486 *load_symbols = \&_load_symbols_nm;
487} elsif ( $target_os eq "mac" ) {
488 *load_symbols = \&_load_symbols_nm;
489} else {
490 runtime_error( "OS \"$target_os\" not supported" );
491}; # if
492
493# Do the work.
494
495my $required = required_extra_objects( $base, $extra, $dump );
496if ( $print_base ) {
497 print( map( "$_\n", sort( keys( %$base ) ) ) );
498}; # if
499if ( $print_extra ) {
500 print( map( "$_\n", sort( keys( %$required ) ) ) );
501}; # if
502my @symbols;
503if ( defined( $prefix ) ) {
504 foreach my $object ( sort( keys( %$required ) ) ) {
505 push( @symbols, @{ $required->{ $object }->{ defined } } );
506 }; # foreach $objects
507}; # if
508if ( $copy_base ) {
509 copy_objects( $base, $copy_base, $prefix, @symbols );
510}; # if
511if ( $copy_extra ) {
512 copy_objects( $required, $copy_extra, $prefix, @symbols );
513}; # if
514
515exit( 0 );
516
517__END__
518
519=pod
520
521=head1 NAME
522
523B<required-objects.pl> -- Select a required extra object files.
524
525=head1 SYNOPSIS
526
527B<required-objects.pl> I<option>... [--base] I<file>... --extra I<file>...
528
529=head1 DESCRIPTION
530
531B<required-objects.pl> works with two sets of object files -- a set of I<base> objects
532and a set of I<extra> objects, and selects those extra objects which are required for resolving
533undefined symbols in base objects I<and> selected extra objects.
534
535Selected object files may be copied to specified location or their names may be printed to stdout,
536a name per line. Additionally, symbols defined in selected extra objects may be renamed.
537
538Depending on OS, different external tools may be used. For example, B<required-objects.pl> uses
539F<link.exe> on "win" and F<nm> on "lin" and "mac" OSes. Normally OS is autodetected, but
540detection can be overrided with B<--os> option. It may be helpful in cross-build environments.
541
542=head1 OPTIONS
543
544=over
545
546=item B<--base>
547
548The list of base objects follows this option.
549
550=item B<--extra>
551
552List of extra objects follows this option.
553
554=item B<--print-all>
555
556Print list of base objects and list of required extra objects.
557
558=item B<--print-base>
559
560Print list of base objects.
561
562=item B<--print-extra>
563
564Print list of selected extra objects.
565
566=item B<--copy-all=>I<dir>
567
568Copy all base and selected extra objects to specified directory. The directory must exist. Existing
569files are overwritten.
570
571=item B<--copy-base=>I<dir>
572
573Copy all base objects to specified directory.
574
575=item B<--copy-extra=>I<dir>
576
577Copy selected extra objects to specified directory.
578
579=item B<--prefix=>I<str>
580
581If prefix is specified, copied object files are edited -- symbols defined in selected extra
582object files are renamed (in all the copied object files) by adding this prefix.
583
584F<objcopy> program should be available for performing this operation.
585
586=item B<--os=>I<str>
587
588Specify OS name. By default OS is autodetected.
589
590Depending on OS, B<required-objects.pl> uses different external tools.
591
592=item B<--help>
593
594Print short help message and exit.
595
596=item B<--doc>
597
598=item B<--manual>
599
600Print full documentation and exit.
601
602=item B<--version>
603
604Print version and exit.
605
606=back
607
608=head1 ARGUMENTS
609
610=over
611
612=item I<file>
613
614A name of object file.
615
616=back
617
618=head1 EXAMPLES
619
620 $ required-objects.pl --base obj/*.o --extra ../lib/obj/*.o --print-extra > required.lst
621 $ ar cr libx.a obj/*.o $(cat required.lst)
622
623 $ required-objects.pl --base internal/*.o --extra external/*.o --prefix=__xyz_ --copy-all=obj
624 $ ar cr xyz.a obj/*.o
625
626=cut
627
628# end of file #
629