]> git.saurik.com Git - apple/libsystem.git/blob - libsys/build-libc.pl
ff11e1d8df248f1b7707a3f0e5e5ae20583f4dd1
[apple/libsystem.git] / libsys / build-libc.pl
1 #!/usr/bin/perl
2 #
3 # Copyright (c) 2006-2007 Apple Inc. All rights reserved.
4 #
5 # @APPLE_LICENSE_HEADER_START@
6 #
7 # This file contains Original Code and/or Modifications of Original Code
8 # as defined in and that are subject to the Apple Public Source License
9 # Version 2.0 (the 'License'). You may not use this file except in
10 # compliance with the License. Please obtain a copy of the License at
11 # http://www.opensource.apple.com/apsl/ and read it before using this
12 # file.
13 #
14 # The Original Code and all software distributed under the License are
15 # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 # Please see the License for the specific language governing rights and
20 # limitations under the License.
21 #
22 # @APPLE_LICENSE_HEADER_END@
23 #
24 ##########################################################################
25 #
26 # % build-libc.pl usr-local-lib-system out-directory
27 #
28 # This script takes the directory full of the contents libc-partial*.a and
29 # libsyscall*.a, and makes the necessary symbol aliases for those syscalls
30 # that aren't being wrapped in Libc. The usr-local-lib-system is the
31 # /usr/local/lib/system or equivalent directory where the necessary symbol
32 # files from Libc and Libsyscall reside.
33 #
34 # A Makefile is created that will build libc*.a from the contents of the
35 # out-directory after symbol aliasing has been added.
36 #
37 # The out-directory path must be of the form ".../arch/form", where arch is
38 # the architecture being built and form is one of debug, dynamic and profile.
39 #
40 ##########################################################################
41
42 use strict;
43 use DirHandle;
44 use File::Basename ();
45 use File::Copy ();
46 use File::Spec;
47 use IO::File;
48
49 my $MyName = File::Basename::basename($0);
50
51 my $OutDir;
52 my %Stub;
53 my %StubArgs;
54 my $StubFile = 'libsyscall.list';
55 my %Suffix = (
56 debug => ['do', '_debug'],,
57 dynamic => ['So', ''],,
58 profile => ['po', '_profile'],,
59 );
60 my $SyscallBase = 'libc.syscall';
61
62 ##########################################################################
63 # Scan the archive for existing wrappers, and remove them from the stub
64 # list.
65 ##########################################################################
66 sub processLibc {
67 my($arch, $dir, $sufname) = @_;
68 local $_;
69 my $file = File::Spec->join($dir, "libc-partial$sufname.a");
70 my $f = IO::File->new("nm -g -arch $arch $file |");
71 die "$MyName: nm -g -arch $arch $file: $!\n" unless defined($f);
72 while(<$f>) {
73 next unless s/^.* T //;
74 chomp;
75 delete($Stub{$_});
76 }
77 }
78
79 ##########################################################################
80 # Read the libc.syscall and any libc.syscall.arch file for additional aliases
81 # for the double underbar syscalls.
82 ##########################################################################
83 sub readLibcSyscalls {
84 my($arch, $dir) = @_;
85 local $_;
86 my @files = (File::Spec->join($dir, $SyscallBase));
87 my $archfile = File::Spec->join($dir, "$SyscallBase.$arch");
88 if(-r $archfile) {
89 push(@files, $archfile);
90 } elsif($arch =~ s/^armv.*/arm/) {
91 $archfile = File::Spec->join($dir, "$SyscallBase.$arch");
92 push(@files, $archfile) if -r $archfile;
93 }
94 foreach my $file (@files) {
95 my $f = IO::File->new($file, 'r');
96 die "$MyName: $file: $!\n" unless defined($f);
97 while(<$f>) {
98 next if /^#/;
99 chomp;
100 my($k, $v) = split;
101 if(defined($v)) {
102 $Stub{$k} = $v;
103 } else {
104 delete($Stub{$k});
105 }
106 }
107 }
108 }
109
110 ##########################################################################
111 # Read the libsyscall.list file for the system call names and number
112 # of arguments and store in %StubArgs. Also, make an entry for a syscall
113 # stub.
114 ##########################################################################
115 sub readStub {
116 my $dir = shift;
117 local $_;
118 my $file = File::Spec->join($dir, $StubFile);
119 my $f = IO::File->new($file, 'r');
120 die "$MyName: $file: $!\n" unless defined($f);
121 while(<$f>) {
122 chomp;
123 my($k, $v) = split;
124 if(!($k =~ s/^#//)) {
125 $_ = $k;
126 s/^__//;
127 $Stub{$_} = $k;
128 }
129 $StubArgs{$k} = $v;
130 }
131 }
132
133 sub usage {
134 die "Usage: $MyName usr-local-lib-system out-directory\n";
135 }
136
137 usage() unless scalar(@ARGV) == 2;
138 my($usr_local_lib_system);
139 ($usr_local_lib_system, $OutDir) = @ARGV;
140 die "$MyName: $usr_local_lib_system: No such directory\n" unless -d $usr_local_lib_system;
141 die "$MyName: $OutDir: No such directory\n" unless -d $OutDir;
142 my @pieces = File::Spec->splitdir($OutDir);
143 my $form = pop(@pieces);
144 my $arch = pop(@pieces);
145 my $suf = $Suffix{$form};
146 die "$MyName: $form: Unknown form\n" unless defined($suf);
147 my($suffix, $sufname) = @$suf;
148 readStub($usr_local_lib_system);
149 readLibcSyscalls($arch, $usr_local_lib_system);
150 processLibc($arch, $usr_local_lib_system, $sufname);
151
152 ##########################################################################
153 # Invert the Stub hash, so the key will correspond to the file to process.
154 # The value will be an array ref containing all aliases.
155 ##########################################################################
156 my %Inv;
157 while(my($k, $v) = each(%Stub)) {
158 my $a = $Inv{$v};
159 $a = $Inv{$v} = [] if !defined($a);
160 push(@$a, $k);
161 }
162
163 ##########################################################################
164 # Create the Makefile file
165 ##########################################################################
166 my $path = File::Spec->join($OutDir, 'Makefile');
167 my $f = IO::File->new($path, 'w');
168 die "$MyName: $path: $!\n" unless defined($f);
169
170 ##########################################################################
171 # List all the object files
172 ##########################################################################
173 my $dir = DirHandle->new($OutDir);
174 die "$MyName: can't open $dir\n" unless defined($dir);
175 print $f "OBJS = libsystem.o \\\n";
176 my @objs;
177 while(defined($_ = $dir->read())) {
178 next unless s/\.$suffix$/.o/;
179 push(@objs, $_);
180 }
181 undef $dir;
182 printf $f "\t%s\n", join(" \\\n\t", @objs);
183
184 ##########################################################################
185 # Add the build logic
186 ##########################################################################
187 print $f <<XXX;
188
189 LIB = libc$sufname.a
190
191 all: \$(LIB)
192
193 \$(LIB): \$(OBJS)
194 ar cq \$(.TARGET) `lorder \$(OBJS) | tsort -q`
195
196 .SUFFIXES: .$suffix
197
198 .$suffix.o:
199 mv \$(.IMPSRC) \$(.TARGET)
200
201 XXX
202
203 ##########################################################################
204 # Special case each binary that needs aliasing
205 ##########################################################################
206 foreach my $k (sort(keys(%Inv))) {
207 my $n = $k;
208 $n =~ s/^_//;
209 print $f "$n.o: $n.$suffix\n";
210 print $f "\tld -arch $arch -r -keep_private_externs";
211 foreach my $i (@{$Inv{$k}}) {
212 $_ = $i;
213 s/\$/\$\$/g;
214 printf $f " -alias '$k' '$_'";
215 }
216 printf $f " -o \$(.TARGET) \$(.IMPSRC)\n";
217 }