1#! perl
2################################################################################
3# Copyright (C) 2001-2003, Parrot Foundation.
4################################################################################
5
6=head1 NAME
7
8tools/dev/lib_deps.pl - List libc dependencies
9
10=head1 SYNOPSIS
11
12    % perl tools/dev/lib_deps.pl [object | source] file1 [file2 ...]
13
14=head1 DESCRIPTION
15
16This script is intended to give us an idea of what C<libc> functions
17this build depends upon.
18
19=head2 Options
20
21=over 4
22
23=item C<object>
24
25In C<object> mode, it expects a list of all parrot's object files. It
26runs C<nm> on each and determines what external functions are being
27called. Note that it assumes a gnu-ish C<nm>.
28
29=item C<source>
30
31In C<source> mode, it uses a the C<cxref> program
32(L<http://www.gedanken.demon.co.uk/cxref/>) to extract information from
33the program source about what functions are being called, what includes
34are used, etc.  This mode is potentially more thorough, but a bit more
35magical and therefore less conclusive.
36
37=back
38
39=cut
40
41################################################################################
42
43use strict;
44use warnings;
45use File::Find;
46use File::Spec;
47
48my %defined_in;
49my %referenced_in;
50my %ansi_c89_symbol;
51my %ansi_c89_header;
52
53my ( $mode, @files ) = @ARGV;
54
55if ( $mode !~ /^(source|object)$/ || !@files ) {
56    die "Usage: $0 object <object files..>\n" . "       $0 source <source files..>\n";
57}
58
59while (<DATA>) {
60    next if /^\s*#/;
61    chomp;
62    next unless $_;
63    my ( $symbol, $file ) = /(\S+)\s+(\S+)/;
64    $ansi_c89_symbol{$symbol} = $file unless ( $symbol eq "UNDEF" );
65    push @{ $ansi_c89_header{$file} }, $symbol;
66}
67
68if ( $mode eq "object" ) {
69    do_object();
70}
71else {
72    do_source();
73}
74
75exit(0);
76
77##############################################################################
78
79sub do_source {
80
81    if ( $files[0] eq "all_source" ) {
82
83        # do a little "find" action for now.
84
85        @files = ();
86        File::Find::find(
87            {
88                wanted => sub {
89                    /^.*\.[ch]\z/s
90                        && push @files, $File::Find::name;
91                    }
92            },
93            '.'
94        );
95    }
96
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 -Iinclude/pmc -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";
106
107    my %external_calls;
108    my %internal_calls;
109    my %variable_visible;
110    my %system_include;
111    my ( $file, $function, $variable );
112    while (<$F>) {
113
114        if (/----------------------------------------/) {
115            undef $file if defined($file);
116            next;
117        }
118
119        if (/^INCLUDES : '(.*)' \[System file\]/) {
120            next if ( $1 =~ /^include\// );
121            $system_include{$1}{$file}++;
122            next;
123        }
124
125        if ( !$file && /^FILE : '(.*)'$/ ) {
126            $file = $1;
127            next;
128        }
129
130        # skip anything between files.
131        next unless $file;
132
133        # beginning of function block
134        if (/FUNCTION : (.*) \[(.*)\]/) {
135            $function = $1;
136            my $function_scope = $2;
137
138            next;
139        }
140
141        # end of function block
142        if ( $function && /^\s*$/ ) {
143            undef $function;
144            next;
145        }
146
147        # beginning of variable block
148        if (/VARIABLE : (.*) \[(.*)\]/) {
149            $variable = $1;
150            my $variable_scope = $2;
151            if ( $variable_scope eq "Local" ) {
152                $variable_visible{$file}{$1}++;
153            }
154            else {
155                $variable_visible{"ALL"}{$1}++;
156            }
157
158            next;
159        }
160
161        # end of variable block
162        if ( $variable && /^\s*$/ ) {
163            undef $variable;
164            next;
165        }
166
167        if ($function) {
168            if (/Calls (.*) : (.*)/) {
169
170                # calling another function within parrot.
171                $internal_calls{$1}{"$file:$function"}++
172                    unless ( $variable_visible{$file}{$1}
173                    || $variable_visible{ALL}{$1} );
174            }
175            elsif (/Calls (.*)/) {
176
177                # calling a function outside of parrot!
178                $external_calls{$1}{"$file:$function"}++
179                    unless ( $variable_visible{$file}{$1}
180                    || $variable_visible{ALL}{$1} );
181            }
182        }
183    }
184
185    close($F);
186
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;
191
192    printf(
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) );
197
198    foreach (@non_ansi_external_calls) {
199        print "    $_:\n";
200        foreach ( sort keys %{ $external_calls{$_} } ) {
201            print "        $_\n";
202        }
203    }
204
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} } ) {
210                print "        $file\n";
211            }
212        }
213    }
214}
215
216sub do_object {
217    foreach my $obj (@files) {
218        open( my $F, '-|', "nm -a $obj" ) || die "Can't run nm -a $obj\n";
219
220        while (<$F>) {
221            chomp;
222
223            my ( $type, $symbol ) = /^.+ (\S) (.*)/;
224
225            if ( $type eq 'U' ) {
226                $defined_in{$symbol} ||= undef;
227                push @{ $referenced_in{$symbol} }, $obj;
228            }
229            else {
230                $defined_in{$symbol} .= "$obj ";
231            }
232        }
233
234        close($F);
235    }
236
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;
240
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;
244
245    printf(
246        "Found %d symbols defined within the %d supplied object files.\n",
247        scalar(@internal_symbols),
248        scalar(@files)
249    );
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) );
252
253    print "    $_ (in " . ( join ',', @{ $referenced_in{$_} } ) . ")\n"
254        foreach (@non_ansi_external_symbols);
255}
256
257__END__
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)
261abort       stdlib.h
262abs         stdlib.h
263acos        math.h
264acosf       math.h
265acosh       math.h
266acoshf      math.h
267acoshl      math.h
268acosl       math.h
269arg         complex.h
270asctime     time.h
271asin        math.h
272asinf       math.h
273asinh       math.h
274asinhf      math.h
275asinhl      math.h
276asinl       math.h
277atan        math.h
278atan2       math.h
279atan2f      math.h
280atan2l      math.h
281atanf       math.h
282atanh       math.h
283atanhf      math.h
284atanhl      math.h
285atanl       math.h
286atexit      stdlib.h
287atof        stdlib.h
288atoi        stdlib.h
289atol        stdlib.h
290atoll       stdlib.h
291bsearch     stdlib.h
292cabs        complex.h
293cabsf       complex.h
294cabsl       complex.h
295cacos       complex.h
296cacosf      complex.h
297cacosh      complex.h
298cacoshf     complex.h
299cacoshl     complex.h
300cacosl      complex.h
301calloc      stdlib.h
302carg        complex.h
303cargf       complex.h
304cargl       complex.h
305casin       complex.h
306casinf      complex.h
307casinh      complex.h
308casinhf     complex.h
309casinhl     complex.h
310casinl      complex.h
311catan       complex.h
312catanf      complex.h
313catanh      complex.h
314catanhf     complex.h
315catanhl     complex.h
316catanl      complex.h
317cbrt        math.h
318cbrtf       math.h
319cbrtl       math.h
320ccos        complex.h
321ccosf       complex.h
322ccosh       complex.h
323ccoshf      complex.h
324ccoshl      complex.h
325ccosl       complex.h
326ceil        math.h
327ceilf       math.h
328ceill       math.h
329cexp        complex.h
330cexpf       complex.h
331cexpl       complex.h
332cimag       complex.h
333cimagf      complex.h
334cimagl      complex.h
335clearerr    stdio.h
336clock       time.h
337clog        complex.h
338clogf       complex.h
339clogl       complex.h
340conj        complex.h
341conjf       complex.h
342conjl       complex.h
343copysign    math.h
344copysignf   math.h
345copysignl   math.h
346cos         math.h
347cosf        math.h
348cosh        math.h
349coshf       math.h
350coshl       math.h
351cosl        math.h
352cpow        complex.h
353cpowf       complex.h
354cpowl       complex.h
355cproj       complex.h
356cprojf      complex.h
357cprojl      complex.h
358creal       complex.h
359crealf      complex.h
360creall      complex.h
361csin        complex.h
362csinf       complex.h
363csinh       complex.h
364csinhf      complex.h
365csinhl      complex.h
366csinl       complex.h
367csqrt       complex.h
368csqrtf      complex.h
369csqrtl      complex.h
370ctan        complex.h
371ctanf       complex.h
372ctanh       complex.h
373ctanhf      complex.h
374ctanhl      complex.h
375ctanl       complex.h
376ctime       time.h
377difftime    time.h
378div         stdlib.h
379erf         math.h
380erfc        math.h
381erfcf       math.h
382erfcl       math.h
383erff        math.h
384erfl        math.h
385errno       errno.h
386exit        stdlib.h
387exp         math.h
388exp2        math.h
389exp2f       math.h
390exp2l       math.h
391expf        math.h
392expl        math.h
393expm1       math.h
394expm1f      math.h
395expm1l      math.h
396fabs        math.h
397fabsf       math.h
398fabsl       math.h
399fclose      stdio.h
400fdim        math.h
401fdimf       math.h
402fdiml       math.h
403feof        stdio.h
404ferror      stdio.h
405fflush      stdio.h
406fgetc       stdio.h
407fgetpos     stdio.h
408fgets       stdio.h
409floor       math.h
410floorf      math.h
411floorl      math.h
412fma         math.h
413fmaf        math.h
414fmal        math.h
415fmax        math.h
416fmaxf       math.h
417fmaxl       math.h
418fmin        math.h
419fminf       math.h
420fminl       math.h
421fmod        math.h
422fmodf       math.h
423fmodl       math.h
424fopen       stdio.h
425fpclassify  math.h
426fprintf     stdio.h
427fputc       stdio.h
428fputs       stdio.h
429fread       stdio.h
430free        stdlib.h
431freopen     stdio.h
432frexp       math.h
433frexpf      math.h
434frexpl      math.h
435fscanf      stdio.h
436fseek       stdio.h
437fsetpos     stdio.h
438ftell       stdio.h
439fwrite      stdio.h
440getc        stdio.h
441getchar     stdio.h
442getenv      stdlib.h
443gets        stdio.h
444gmtime      time.h
445hypot       math.h
446hypotf      math.h
447hypotl      math.h
448ilogb       math.h
449ilogbf      math.h
450ilogbl      math.h
451imag        complex.h
452isalnum     ctype.h
453isalpha     ctype.h
454isblank     ctype.h
455iscntrl     ctype.h
456isdigit     ctype.h
457isfinite    math.h
458isgraph     ctype.h
459isgreater   math.h
460isgreatereq math.h
461isinf       math.h
462isless      math.h
463islessequal math.h
464islessgreat math.h
465islower     ctype.h
466isnan       math.h
467isnormal    math.h
468isprint     ctype.h
469ispunct     ctype.h
470isspace     ctype.h
471isunordered math.h
472isupper     ctype.h
473isxdigit    ctype.h
474labs        stdlib.h
475ldexp       math.h
476ldexpf      math.h
477ldexpl      math.h
478ldiv        stdlib.h
479lgamma      math.h
480lgammaf     math.h
481lgammal     math.h
482llabs       stdlib.h
483llrint      math.h
484llrintf     math.h
485llrintl     math.h
486llround     math.h
487llroundf    math.h
488llroundl    math.h
489localeconv  locale.h
490localtime   time.h
491log         math.h
492log10       math.h
493log10f      math.h
494log10l      math.h
495log1p       math.h
496log1pf      math.h
497log1pl      math.h
498log2        math.h
499log2f       math.h
500log2l       math.h
501logb        math.h
502logbf       math.h
503logbl       math.h
504logf        math.h
505logl        math.h
506longjmp     setjmp.h
507lrint       math.h
508lrintf      math.h
509lrintl      math.h
510lround      math.h
511lroundf     math.h
512lroundl     math.h
513malloc      stdlib.h
514mblen       stdlib.h
515mbstowcs    stdlib.h
516mbtowc      stdlib.h
517memchr      string.h
518memcmp      string.h
519memcpy      string.h
520memmove     string.h
521memset      string.h
522mktime      time.h
523modf        math.h
524modff       math.h
525modfl       math.h
526nan         math.h
527nanf        math.h
528nanl        math.h
529nearbyint   math.h
530nearbyintf  math.h
531nearbyintl  math.h
532nextafter   math.h
533nextafterf  math.h
534nextafterl  math.h
535nexttoward  math.h
536nexttowardf math.h
537nexttowardl math.h
538perror      stdio.h
539pow         math.h
540printf      stdio.h
541putc        stdio.h
542putchar     stdio.h
543puts        stdio.h
544qsort       stdlib.h
545raise       signal.h
546rand        stdlib.h
547real        complex.h
548realloc     stdlib.h
549remainder   math.h
550remainderf  math.h
551remainderl  math.h
552remove      stdio.h
553remquo      math.h
554remquof     math.h
555remquol     math.h
556rename      stdio.h
557rewind      stdio.h
558rint        math.h
559rintf       math.h
560rintl       math.h
561round       math.h
562roundf      math.h
563roundl      math.h
564scalbln     math.h
565scalblnf    math.h
566scalblnl    math.h
567scalbn      math.h
568scalbnf     math.h
569scalbnl     math.h
570scanf       stdio.h
571setbuf      stdio.h
572setlocale   locale.h
573setvbuf     stdio.h
574signal      signal.h
575signbit     math.h
576sin         math.h
577sinf        math.h
578sinh        math.h
579sinhf       math.h
580sinhl       math.h
581sinl        math.h
582sprintf     stdio.h
583sqrt        math.h
584sqrtf       math.h
585sqrtl       math.h
586srand       stdlib.h
587sscanf      stdio.h
588stderr      stdio.h
589stdin       stdio.h
590stdout      stdio.h
591strcat      string.h
592strchr      string.h
593strcmp      string.h
594strcoll     string.h
595strcpy      string.h
596strcspn     string.h
597strerror    string.h
598strftime    time.h
599strlen      string.h
600strncat     string.h
601strncmp     string.h
602strncpy     string.h
603strpbrk     string.h
604strrchr     string.h
605strspn      string.h
606strstr      string.h
607strtod      stdlib.h
608strtof      stdlib.h
609strtok      string.h
610strtol      stdlib.h
611strtold     stdlib.h
612strtoll     stdlib.h
613strtoul     stdlib.h
614strtoull    stdlib.h
615strxfrm     string.h
616system      stdlib.h
617tan         math.h
618tanf        math.h
619tanh        math.h
620tanhf       math.h
621tanhl       math.h
622tanl        math.h
623tgamma      math.h
624tgammaf     math.h
625tgammal     math.h
626time        time.h
627tmpfile     stdio.h
628tmpnam      stdio.h
629tolower     ctype.h
630toupper     ctype.h
631trunc       math.h
632truncf      math.h
633truncl      math.h
634ungetc      stdio.h
635vfprintf    stdio.h
636vfscanf     stdio.h
637vprintf     stdio.h
638vscanf      stdio.h
639vsprintf    stdio.h
640vsscanf     stdio.h
641UNDEF       assert.h
642UNDEF       stdarg.h
643
644# Local Variables:
645# mode: cperl
646# cperl-indent-level: 4
647# fill-column: 100
648# End:
649# vim: expandtab shiftwidth=4:
650