source: branches/gcc/SOURCE_TOOLS/needed_libs.pl

Last change on this file was 19810, checked in by westram, 3 weeks ago
  • Property svn:executable set to *
File size: 31.9 KB
Line 
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6my $debug_verboose;
7# BEGIN {
8  # $debug_verboose = 1;
9  # $SIG{__DIE__} = sub {
10    # require Carp;
11    # if ($debug_verboose>0) { Carp::confess(@_); } # with backtrace
12    # else { Carp::croak(@_); }
13  # }
14# }
15
16my $dieOnUndefEnvvar = 1; # use '-U' to toggle
17
18my $libdepend_file = 'needs_libs';
19my $exedepend_dir  = 'BINDEP';
20
21# --------------------------------------------------------------------------------
22
23my $ARBHOME = $ENV{ARBHOME};
24defined $ARBHOME || die "Environmentvariable 'ARBHOME' is not defined";
25-d $ARBHOME || die "ARBHOME does not point to a directory ($ARBHOME)";
26if (not $ARBHOME =~ /\/$/o) { $ARBHOME .= '/'; }
27my $AH_len = length($ARBHOME);
28
29sub ARBHOME_relative($) {
30  my ($dir) = @_;
31  defined $dir || die;
32  if (substr($dir,0,$AH_len) eq $ARBHOME) { substr($dir,$AH_len); }
33  else { $dir; }
34}
35
36sub fullpath($) {
37  my ($path) = @_;
38  return $ARBHOME.ARBHOME_relative($path);
39}
40
41# --------------------------------------------------------------------------------
42
43my $LINK_STATIC = $ENV{LINK_STATIC};
44# LINK_STATIC==1 (used on OSX) ->
45# - shared ARB-libraries (e.g. lib/libWINDOW.so) are created/linked statically (as lib/libWINDOW.a)
46# - in contrast to "normal" static libs
47#   - they do NOT reside in the source-code directory and
48#   - they have a 'lib'-prefix
49
50sub fixFileSuffix($) {
51  my ($file) = @_;
52  defined $LINK_STATIC || die "Environmentvariable 'LINK_STATIC' is not defined";
53  if ($LINK_STATIC==1) { # true on OSX
54    $file =~ s/\.so/\.a/; # correct lib-suffix
55  }
56  $file;
57}
58
59# --------------------------------------------------------------------------------
60
61sub dirOf($) {
62  my ($full) = @_;
63  if ($full =~ /\/([^\/]+)$/o) { $`; }
64  else { undef; }
65}
66
67sub filenameOf($) {
68  my ($full) = @_;
69  defined $full || die;
70  if ($full =~ /\/([^\/]+)$/o) { $1; }
71  else { $full; }
72}
73
74sub trim($) {
75  my ($str) = @_;
76  $str =~ s/^\s+//go;
77  $str =~ s/\s+$//go;
78  return $str;
79}
80
81# --------------------------------------------------------------------------------
82
83sub legal_target_or_die($) {
84  my ($target) = @_;
85
86  my $ct = $target;
87  $ct =~ s/ $//g;
88  $ct =~ s/^ //g;
89
90  if ($ct ne $target) {
91    die "Invalid target '$target' (chomped='$ct')";
92  }
93}
94
95my $reg_exedepend = qr/^$exedepend_dir\/$libdepend_file\./;
96my $reg_depend = qr/\/$libdepend_file/;
97
98sub dependencyFile2target($) {
99  my ($depfile) = @_;
100
101  $depfile = ARBHOME_relative($depfile);
102  my $target = undef;
103  if ($depfile =~ $reg_exedepend) {
104    $target = $';
105  }
106  elsif ($depfile =~ $reg_depend) {
107    my ($dir,$suffix) = ($`,$');
108    my $libname = undef;
109    if ($suffix eq '') { # default (DIR/DIR.a)
110      my $lastDir = filenameOf($dir);
111      $libname = $lastDir.'.a';
112    }
113    else {
114      $libname = substr($suffix,1);
115      $libname =~ s/\_(so|a|o)$/\.$1/o;
116      if ($1 eq 'so') {
117        $dir = 'lib';
118      }
119    }
120    $target = $dir.'/'.$libname;
121    if ($target eq 'lib/lib.dummy') {
122      die "Generated invalid target '$target'";
123    }
124  }
125  else {
126    die "Illegal dependency file '$depfile'";
127  }
128
129  return $target;
130}
131
132sub target2dependencyFile($) {
133  my ($target) = @_;
134
135  $target = ARBHOME_relative($target);
136  legal_target_or_die($target);
137
138  my $depfile = undef;
139  my $dir     = dirOf($target);
140
141  if (defined $dir) {
142    if ($dir eq 'lib') {
143      if ($target =~ /^lib\/lib([A-Z]+)\.(so|a)$/) {
144        $depfile = $1.'/'.$libdepend_file.'.lib'.$1.'_so';
145      }
146      else {
147        $depfile = "failed to parse libname from '$target'";
148      }
149    }
150    else {
151      my $lastdir    = filenameOf($dir);
152      my $defaultLib = $dir.'/'.$lastdir.'.a';
153
154      if ($target eq $defaultLib) {
155        $depfile = $dir.'/'.$libdepend_file;
156      }
157      else {
158        my $targetName =  filenameOf($target);
159        $targetName    =~ s/\.(so|a|o)$/_$1/o;
160        $depfile       =  $dir.'/'.$libdepend_file.'.'.$targetName;
161      }
162    }
163  }
164  else { # no dir -> must be executable
165    $depfile = $exedepend_dir.'/'.$libdepend_file.'.'.$target;
166  }
167  return $depfile;
168}
169
170# --------------------------------------------------------------------------------
171
172my $errors = 0;
173
174sub if_errors_abortNow() {
175  if ($errors>0) { die "Errors occurred - abort!\n"; }
176}
177
178sub show_location($$$) {
179  my ($location,$message,$type) = @_;
180  if (defined $location) { print STDERR $location.': '.$type.': '.$message."\n"; }
181  else { print STDERR '(unknown source): '.$type.': '.$message."\n"; }
182}
183sub location_error($$) {
184  my ($location,$error) = @_;
185  show_location($location,$error,'Error');
186  $errors++;
187}
188sub location_warning($$) {
189  my ($location,$warning) = @_;
190  show_location($location,$warning,'Warning');
191}
192sub location_note($$) {
193  my ($location,$note) = @_;
194  show_location($location,$note,'Note');
195}
196
197# --------------------------------------------------------------------------------
198
199# values for %target_type:
200my $DYNAMIC_LIB  = 0;
201my $STATIC_LIB   = 1;
202my $EXECUTABLE   = 2;
203my $EXTRA_PARAMS = 3;
204
205my %inheritants_of      = (); # key=target; value=ref to hash (key=inheritant of target; value=location in definition file)
206my %target_type         = (); # key=target; value: see above
207my %dependencies_of     = (); # key=target; value=ref to hash (containing direct dependencies: key=dependency, value=1)
208my %all_dependencies_of = (); # key=target; value=ref to hash (containing all    dependencies: key=dependency, value=1)
209
210sub get_inheritance_location($$) {
211  my ($inheritor,$dependency) = @_;
212  my $inh_r = $inheritants_of{$dependency};
213  return $$inh_r{$inheritor};
214}
215
216sub show_why_inherits($$$);
217sub show_why_inherits($$$) {
218  my ($inheritor,$dependency,$depth) = @_;
219
220  return if $inheritor eq $dependency;
221  die "aborting deep dependency recursion (assuming unfixed cyclic dependency)" if $depth>20;
222
223  my $INDENT = '';
224  if ($depth>1) { $INDENT = "[$depth] "; }
225
226  my $location = get_inheritance_location($inheritor,$dependency);
227  if (defined $location) {
228    location_note($location, "$INDENT'$inheritor' depends on '$dependency' here");
229  }
230  else {
231    my $direct_dep_r = $dependencies_of{$inheritor};
232    my $recursed = 0;
233    foreach my $direct_dep (keys %$direct_dep_r) {
234      my $all_sub_r = $all_dependencies_of{$direct_dep};
235      if (defined $$all_sub_r{$dependency}) {
236        $location = get_inheritance_location($inheritor,$direct_dep);
237        location_note($location, "$INDENT'$inheritor' depends on '$dependency' via '$direct_dep'");
238        show_why_inherits($direct_dep, $dependency, $depth+1);
239        $recursed++;
240      }
241    }
242    if (not $recursed) { die "expected to find dependency from '$inheritor' to '$dependency'"; }
243  }
244}
245
246sub warn_bad_dependency($) {
247  my ($target) = @_;
248
249  my $directly_depends_on_r = $dependencies_of{$target};
250  foreach my $sub (keys %$directly_depends_on_r) {
251    my $sub_depends_r = $all_dependencies_of{$sub};
252
253    # check multi dependencies:
254    foreach my $some_dep (keys %$sub_depends_r) {
255      if (($some_dep ne $sub) and (defined $$directly_depends_on_r{$some_dep})) { # multi dependency
256        my $some_dep_location = get_inheritance_location($target,$some_dep);
257        location_warning($some_dep_location, "Duplicated dependency of '$target' from '$some_dep'");
258
259        my $sub_location = get_inheritance_location($target,$sub);
260        location_note($sub_location, "already depends on '$some_dep' via '$sub'");
261
262        show_why_inherits($sub, $some_dep, 1);
263      }
264    }
265
266    # check cyclic dependencies:
267    if (defined $$sub_depends_r{$target}) {
268      my $sub_location = get_inheritance_location($target,$sub);
269      location_error($sub_location, "Cyclic dependency between $target and $sub");
270      show_why_inherits($sub, $target, 1);
271    }
272  }
273}
274
275sub warn_bad_dependencies() {
276  foreach (keys %inheritants_of) {
277    warn_bad_dependency($_);
278  }
279}
280
281# --------------------------------------------------------------------------------
282
283sub dump_dependencies() {
284  foreach my $dependency (sort keys %inheritants_of) {
285    print STDERR "------------------------------------ inheriting $dependency\n";
286    my $inherit_locations_r = $inheritants_of{$dependency};
287    foreach my $inheritant (keys %$inherit_locations_r) {
288      my $location = $$inherit_locations_r{$inheritant};
289      location_warning($location, "'$dependency' inherited by '$inheritant'");
290    }
291  }
292}
293
294# --------------------------------------------------------------------------------
295
296sub prefix($$) {
297  my ($maybePrefix,$path) = @_;
298  if (defined $maybePrefix) { $maybePrefix.'/'.$path; }
299  else { $path; }
300}
301
302sub dynamic_name($) {
303  my ($target) = @_;
304  my $name = filenameOf($target);
305  if ($name =~ /^lib(.*)\.so$/o) { $1; }
306  else { undef; }
307}
308
309sub assert_defined($) {
310  my ($val) = @_;
311  use Carp;
312  defined $val || Carp::confess("undef");
313  return $val;
314}
315
316sub is_dynamic_lib($) { my ($target) = @_; return $target_type{$target} == $DYNAMIC_LIB; }
317sub is_static_lib($)  { my ($target) = @_; return assert_defined($target_type{$target}) == $STATIC_LIB; }
318sub is_extra_param($) { my ($target) = @_; return $target_type{$target} == $EXTRA_PARAMS; }
319sub is_executable($)  { my ($target) = @_; return $target_type{$target} == $EXECUTABLE; }
320
321sub is_library($)  { my ($target) = @_; return is_static_lib($target) || is_dynamic_lib($target); }
322sub is_file($)     { my ($target) = @_; return is_library($target) || is_executable($target); }
323
324# --------------------------------------------------------------------------------
325
326sub declare_initial_target($$) {
327  my ($target,$type) = @_;
328
329  if ($target ne '') {
330    legal_target_or_die($target);
331
332    my $inherit_locations_r = $inheritants_of{$target};
333    if (not defined $inherit_locations_r) {
334      my %new_hash = ();
335      $inheritants_of{$target} = \%new_hash;
336      $target_type{$target} = $type;
337    }
338    else {
339      $target_type{$target}==$type || die "type mismatch for initial '$target' (".$target_type{$target}." vs $type)\n";
340    }
341  }
342}
343
344sub detect_target_type($) {
345  my ($target) = @_;
346
347  if ($target =~ /\.(so|a|o)$/o) {
348    if ($1 eq 'so') { $DYNAMIC_LIB; }
349    else { $STATIC_LIB; }
350  }
351  else { $EXECUTABLE; }
352}
353
354sub detect_type_and_declare_initial_target($) {
355  my ($target) = @_;
356
357  my $type = detect_target_type($target);
358  declare_initial_target($target,$type);
359}
360
361# --------------------------------------------------------------------------------
362
363sub scan_dependsfile_entry($$$) {
364  my ($line, $inheritant, $location) = @_;
365
366  my $analyse = 1;
367  my $type = undef;
368
369  if ($line =~ /^\$\((.*)\)$/o) {
370    my $envvar = $1;
371    my $env = $ENV{$envvar};
372    if (not defined $env) {
373      if ($dieOnUndefEnvvar==1) { die "Undefined environment variable '$envvar'\n"; }
374      $type = $EXTRA_PARAMS;
375      $analyse = 0;
376    }
377    else {
378      $line = $env;
379      $line =~ s/\s\s/ /g;
380      $line =~ s/^\s//g;
381      $line =~ s/\s$//g;
382    }
383  }
384
385  if ($analyse==1) {
386    if ($line =~ /-[lL]/o) {
387      $type = $EXTRA_PARAMS;
388    }
389    else {
390      $line = ARBHOME_relative($line);
391      $type = detect_target_type($line);
392    }
393    $analyse = 0;
394  }
395
396  defined $type || die "could not detect line type\n";
397
398  my $target = $line;
399  declare_initial_target($target,$type);
400
401  my $inherit_locations_r = $inheritants_of{$target};
402  $$inherit_locations_r{$inheritant} = $location;
403}
404
405
406my %scanned = (); # key=dependsfile, value=1 -> already scanned
407
408sub scan_target($) {
409  my ($target) = @_;
410
411  my $depfile = target2dependencyFile($target);
412
413  if (not defined $scanned{$depfile}) {
414    $scanned{$depfile} = 1;
415
416    my $fulldep = fullpath($depfile);
417
418    if (not -f $fulldep) {
419      my $dir = dirOf($fulldep);
420      my $err = "Missing dependency file for '$target'";
421      if (not -d $dir) { $err .= " (No such directory '$dir')"; }
422      my $location = $fulldep.':0';
423      location_error($location,$err);
424    }
425    else {
426      open(IN,'<'.$fulldep) || die "can't read '$fulldep' (Reason: $!)";
427      my $lineno = 0;
428      foreach (<IN>) {
429        $lineno++;
430        chomp;
431        if ($_ =~ /\#/) { $_ = $`; } # remove comments
432        $_ = trim($_); # remove whitespace
433
434        if ($_ ne '') {  # skip empty lines
435          my $location = $fulldep.':'.$lineno;
436          eval {
437            scan_dependsfile_entry($_, $target, $location);
438          };
439          if ($@) {
440            location_error($location, $@);
441          }
442        }
443      }
444      close(IN);
445    }
446  }
447}
448
449sub rec_add_depends_to_hash($\%);
450sub rec_add_depends_to_hash($\%) {
451  my ($target,$hash_r) = @_;
452
453  my $all_dep_r = $all_dependencies_of{$target};
454  if (defined $all_dep_r) {
455    foreach (keys %$all_dep_r) {
456      $$hash_r{$_} = 1;
457    }
458  }
459  else {
460    my $dep_r = $dependencies_of{$target};
461    foreach (keys %$dep_r) {
462      if (not defined $$hash_r{$_}) {
463        $$hash_r{$_} = 1;
464        rec_add_depends_to_hash($_,%$hash_r);
465      }
466    }
467  }
468}
469
470sub resolve_dependencies() {
471  my $done = 0;
472  my $target;
473  while ($done==0) {
474    my %unscanned = ();
475    foreach my $target (keys %inheritants_of) {
476      if ($target_type{$target} != $EXTRA_PARAMS) { # recurse dependency
477        my $depfile = target2dependencyFile($target);
478        if (not defined $scanned{$depfile}) {
479          if ($target eq '') {
480            my $inh_r = $inheritants_of{$target};
481            foreach (keys %$inh_r) {
482              my $loc = $$inh_r{$_};
483              location_error($loc, "Empty target inherited from here");
484            }
485          }
486          else {
487            $unscanned{$target} = 1;
488          }
489        }
490      }
491    }
492
493    my @unscanned = sort keys %unscanned;
494    if (scalar(@unscanned)) {
495      foreach $target (@unscanned) { scan_target($target); }
496    }
497    else {
498      $done = 1;
499    }
500  }
501
502  # build %dependencies_of
503
504  foreach $target (keys %inheritants_of) {
505    my %new_hash = ();
506    $dependencies_of{$target} = \%new_hash;
507  }
508  foreach $target (keys %inheritants_of) {
509    my $inherit_locations_r = $inheritants_of{$target};
510    foreach my $inheritant (keys %$inherit_locations_r) {
511      if ($target eq $inheritant) {
512        my $self_include_loc = get_inheritance_location($inheritant, $target);
513        location_error($self_include_loc, "Illegal self-dependency");
514      }
515      my $dep_r = $dependencies_of{$inheritant};
516      $$dep_r{$target} = 1;
517    }
518  }
519
520  if_errors_abortNow();
521
522  # build %all_dependencies_of
523
524  my @targets = keys %dependencies_of;
525  my %depends_size = map {
526    my $dep_r = $dependencies_of{$_};
527    $_ => scalar(keys %$dep_r);
528  } @targets;
529
530  @targets = sort { $depends_size{$a} <=> $depends_size{$b}; } @targets; # smallest first
531
532  foreach $target (@targets) {
533    my %new_hash = ();
534    rec_add_depends_to_hash($target,%new_hash);
535    $all_dependencies_of{$target} = \%new_hash;
536  }
537}
538
539# --------------------------------------------------------------------------------
540
541my $reg_is_libdepend_file = qr/^($libdepend_file|$libdepend_file\..*)$/;
542
543sub find_dep_decl_files($\@);
544sub find_dep_decl_files($\@) {
545  my ($dir,$found_r) = @_;
546  $dir =~ s/\/\//\//og;
547  my @subdirs = ();
548  opendir(DIR,$dir) || die "can't read directory '$dir' (Reason: $!)";
549  foreach (readdir(DIR)) {
550    if ($_ ne '.' and $_ ne '..') {
551      my $full = $dir.'/'.$_;
552      if (not -l $full) {
553        if (-d $full) {
554          if (not $_ =~ /\.(svn|git)$/o) { push @subdirs, $full; }
555        }
556        elsif ($_ =~ $reg_is_libdepend_file) { push @$found_r, ARBHOME_relative($full); }
557      }
558    }
559  }
560  closedir(DIR);
561  foreach (@subdirs) { find_dep_decl_files($_,@$found_r); }
562}
563
564my %dep2lib = (
565               'ARBDB/needs_libs.libARBDB_so'   => 'lib/libARBDB.so',
566               'AWT/needs_libs.libAWT_so'       => 'lib/libAWT.so',
567               'CORE/needs_libs.libCORE_so'     => 'lib/libCORE.so',
568               'WINDOW/needs_libs.libWINDOW_so' => 'lib/libWINDOW.so',
569
570               'GL/glAW/needs_libs.libglAW_a'       => 'GL/glAW/libglAW.a',
571               'GL/glpng/needs_libs.libglpng_arb_a' => 'GL/glpng/libglpng_arb.a',
572
573               'PROBE_COM/needs_libs.client_a' => 'PROBE_COM/client.a',
574               'PROBE_COM/needs_libs.server_a' => 'PROBE_COM/server.a',
575               'NAMES_COM/needs_libs.client_a' => 'NAMES_COM/client.a',
576               'NAMES_COM/needs_libs.server_a' => 'NAMES_COM/server.a',
577
578               'ptpan/needs_libs.PROBE_a' => 'ptpan/PROBE.a',
579              );
580
581sub libdepend_file_2_libname($) {
582  my ($dep) = @_;
583  if (defined $dep2lib{$dep}) {
584    $dep = $dep2lib{$dep};
585  }
586  elsif ($dep =~ /^(.*)\/([^\/]*)/) {
587    my ($dir,$name) = ($1,$2);
588    if ($name =~ $reg_is_libdepend_file) {
589      if ($dep =~ /BINDEP\/needs_libs\./) {
590        $dep = $';
591      }
592      else {
593        my ($prefix,$targetdir) = ('',undef);
594
595        if ($dir =~ /^(.*)\/([^\/]*)/) {
596          my ($path,$lastdir) = ($1,$2);
597          $path =~ s/^.\///;
598          $prefix = $path.'/';
599          $targetdir = $lastdir;
600        }
601        else {
602          $targetdir = $dir;
603        }
604
605        my $target = undef;
606        if ($name =~ /^needs_libs\.(.*)_o$/) {
607          $target = $targetdir.'/'.$1.'.o';
608        }
609        else {
610          $target = $targetdir.'/'.$targetdir.'.a';
611        }
612
613        $dep = $prefix.$target;
614      }
615    }
616  }
617  return $dep;
618}
619
620sub declare_all_targets() {
621  my @depfiles = ();
622  find_dep_decl_files($ARBHOME,@depfiles);
623  foreach my $depfile (sort @depfiles) {
624    my $target = dependencyFile2target($depfile);
625    detect_type_and_declare_initial_target($target);
626  }
627}
628
629# --------------------------------------------------------------------------------
630
631sub dot_label($) {
632  my ($target) = @_;
633  if (is_file($target)) { $target = filenameOf($target); }
634  return '"'.$target.'"';
635}
636
637sub generateDependencyGraph(\@\@$$) {
638  my ($depends_r,$targets_r,$gif,$bundleExe) = @_;
639
640  my $base;
641  if ($gif =~ /\.gif$/) {
642    $base = $`;
643  }
644  else {
645    $base = $gif;
646    $gif = $base.'.gif';
647  }
648
649  my $dotfile = $base.'.dot';
650  my $maxsize_X = 20; # inch
651  my $maxsize_Y = 17; # inch
652
653  open(DOT,'>'.$dotfile) || die "can't write to '$dotfile' (Reason: $!)";
654  print DOT "digraph ARBLIBDEP {\n";
655  print DOT "  rankdir=LR;\n";
656  print DOT "  concentrate=true;\n";
657  print DOT "  searchsize=1000;\n";
658  print DOT "  Damping=2.0;\n";
659  print DOT "  size=\"$maxsize_X,$maxsize_Y\";\n";
660  print DOT "  orientation=portrait;\n";
661  print DOT "\n";
662
663  my %wanted_depend = map { $_ => 1; } @$depends_r;
664
665  my $seen_binary = 0;
666
667  my %execount = ();
668
669  foreach my $exe (keys %inheritants_of) {
670    if ($target_type{$exe}==$EXECUTABLE) {
671      my $deps_r = $all_dependencies_of{$exe};
672      foreach (keys %$deps_r) {
673        my $count = $execount{$_};
674        $count = (defined $count) ? $count+1 : 1;
675        $execount{$_} = $count;
676      }
677    }
678  }
679
680  my %is_target = map { $_ => 1; } @$targets_r;
681
682  foreach my $target (@$depends_r) {
683    my $deps_r = $dependencies_of{$target};
684    my $type = $target_type{$target};
685
686    if (not defined $type) {
687      use Carp;
688      Carp::confess("no target_type has been defined for '$target' (misspelled or directory missing?) ");
689    }
690
691    my $dtarget = dot_label($target);
692
693    my $color = 'black';
694    my $shape = 'box';
695    my $style = '';
696
697    if ($type==$EXECUTABLE)   { $color = 'green'; $shape = 'ellipse'; }
698    if ($type==$DYNAMIC_LIB)  { $color = 'blue'; }
699    if ($type==$STATIC_LIB)   { ; }
700    if ($type==$EXTRA_PARAMS) { $color = 'red'; $shape = 'box'; }
701
702    if ($is_target{$target}) {
703      $color = '"#ffbb66"';
704      $style = 'style=filled';
705    }
706
707    my $peri = $execount{$target};
708    $peri = defined $peri ? $peri : 1;
709
710    print DOT '    '.$dtarget.' [';
711    print DOT ' color='.$color;
712    print DOT ' shape='.$shape;
713    print DOT ' peripheries='.$peri;
714    print DOT ' '.$style;
715    print DOT '];'."\n";
716
717    if ($type==$EXECUTABLE) {
718      if ($bundleExe==1) {
719        if ($seen_binary==0) {
720          print DOT '    executables [';
721          print DOT ' color=yellow';
722          print DOT '];'."\n";
723          $seen_binary = 1;
724        }
725        print DOT '    executables -> '.$dtarget.';'."\n";
726      }
727    }
728
729    foreach my $depend (keys %$deps_r) {
730      if (defined $wanted_depend{$depend}) {
731        my $ddepend = dot_label($depend);
732        print DOT '    '.$dtarget.' -> '.$ddepend.';'."\n";
733      }
734    }
735  }
736  print DOT "}\n";
737  close(DOT);
738  print STDERR "Wrote $dotfile\n";
739
740  my $cmd = 'dot -Tgif -o'.$gif.' '.$dotfile;
741  print STDERR $cmd."\n";
742  system($cmd)==0 || die "Failed to execute '$cmd'";
743
744  unlink($dotfile) || die "Failed to unlink '$dotfile' (Reason: $!)";
745}
746
747# --------------------------------------------------------------------------------
748
749sub pushDirsTo($\@\@) {
750  my ($pathPrefix,$depends_r,$out_r) = @_;
751  my @out = ();
752  foreach my $dep (@$depends_r) {
753    if (is_static_lib($dep)) {
754      my $dir  = dirOf($dep);
755      defined $dir || die "no dir for '$dep'";
756      my $name = filenameOf($dir);
757      push @out, prefix($pathPrefix,$dir.'/'.$name);
758    }
759    elsif (is_dynamic_lib($dep)) {
760      if ($dep =~ /^lib\/lib([A-Z_]+)\.so/) {
761        my $base = $1;
762        push @out, prefix($pathPrefix,$base.'/'.$base);
763      }
764      else {
765        die "malformed (unexpected) dependency name for shared lib ('$dep')";
766      }
767    }
768  }
769
770  foreach (sort @out) { push @$out_r, $_; }
771}
772
773sub pushFilesTo($\@\@) {
774  my ($pathPrefix,$depends_r,$out_r) = @_;
775  foreach my $dep (@$depends_r) {
776    if (is_file($dep)) {
777      push @$out_r, fixFileSuffix(prefix($pathPrefix,$dep));
778    }
779  }
780}
781
782sub sortLibsByDependency(\@) {
783  # sort libs for linker CL (fullfilling libs behind requesting libs)
784  my ($libs_r) = @_;
785  my @order = ();
786  my %added = map { $_ => 0; } @$libs_r;
787
788  while (scalar(@order) < scalar(@$libs_r)) {
789    my $didAdd = 0;
790    foreach my $lib (@$libs_r) {
791      if ($added{$lib}==0) { # not added yet
792        my $all_dep_r = $all_dependencies_of{$lib};
793        my $missing = 0;
794      CHECK: foreach my $dep (keys %$all_dep_r) {
795          my $was_added = $added{$dep};
796          if (defined $was_added) {
797            if ($was_added==0) { $missing = 1; last CHECK; }
798          }
799        }
800        if ($missing==0) {
801          push @order, $lib;
802          $added{$lib} = 1;
803          $didAdd = 1;
804        }
805      }
806    }
807    if ($didAdd==0) {
808      die "internal error: did not add any lib in last loop (undetected nested dependency?)";
809    }
810  }
811  @$libs_r = reverse @order;
812}
813
814sub pushStaticLibsTo($\@\@) {
815  my ($pathPrefix,$depends_r,$out_r) = @_;
816  my @libs = ();
817  foreach my $dep (@$depends_r) { if (is_static_lib($dep)) { push @libs, $dep; } }
818  sortLibsByDependency(@libs);
819  foreach (@libs) { push @$out_r, prefix($pathPrefix,$_); }
820}
821
822sub pushDynamicLibsTo(\@\@) {
823  my ($depends_r,$out_r) = @_;
824  my @dep = ();
825  foreach my $dep (@$depends_r) { if (is_dynamic_lib($dep)) { push @dep, $dep; } }
826  sortLibsByDependency(@dep);
827  foreach (@dep) { push @$out_r, '-l'.dynamic_name($_); }
828  foreach my $dep (@$depends_r) { if (is_extra_param($dep)) { push @$out_r, $dep; } }
829}
830
831# --------------------------------------------------------------------------------
832
833sub die_usage($) {
834  my ($err) = @_;
835  print "Usage: needed_libs.pl [options] [lib|obj|executable]\n";
836  print "Scans directories of 'lib|obj's for files named '$libdepend_file' or '$libdepend_file.libname'\n";
837  print "In case of an executable, it scans for a file named 'BINDEP/$libdepend_file.executable'.\n";
838  print "\n";
839  print "These files have to contain the name(s) of the libraries needed by 'lib', either\n";
840  print "as ARBHOME-relative path to the lib file or\n";
841  print "as link instruction (containing '-l') for non-ARB-libraries\n";
842  print "\n";
843  print "Libraries in directory '\$ARBHOME/lib' are handled special:\n";
844  print "- they need to be specified as lib/libNAME.so\n";
845  print "- their source directory is assumed to be \$ARBHOME/NAME\n";
846  print "- they are called 'dynamic' in the context of this script (even if \$LINK_STATIC=1, where they aren't dynamic)\n";
847  print "\n";
848  print "They may as well contain \${ENVVAR}\n";
849  print "If no '$libdepend_file' exists, the 'lib' is assumed to be independent.\n";
850  print "\n";
851  print "If the filename is 'DIR/$libdepend_file', the library is assumed to be 'DIR/DIR.a'\n";
852  print "\n";
853  print "options:\n";
854  print "  -D             output dirs lib depends on (e.g. ARBDB/ARBDB SL/ARB_TREE/ARB_TREE ..)\n";
855  print "  -F             output all libfiles the given lib depends on (e.g. ARBDB/libARBDB.so SL/ARB_TREE/ARB_TREE.a ..)\n";
856  print "                 (suffix used for \"dynamic\" libs depends on setting of \$LINK_STATIC)\n";
857  print "  -l             output link params (e.g. -lARBDB SL/ARB_TREE/ARB_TREE.a ..)\n";
858  print "  -L             same as -l, but link whole archive for the specified library (i.e. for the tested unit)\n";
859  print "  -s             output names of \"static\" libs (e.g. SL/ARB_TREE/ARB_TREE.a ..)\n";
860  print "  -d             output names of \"dynamic\" libs (e.g. -lARBDB ..)\n";
861  print "  -A dir         prefix paths with 'dir' (not for \"dynamic\" libs)\n";
862  print "  -U             do not die on undefined environment variables\n";
863  print "  -G outgif      Draw dependency graph (using dot)\n";
864  print "  -V             Dump dependencies\n";
865  print "  -n [<depth>]   print nested dependencies down to depth (default=all)\n";
866  print "  -N [<depth>]   print nested inheritants up to depth (default=all)\n";
867  print "  -I             Invert (print inheritants instead of dependencies)\n";
868  print "  -B             Both (print inheritants and dependencies)\n";
869  print "  -S             Include self (lib/exe given on command line)\n";
870  print "  -T             only show terminals (=those w/o dependencies and/or inheritants)\n";
871
872  die "Error: $err\n" if defined $err;
873  exit(1);
874}
875
876
877sub main() {
878  my @targets = ();
879
880  my $printDirs       = 0;
881  my $printFiles      = 0;
882  my $printStatic     = 0;
883  my $printDynamic    = 0;
884  my $linkWholeTarget = 0;
885  my $pathPrefix      = undef;
886  my $dependencyGraph = undef;
887  my $dump            = 0;
888  my $trackDepends    = 1;
889  my $dependsNesting  = -1; # -1 means infinite
890  my $inheritsNesting = -1; # -1 means infinite
891  my $trackInherits   = 0;
892  my $includeSelf     = 0;
893  my $onlyTerminals   = 0;
894
895  if (not @ARGV) {
896    die_usage("no arguments specified");
897  }
898
899  while (scalar(@ARGV)) {
900    $_ = shift @ARGV;
901    if ($_ =~ /^-/o) {
902      my $switch = $';
903      if    ($switch eq 'D') { $printDirs = 1; }
904      elsif ($switch eq 'F') { $printFiles = 1; }
905      elsif ($switch eq 'd') { $printDynamic = 1; }
906      elsif ($switch eq 's') { $printStatic = 1; }
907      elsif ($switch eq 'l') { $printStatic = 1; $printDynamic = 1; }
908      elsif ($switch eq 'L') { $printStatic = 1; $printDynamic = 1; $linkWholeTarget = 1; }
909      elsif ($switch eq 'A') { $pathPrefix = shift @ARGV; }
910      elsif ($switch eq 'U') { $dieOnUndefEnvvar = 0; }
911      elsif ($switch eq 'G') { $dependencyGraph = shift @ARGV; }
912      elsif ($switch eq 'V') { $dump = 1; }
913      elsif ($switch eq 'n' or $switch eq 'N') {
914        my $num = 1;
915        if (scalar(@ARGV) and $ARGV[0] =~ /^[0-9]+$/o) { $num = shift @ARGV; }
916        if    ($switch eq 'n') { $dependsNesting = $num; }
917        elsif ($switch eq 'N') { $inheritsNesting = $num; }
918        else { die; }
919      }
920      elsif ($switch eq 'I') { $trackInherits = 1; $trackDepends = 0; }
921      elsif ($switch eq 'B') { $trackInherits = 1; }
922      elsif ($switch eq 'S') { $includeSelf = 1; }
923      elsif ($switch eq 'T') { $onlyTerminals = 1; }
924      elsif (grep { $switch eq $_ } qw(? -help help h)) { die_usage(undef); }
925      else { die "unknown switch '-$switch'"; }
926    }
927    else {
928      if ($_ ne '') { push @targets, $_; }
929    }
930  }
931
932  my $targets = scalar(@targets);
933  my $specified_lib = undef;
934
935  if ($targets>0) {
936    if ($targets>1) {
937      if (not defined $dependencyGraph) {
938        die_usage("You may only specify ONE target! (only with -G multiple targets are possible)");
939      }
940    }
941    @targets = map { $_ = libdepend_file_2_libname($_); } @targets;
942    @targets = map { $_ = ARBHOME_relative($_); } @targets;
943    $specified_lib = $targets[0];
944    if ($trackDepends==1 and $trackInherits==0) {
945      foreach (@targets) {
946        detect_type_and_declare_initial_target($_);
947      }
948    }
949    else {
950      declare_all_targets();
951    }
952  }
953  else {
954    declare_all_targets();
955  }
956
957  resolve_dependencies();
958  warn_bad_dependencies();
959  if_errors_abortNow();
960
961  my %track = ();
962  if ($trackDepends==1) {
963    if ($dependsNesting==-1) { # infinite
964      foreach (@targets) {
965        my $dep_r = $all_dependencies_of{$_};
966        foreach (keys %$dep_r) { $track{$_} = 1; }
967      }
968    }
969    else {
970      my @track_depends_of = @targets;
971      my $nesting = 0;
972      NESTED_DEPENDS : while (@track_depends_of) {
973        ++$nesting;
974        if ($nesting>$dependsNesting) {
975          last NESTED_DEPENDS;
976        }
977        my %nextTracks = ();
978        foreach (@track_depends_of) {
979          my $dep_r = $dependencies_of{$_};
980          foreach (keys %$dep_r) {
981            my $tracked = $track{$_};
982            if (not defined $tracked or $tracked!=1) {
983              $track{$_} = 1;
984              $nextTracks{$_} = 1;
985            }
986          }
987        }
988        @track_depends_of = keys %nextTracks;
989      }
990    }
991  }
992  my $bundleExe = 1;
993  if ($trackInherits==1) {
994    if ($targets>0) {
995      if ($inheritsNesting==-1) { # infinite
996        foreach my $inheritant (keys %inheritants_of) {
997          my $dep_r = $all_dependencies_of{$inheritant};
998          foreach (@targets) {
999            if (defined $$dep_r{$_}) { $track{$inheritant} = 1; }
1000          }
1001        }
1002      }
1003      else {
1004        $bundleExe = 0;
1005        my @track_inherits_of = @targets;
1006        my $nesting = 0;
1007        NESTED_INHERITS : while (@track_inherits_of) {
1008          ++$nesting;
1009          if ($nesting>$inheritsNesting) {
1010            last NESTED_INHERITS;
1011          }
1012          my %nextTracks = ();
1013          foreach (@track_inherits_of) {
1014            my $inh_r = $inheritants_of{$_};
1015            foreach (keys %$inh_r) {
1016              my $tracked = $track{$_};
1017              if (not defined $tracked or $tracked!=1) {
1018                $track{$_} = 1;
1019                $nextTracks{$_} = 1;
1020              }
1021            }
1022          }
1023          @track_inherits_of = keys %nextTracks;
1024        }
1025      }
1026    }
1027  }
1028
1029  if ($targets>0) {
1030    if ($includeSelf==1) {
1031      foreach (@targets) {
1032        $track{$_} = 1;
1033      }
1034    }
1035  }
1036  else {
1037    foreach (keys %inheritants_of) { $track{$_} = 1; }
1038  }
1039
1040  if ($onlyTerminals==1) {
1041    if ($trackInherits==1) {
1042      # untrack all which have inheritants
1043      foreach (keys %track) {
1044        my $hash_r = $inheritants_of{$_};
1045        if ((defined $hash_r) and (scalar(keys %$hash_r)>0)) {
1046          delete $track{$_};
1047        }
1048      }
1049    }
1050    if ($trackDepends==1) {
1051      # untrack all which have dependencies
1052      foreach (keys %track) {
1053        my $hash_r = $dependencies_of{$_};
1054        if ((defined $hash_r) and (scalar(keys %$hash_r)>0)) {
1055          delete $track{$_};
1056        }
1057      }
1058    }
1059  }
1060
1061  my @track = sort keys %track;
1062
1063  if ($dump==1) { dump_dependencies(); }
1064  if (defined $dependencyGraph) { generateDependencyGraph(@track,@targets,$dependencyGraph,$bundleExe); }
1065
1066  my @out = ();
1067  if ($printDirs==1) { pushDirsTo($pathPrefix,@track,@out); }
1068  if ($printFiles==1) { pushFilesTo($pathPrefix,@track,@out); }
1069
1070  {
1071    my @libs = ();
1072    if ($printStatic==1) { pushStaticLibsTo($pathPrefix,@track,@libs); }
1073    if ($printDynamic==1) { pushDynamicLibsTo(@track,@libs); }
1074
1075    # detect whether to wrap specified library (in whole-archive linker flags):
1076    my $parameter_to_wrap = undef;
1077    if (defined $specified_lib and $linkWholeTarget==1) {
1078      if (is_dynamic_lib($specified_lib)) {
1079        $parameter_to_wrap = '-l'.dynamic_name($specified_lib); # as done in .@pushStaticLibsTo
1080      }
1081      elsif (is_static_lib($specified_lib)) {
1082        $parameter_to_wrap = prefix($pathPrefix,$specified_lib); # as done in .@pushDynamicLibsTo
1083      }
1084      else {
1085        die "'$specified_lib' is neither detected as dynamic nor as static";
1086      }
1087    }
1088
1089    my $seen = 0;
1090    foreach (@libs) {
1091      if (defined $parameter_to_wrap and $_ eq $parameter_to_wrap) {
1092        # force the linker to link the whole-archive for the main library (aka the tested unit):
1093        push @out, '-Wl,--whole-archive';
1094        push @out, $_;
1095        push @out, '-Wl,--no-whole-archive';
1096        $seen = 1;
1097      }
1098      else {
1099        push @out, $_;
1100      }
1101    }
1102
1103    if ($seen==0 and defined $parameter_to_wrap) {
1104      die "expected to see '$specified_lib' (required to link in whole-archive mode)";
1105    }
1106  }
1107
1108  if (scalar(@out)>0) { print join(' ',@out)."\n"; }
1109}
1110
1111main();
Note: See TracBrowser for help on using the repository browser.