1#!@PERL@ -w
2
3# Merges several static libraries (*.a) into a single library.  Tries
4# to maintain the order of the members as it was in the original
5# libraries.  Multiple members of the same name may be present in
6# different input libraries and correctly packaged.  However, if
7# multiple members with the same name reside in the same input
8# library, only the last one will be used.
9
10use strict;
11
12my $usageString = "unpack.pl <tmpdir> lib1.a lib2.a ...
13Unpacks all .o files from lib1.a, lib2.a, etc into <tmpdir> and prints the list
14of .o files on the standard output";
15
16if($#ARGV < 1) {
17    print STDERR "temp dir and at least 1 input name must be given.\n";
18    print STDERR "$usageString\n";
19    exit 1;
20}
21
22my $tmpDir = $ARGV[0];
23my @inFiles = @ARGV[1..$#ARGV];
24
25my $currDir = `pwd`; $currDir =~ s/\n//g;
26
27# Create the database of members: mappings of each file to the
28# respective library name, and to the list of members in the original
29# order
30
31my %libName=();
32my %members=();
33my $countLibs=0;
34my $countMembers=0;
35
36# List of input files without repetition
37my @tmp = ();
38
39for(my $i=0; $i<=$#inFiles; $i++) {
40    # Skip the library if we've seen it already
41    if(!defined($libName{$inFiles[$i]})) {
42	push @tmp, $inFiles[$i];
43	$countLibs++;
44	if($inFiles[$i] =~ m/lib(\w+).a$/) {
45	    $libName{$inFiles[$i]} = $1;
46	    my $lines=`ar t '$inFiles[$i]'`;
47	    my @lines = split(/\n/, $lines);
48	    $countMembers += ($#lines + 1);
49	    $members{$inFiles[$i]} = [@lines];
50	} else {
51	    print STDERR "Weird library name: $inFiles[$i]; skipping it";
52	}
53    } else {
54	print STDERR "Repeated input (ignored): $inFiles[$i]\n";
55    }
56}
57
58print STDERR "Found $countMembers members in $countLibs libraries\n";
59
60# Update the list of input files (remove repetitions)
61@inFiles = @tmp;
62
63# Given a possibly relative path, compute the full path
64sub fullPath {
65    my ($name) = @_;
66    if($name =~ m@^/@) {
67	# It's already the full path
68	return $name;
69    } else {
70	return "$currDir/$name";
71    }
72}
73
74# Unpack files and create the list of members with relative paths into tmpDir
75my @allMembers=();
76
77mkdir($tmpDir, 0755) or die "Cannot create $tmpDir/: $?";
78for(my $i=0; $i<=$#inFiles; $i++) {
79    my $libName = $libName{$inFiles[$i]};
80    my $file = fullPath($inFiles[$i]);
81    print STDERR "Unpacking $libName\n";
82    mkdir("$tmpDir/$libName", 0755)
83	or die "Cannot create $tmpDir/$libName: $?";
84    system("cd '$tmpDir/$libName'; ar x '$file'")
85	&& die "Cannot extract from archive $file: $?";
86    my @names=@{$members{$inFiles[$i]}};
87    for(my $j=0; $j<=$#names; $j++) {
88        if ($names[$j] =~ /^.*\.o/i) {
89	    push @allMembers, "'$tmpDir/$libName/$names[$j]'";
90        }
91    }
92}
93
94# Create the list of all members
95my $allMembers = join(" ", @allMembers);
96print "$allMembers";
97