2 ################################################################################
3 # Copyright (C) 2001-2003, Parrot Foundation.
5 ################################################################################
9 tools/dev/lib_deps.pl - List libc dependencies
13 % perl tools/dev/lib_deps.pl [object | source] file1 [file2 ...]
17 This script is intended to give us an idea of what C<libc> functions
18 this build depends upon.
26 In C<object> mode, it expects a list of all parrot's object files. It
27 runs C<nm> on each and determines what external functions are being
28 called. Note that it assumes a gnu-ish C<nm>.
32 In C<source> mode, it uses a the C<cxref> program
33 (L<http://www.gedanken.demon.co.uk/cxref/>) to extract information from
34 the program source about what functions are being called, what includes
35 are used, etc. This mode is potentially more thorough, but a bit more
36 magical and therefore less conclusive.
42 ################################################################################
54 my ( $mode, @files ) = @ARGV;
56 if ( $mode !~ /^(source|object)$/ || !@files ) {
57 die "Usage: $0 object <object files..>\n" . " $0 source <source files..>\n";
63 my ( $symbol, $file ) = /(\S+)\s+(\S+)/;
64 $ansi_c89_symbol{$symbol} = $file unless ( $symbol eq "UNDEF" );
65 push @
{ $ansi_c89_header{$file} }, $symbol;
68 if ( $mode eq "object" ) {
77 ##############################################################################
81 if ( $files[0] eq "all_source" ) {
83 # do a little "find" action for now.
90 && push @files, $File::Find
::name
;
97 # note: need to run this a second time so the database is built.
98 # should just use the build process to do it the first time.
99 my $devnull = File
::Spec
->devnull;
100 my $cmd = "cxref -raw -Iinclude -xref @files";
101 print "Running cxref (pass 1)\n";
102 system("$cmd > $devnull 2>$devnull");
103 print "Running cxref (pass 2)\n";
104 open( my $F, '<', "$cmd 2>$devnull|" )
105 || die "Can't run $cmd.\n";
109 my %variable_visible;
111 my ( $file, $function, $variable );
114 if (/----------------------------------------/) {
115 undef $file if defined($file);
119 if (/^INCLUDES : '(.*)' \[System file\]/) {
120 next if ( $1 =~ /^include\// );
121 $system_include{$1}{$file}++;
125 if ( !$file && /^FILE : '(.*)'$/ ) {
130 # skip anything between files.
133 # beginning of function block
134 if (/FUNCTION : (.*) \[(.*)\]/) {
136 my $function_scope = $2;
141 # end of function block
142 if ( $function && /^\s*$/ ) {
147 # beginning of variable block
148 if (/VARIABLE : (.*) \[(.*)\]/) {
150 my $variable_scope = $2;
151 if ( $variable_scope eq "Local" ) {
152 $variable_visible{$file}{$1}++;
155 $variable_visible{"ALL"}{$1}++;
161 # end of variable block
162 if ( $variable && /^\s*$/ ) {
168 if (/Calls (.*) : (.*)/) {
170 # calling another function within parrot.
171 $internal_calls{$1}{"$file:$function"}++
172 unless ( $variable_visible{$file}{$1}
173 || $variable_visible{ALL
}{$1} );
175 elsif (/Calls (.*)/) {
177 # calling a function outside of parrot!
178 $external_calls{$1}{"$file:$function"}++
179 unless ( $variable_visible{$file}{$1}
180 || $variable_visible{ALL
}{$1} );
187 # filter out things that start with _. Probably internal libc stuff.
188 my @external_calls = grep { !/^_/ } sort keys %external_calls;
189 my @internal_calls = grep { !/^_/ } sort keys %internal_calls;
190 my @non_ansi_external_calls = grep { !exists( $ansi_c89_symbol{$_} ) } @external_calls;
193 "Found %d functions which are defined and called within the %d supplied source files.\n",
194 scalar(@internal_calls), scalar(@files) );
195 printf( "Found %d external functions which were called.\n", scalar(@external_calls) );
196 printf( "Of these, %d are not defined by ANSI C89:\n", scalar(@non_ansi_external_calls) );
198 foreach (@non_ansi_external_calls) {
200 foreach ( sort keys %{ $external_calls{$_} } ) {
205 print "\nThe following non-ansi system includes are used:\n";
206 foreach my $include ( sort keys %system_include ) {
207 if ( !exists( $ansi_c89_header{$include} ) ) {
208 print " $include, included by:\n";
209 foreach my $file ( sort keys %{ $system_include{$include} } ) {
217 foreach my $obj (@files) {
218 open( my $F, '<', "nm -a $obj|" ) || die "Can't run nm on $obj\n";
223 my ( $type, $symbol ) = /^........ (\S) (.*)/;
225 if ( $type eq 'U' ) {
226 $defined_in{$symbol} ||= undef;
227 push @
{ $referenced_in{$symbol} }, $obj;
230 $defined_in{$symbol} .= "$obj ";
237 # omit symbols which begin with _. These are likely to be internal
238 # variables used by libc macros.
239 my @symbols = grep { !/^_/ } sort keys %defined_in;
241 my @external_symbols = sort grep { !defined( $defined_in{$_} ) } @symbols;
242 my @internal_symbols = sort grep { defined( $defined_in{$_} ) } @symbols;
243 my @non_ansi_external_symbols = grep { !exists( $ansi_c89_symbol{$_} ) } @external_symbols;
246 "Found %d symbols defined within the %d supplied object files.\n",
247 scalar(@internal_symbols),
250 printf( "Found %d external symbols\n", scalar(@external_symbols) );
251 printf( "Of these, %d are not defined by ANSI C89:\n", scalar(@non_ansi_external_symbols) );
253 print " $_ (in " . ( join ',', @
{ $referenced_in{$_} } ) . ")\n"
254 foreach (@non_ansi_external_symbols);
258 # The following symbols are available in a C89 Hosted Implementation
259 # (not sure if I got this right- it came from a C99 reference, so some 99isms
260 # might have slipped in)
646 # cperl-indent-level: 4
649 # vim: expandtab shiftwidth=4: