blob: 04be6ea82daa607102fa064eff2704cf0f908b7a [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001#!/usr/bin/env 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 File::Temp;
19use Cwd;
20
21use FindBin;
22use lib "$FindBin::Bin/lib";
23
24use tools;
25use Uname;
26use Platform ":vars";
27
28our $VERSION = "0.005";
29
30# --------------------------------------------------------------------------------------------------
31# Subroutines.
32# --------------------------------------------------------------------------------------------------
33
34sub windows {
35 my ( $arch, $output, @args ) = @_;
36 my %files;
37 # TODO: Check the archives are of specified architecture.
38 foreach my $arg ( @args ) {
39 foreach my $archive ( bsd_glob( $arg ) ) {
40 info( "Processing \"$archive\"..." );
41 my $bulk;
42 execute( [ "lib.exe", "/nologo", "/list", $archive ], -stdout => \$bulk );
43 my @members = split( "\n", $bulk );
44 foreach my $member ( @members ) {
45 my $file = get_file( $member );
46 my $path = cat_file( $output, $file );
47 if ( exists( $files{ $file } ) ) {
48 runtime_error(
49 "Extraction \"$file\" member from \"$archive\" archive failed:",
50 "\"$file\" member has already been extracted from \"$files{ $file }\" archive"
51 );
52 }; # if
53 $files{ $file } = $archive;
54 info( " Writing \"$path\"..." );
55 execute( [ "lib.exe", "/nologo", "/extract:" . $member, "/out:" . $path, $archive ] );
56 }; # foreach $member
57 }; # foreach $archive
58 }; # foreach $arg
59}; # sub windows
60
61sub linux {
62 my ( $arch, $output, @archives ) = @_;
63 # TODO: Check the archives are of specified architecture.
64 my $cwd = Cwd::cwd();
65 change_dir( $output );
66 foreach my $archive ( @archives ) {
67 info( "Processing \"$archive\"..." );
68 my $path = abs_path( $archive, $cwd );
69 execute( [ "ar", "xo", $path ] );
70 }; # foreach $archive
71 change_dir( $cwd );
72}; # sub linux
73
74my %mac_arch = (
75 "32" => "i386",
76 "32e" => "x86_64"
77);
78
79sub darwin {
80 my ( $arch, $output, @archives ) = @_;
81 my $cwd = getcwd();
82 change_dir( $output );
83 if ( defined( $arch ) ) {
84 if ( not defined( $mac_arch{ $arch } ) ) {
85 runtime_error( "Architecture \"$arch\" is not a valid one for OS X*" );
86 }; # if
87 $arch = $mac_arch{ $arch };
88 }; # if
89 foreach my $archive ( @archives ) {
90 info( "Processing \"$archive\"..." );
91 my $path = abs_path( $archive, $cwd );
92 my $temp;
93 # Whether archive is a fat or thin?
94 my $bulk;
95 execute( [ "file", $path ], -stdout => \$bulk );
96 if ( $bulk =~ m{Mach-O universal binary} ) {
97 # Archive is fat, extracy thin archive first.
98 if ( not defined( $arch ) ) {
99 runtime_error(
100 "\"$archive\" archive is universal binary, " .
101 "please specify architecture to work with"
102 );
103 }; # if
104 ( undef, $temp ) = File::Temp::tempfile();
105 execute( [ "libtool", "-static", "-arch_only", $arch, "-o", $temp, $path ] );
106 $path = $temp;
107 }; # if
108 execute( [ "ar", "xo", $path ] ); # Extract members.
109 if ( defined( $temp ) ) { # Delete temp file, if any.
110 del_file( $temp );
111 }; # if
112 }; # foreach $archive
113 change_dir( $cwd );
114}; # sub darwin
115
116
117# --------------------------------------------------------------------------------------------------
118# Main.
119# --------------------------------------------------------------------------------------------------
120
121# Parse command line.
122
123my $output = ".";
124my @args;
125
126get_options(
127 Platform::target_options(),
128 "o|output-directory=s" => \$output,
129);
130@args = @ARGV;
131
132if ( not -e $output ) {
133 runtime_error( "Output directory \"$output\" does not exist" );
134}; # if
135if ( not -d $output ) {
136 runtime_error( "\"$output\" is not a directory" );
137}; # if
138if ( not -w $output ) {
139 runtime_error( "Output directory \"$output\" is not writable" );
140}; # if
141
142if ( $target_os eq "win" ) {
143 *process = \&windows;
144} elsif ( $target_os eq "lin" or $target_os eq "lrb" ) {
145 *process = \&linux;
146} elsif ( $target_os eq "mac" ) {
147 *process = \&darwin;
148} else {
149 runtime_error( "OS \"$target_os\" not supported" );
150}; # if
151
152
153# Do the work.
154process( $target_arch, $output, @args );
155exit( 0 );
156
157__END__
158
159=pod
160
161=head1 NAME
162
163B<extract-objects.pl> -- Extract all object files from static library.
164
165=head1 SYNOPSIS
166
167B<extract-objects.pl> I<option>... I<archive>...
168
169=head1 OPTIONS
170
171=over
172
173=item B<--architecture=>I<arch>
174
175Specify architecture to work with. The option is mandatory on OS X* in case of universal archive.
176In other cases the option should not be used. I<arch> may be one of C<32> or C<32e>.
177
178=item B<--os=>I<str>
179
180Specify OS name. By default OS is autodetected.
181
182Depending on OS, B<extract-objects.pl> uses different external tools for handling static
183libraries: F<ar> (in case of "lin" and "mac") or F<lib.exe> (in case of "win").
184
185=item B<--output-directory=>I<dir>
186
187Specify directory to write extracted members to. Current directory is used by default.
188
189=item B<--help>
190
191Print short help message and exit.
192
193=item B<--doc>
194
195=item B<--manual>
196
197Print full documentation and exit.
198
199=item B<--quiet>
200
201Do not print information messages.
202
203=item B<--version>
204
205Print version and exit.
206
207=back
208
209=head1 ARGUMENTS
210
211=over
212
213=item I<archive>
214
215A name of archive file (static library). Multiple archives may be specified.
216
217=back
218
219=head1 DESCRIPTION
220
221The script extracts all the members (object files) from archive (static library) to specified
222directory. Commands to perform this action differ on different OSes. On Linux* OS, simple command
223
224 ar xo libfile.a
225
226is enough (in case of extracting files to current directory).
227
228On OS X*, it is a bit compilicated with universal ("fat") binaries -- C<ar> cannot
229operate on fat archives, so "thin" archive should be extracted from the universal binary first.
230
231On Windows* OS, library manager (C<lib.exe>) can extract only one object file, so operation should be
232repeated for every object file in the library.
233
234B<extract-objects.pl> detects OS automatically. But detection can be overrided with B<--os> option.
235It may be helpful in cross-build environments.
236
237B<extract-objects.pl> effectively encapsulates all these details and provides uniform way for
238extracting object files from static libraries, which helps to keep makefiles simple and clean.
239
240=head1 EXAMPLES
241
242Extract object files from library F<libirc.lib>, and put them into F<obj/> directory:
243
244 $ extract-objects.pl --output=obj libirc.lib
245
246Extract object files from library F<libirc.a>. Use Linux* OS tools (F<ar>), even if run on another OS:
247
248 $ extract-objects.pl --os=lin libirc.a
249
250Extract object files from library F<libirc.a>, if it is a OS X* universal binary, use i386
251architecture. Be quiet:
252
253 $ extract-objects.pl --quiet --arch=i386 libirc.a
254
255=cut
256
257# end of file #
258