source: trunk/SOURCE_TOOLS/needed_libs.pl

Last change on this file was 18862, checked in by westram, 3 years ago
  • increase x-size of dependency graphs.
  • Property svn:executable set to *
File size: 27.5 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}
192
193# --------------------------------------------------------------------------------
194
195# values for %target_type:
196my $DYNAMIC_LIB  = 0;
197my $STATIC_LIB   = 1;
198my $EXECUTABLE   = 2;
199my $EXTRA_PARAMS = 3;
200
201my %inheritants_of      = (); # key=target; value=ref to hash (key=inheritant; value=location)
202my %target_type         = (); # key=target; value: see above
203my %dependencies_of     = (); # key=target; value=ref to hash (containing direct dependencies)
204my %all_dependencies_of = (); # key=target; value=ref to hash (containing all dependencies)
205
206sub get_inheritance_location($$) {
207  my ($inheritor,$dependency) = @_;
208  my $inh_r = $inheritants_of{$dependency};
209  return $$inh_r{$inheritor};
210}
211
212sub warn_bad_dependency($) {
213  my ($target) = @_;
214
215  my $directly_depends_on_r = $dependencies_of{$target};
216  foreach my $sub (keys %$directly_depends_on_r) {
217    my $sub_depends_r = $all_dependencies_of{$sub};
218
219    # check multi dependencies:
220    foreach my $some_dep (keys %$sub_depends_r) {
221      if (defined $$directly_depends_on_r{$some_dep}) { # multi dependency
222        my $some_dep_location = get_inheritance_location($target,$some_dep);
223        location_warning($some_dep_location, "Duplicated dependency on '$some_dep'");
224
225        my $sub_location = get_inheritance_location($target,$sub);
226        location_warning($sub_location, "(already depends on '$some_dep' via '$sub'");
227      }
228    }
229
230    # check cyclic dependencies:
231    if (defined $$sub_depends_r{$target}) {
232      my $sub_location = get_inheritance_location($target,$sub);
233      location_warning($sub_location, "Cyclic dependency between $target ..");
234      my $target_location = get_inheritance_location($sub,$target);
235      location_warning($sub_location, ".. and $sub");
236    }
237  }
238}
239
240sub warn_bad_dependencies() {
241  foreach (keys %inheritants_of) {
242    warn_bad_dependency($_);
243  }
244}
245
246# --------------------------------------------------------------------------------
247
248sub dump_dependencies() {
249  foreach my $dependency (sort keys %inheritants_of) {
250    print STDERR "------------------------------------ inheriting $dependency\n";
251    my $inherit_locations_r = $inheritants_of{$dependency};
252    foreach my $inheritant (keys %$inherit_locations_r) {
253      my $location = $$inherit_locations_r{$inheritant};
254      location_warning($location, "'$dependency' inherited by '$inheritant'");
255    }
256  }
257}
258
259# --------------------------------------------------------------------------------
260
261sub prefix($$) {
262  my ($maybePrefix,$path) = @_;
263  if (defined $maybePrefix) { $maybePrefix.'/'.$path; }
264  else { $path; }
265}
266
267sub dynamic_name($) {
268  my ($target) = @_;
269  my $name = filenameOf($target);
270  if ($name =~ /^lib(.*)\.so$/o) { $1; }
271  else { undef; }
272}
273
274sub assert_defined($) {
275  my ($val) = @_;
276  use Carp;
277  defined $val || Carp::confess("undef");
278  return $val;
279}
280
281sub is_dynamic_lib($) { my ($target) = @_; return $target_type{$target} == $DYNAMIC_LIB; }
282sub is_static_lib($)  { my ($target) = @_; return assert_defined($target_type{$target}) == $STATIC_LIB; }
283sub is_extra_param($) { my ($target) = @_; return $target_type{$target} == $EXTRA_PARAMS; }
284sub is_executable($)  { my ($target) = @_; return $target_type{$target} == $EXECUTABLE; }
285
286sub is_library($)  { my ($target) = @_; return is_static_lib($target) || is_dynamic_lib($target); }
287sub is_file($)     { my ($target) = @_; return is_library($target) || is_executable($target); }
288
289# --------------------------------------------------------------------------------
290
291sub declare_initial_target($$) {
292  my ($target,$type) = @_;
293
294  if ($target ne '') {
295    legal_target_or_die($target);
296
297    my $inherit_locations_r = $inheritants_of{$target};
298    if (not defined $inherit_locations_r) {
299      my %new_hash = ();
300      $inheritants_of{$target} = \%new_hash;
301      $target_type{$target} = $type;
302    }
303    else {
304      $target_type{$target}==$type || die "type mismatch for initial '$target' (".$target_type{$target}." vs $type)\n";
305    }
306  }
307}
308
309sub detect_target_type($) {
310  my ($target) = @_;
311
312  if ($target =~ /\.(so|a|o)$/o) {
313    if ($1 eq 'so') { $DYNAMIC_LIB; }
314    else { $STATIC_LIB; }
315  }
316  else { $EXECUTABLE; }
317}
318
319sub detect_type_and_declare_initial_target($) {
320  my ($target) = @_;
321
322  my $type = detect_target_type($target);
323  declare_initial_target($target,$type);
324}
325
326# --------------------------------------------------------------------------------
327
328sub scan_dependsfile_entry($$$) {
329  my ($line, $inheritant, $location) = @_;
330
331  my $analyse = 1;
332  my $type = undef;
333
334  if ($line =~ /^\$\((.*)\)$/o) {
335    my $envvar = $1;
336    my $env = $ENV{$envvar};
337    if (not defined $env) {
338      if ($dieOnUndefEnvvar==1) { die "Undefined environment variable '$envvar'\n"; }
339      $type = $EXTRA_PARAMS;
340      $analyse = 0;
341    }
342    else {
343      $line = $env;
344      $line =~ s/\s\s/ /g;
345      $line =~ s/^\s//g;
346      $line =~ s/\s$//g;
347    }
348  }
349
350  if ($analyse==1) {
351    if ($line =~ /-[lL]/o) {
352      $type = $EXTRA_PARAMS;
353    }
354    else {
355      $line = ARBHOME_relative($line);
356      $type = detect_target_type($line);
357    }
358    $analyse = 0;
359  }
360
361  defined $type || die "could not detect line type\n";
362
363  my $target = $line;
364  declare_initial_target($target,$type);
365
366  my $inherit_locations_r = $inheritants_of{$target};
367  $$inherit_locations_r{$inheritant} = $location;
368}
369
370
371my %scanned = (); # key=dependsfile, value=1 -> already scanned
372
373sub scan_target($) {
374  my ($target) = @_;
375
376  my $depfile = target2dependencyFile($target);
377
378  if (not defined $scanned{$depfile}) {
379    $scanned{$depfile} = 1;
380
381    my $fulldep = fullpath($depfile);
382
383    if (not -f $fulldep) {
384      my $dir = dirOf($fulldep);
385      my $err = "Missing dependency file for '$target'";
386      if (not -d $dir) { $err .= " (No such directory '$dir')"; }
387      my $location = $fulldep.':0';
388      location_error($location,$err);
389    }
390    else {
391      open(IN,'<'.$fulldep) || die "can't read '$fulldep' (Reason: $!)";
392      my $lineno = 0;
393      foreach (<IN>) {
394        $lineno++;
395        chomp;
396        if ($_ =~ /\#/) { $_ = $`; } # remove comments
397        $_ = trim($_); # remove whitespace
398
399        if ($_ ne '') {  # skip empty lines
400          my $location = $fulldep.':'.$lineno;
401          eval {
402            scan_dependsfile_entry($_, $target, $location);
403          };
404          if ($@) {
405            location_error($location, $@);
406          }
407        }
408      }
409      close(IN);
410    }
411  }
412}
413
414sub rec_add_depends_to_hash($\%);
415sub rec_add_depends_to_hash($\%) {
416  my ($target,$hash_r) = @_;
417
418  my $all_dep_r = $all_dependencies_of{$target};
419  if (defined $all_dep_r) {
420    foreach (keys %$all_dep_r) {
421      $$hash_r{$_} = 1;
422    }
423  }
424  else {
425    my $dep_r = $dependencies_of{$target};
426    foreach (keys %$dep_r) {
427      if (not defined $$hash_r{$_}) {
428        $$hash_r{$_} = 1;
429        rec_add_depends_to_hash($_,%$hash_r);
430      }
431    }
432  }
433}
434
435sub resolve_dependencies() {
436  my $done = 0;
437  my $target;
438  while ($done==0) {
439    my %unscanned = ();
440    foreach my $target (keys %inheritants_of) {
441      if ($target_type{$target} != $EXTRA_PARAMS) { # recurse dependency
442        my $depfile = target2dependencyFile($target);
443        if (not defined $scanned{$depfile}) {
444          if ($target eq '') {
445            my $inh_r = $inheritants_of{$target};
446            foreach (keys %$inh_r) {
447              my $loc = $$inh_r{$_};
448              location_error($loc, "Empty target inherited from here");
449            }
450          }
451          else {
452            $unscanned{$target} = 1;
453          }
454        }
455      }
456    }
457
458    my @unscanned = sort keys %unscanned;
459    if (scalar(@unscanned)) {
460      foreach $target (@unscanned) { scan_target($target); }
461    }
462    else {
463      $done = 1;
464    }
465  }
466
467  # build %dependencies_of
468
469  foreach $target (keys %inheritants_of) {
470    my %new_hash = ();
471    $dependencies_of{$target} = \%new_hash;
472  }
473  foreach $target (keys %inheritants_of) {
474    my $inherit_locations_r = $inheritants_of{$target};
475    foreach my $inheritant (keys %$inherit_locations_r) {
476      if ($target eq $inheritant) {
477        my $self_include_loc = get_inheritance_location($inheritant, $target);
478        location_error($self_include_loc, "Illegal self-dependency");
479      }
480      my $dep_r = $dependencies_of{$inheritant};
481      $$dep_r{$target} = 1;
482    }
483  }
484
485  if_errors_abortNow();
486
487  # build %all_dependencies_of
488
489  my @targets = keys %dependencies_of;
490  my %depends_size = map {
491    my $dep_r = $dependencies_of{$_};
492    $_ => scalar(keys %$dep_r);
493  } @targets;
494
495  @targets = sort { $depends_size{$a} <=> $depends_size{$b}; } @targets; # smallest first
496
497  foreach $target (@targets) {
498    my %new_hash = ();
499    rec_add_depends_to_hash($target,%new_hash);
500    $all_dependencies_of{$target} = \%new_hash;
501  }
502}
503
504# --------------------------------------------------------------------------------
505
506my $reg_is_libdepend_file = qr/^($libdepend_file|$libdepend_file\..*)$/;
507
508sub find_dep_decl_files($\@);
509sub find_dep_decl_files($\@) {
510  my ($dir,$found_r) = @_;
511  $dir =~ s/\/\//\//og;
512  my @subdirs = ();
513  opendir(DIR,$dir) || die "can't read directory '$dir' (Reason: $!)";
514  foreach (readdir(DIR)) {
515    if ($_ ne '.' and $_ ne '..') {
516      my $full = $dir.'/'.$_;
517      if (not -l $full) {
518        if (-d $full) {
519          if (not $_ =~ /\.(svn|git)$/o) { push @subdirs, $full; }
520        }
521        elsif ($_ =~ $reg_is_libdepend_file) { push @$found_r, ARBHOME_relative($full); }
522      }
523    }
524  }
525  closedir(DIR);
526  foreach (@subdirs) { find_dep_decl_files($_,@$found_r); }
527}
528
529my %dep2lib = (
530               'ARBDB/needs_libs.libARBDB_so'   => 'lib/libARBDB.so',
531               'AWT/needs_libs.libAWT_so'       => 'lib/libAWT.so',
532               'CORE/needs_libs.libCORE_so'     => 'lib/libCORE.so',
533               'WINDOW/needs_libs.libWINDOW_so' => 'lib/libWINDOW.so',
534
535               'GL/glAW/needs_libs.libglAW_a'       => 'GL/glAW/libglAW.a',
536               'GL/glpng/needs_libs.libglpng_arb_a' => 'GL/glpng/libglpng_arb.a',
537
538               'PROBE_COM/needs_libs.client_a' => 'PROBE_COM/client.a',
539               'PROBE_COM/needs_libs.server_a' => 'PROBE_COM/server.a',
540               'NAMES_COM/needs_libs.client_a' => 'NAMES_COM/client.a',
541               'NAMES_COM/needs_libs.server_a' => 'NAMES_COM/server.a',
542
543               'ptpan/needs_libs.PROBE_a' => 'ptpan/PROBE.a',
544              );
545
546sub libdepend_file_2_libname($) {
547  my ($dep) = @_;
548  if (defined $dep2lib{$dep}) {
549    $dep = $dep2lib{$dep};
550  }
551  elsif ($dep =~ /^(.*)\/([^\/]*)/) {
552    my ($dir,$name) = ($1,$2);
553    if ($name =~ $reg_is_libdepend_file) {
554      if ($dep =~ /BINDEP\/needs_libs\./) {
555        $dep = $';
556      }
557      else {
558        my ($prefix,$targetdir) = ('',undef);
559
560        if ($dir =~ /^(.*)\/([^\/]*)/) {
561          my ($path,$lastdir) = ($1,$2);
562          $path =~ s/^.\///;
563          $prefix = $path.'/';
564          $targetdir = $lastdir;
565        }
566        else {
567          $targetdir = $dir;
568        }
569
570        my $target = undef;
571        if ($name =~ /^needs_libs\.(.*)_o$/) {
572          $target = $targetdir.'/'.$1.'.o';
573        }
574        else {
575          $target = $targetdir.'/'.$targetdir.'.a';
576        }
577
578        $dep = $prefix.$target;
579      }
580    }
581  }
582  return $dep;
583}
584
585sub declare_all_targets() {
586  my @depfiles = ();
587  find_dep_decl_files($ARBHOME,@depfiles);
588  foreach my $depfile (sort @depfiles) {
589    my $target = dependencyFile2target($depfile);
590    detect_type_and_declare_initial_target($target);
591  }
592}
593
594# --------------------------------------------------------------------------------
595
596sub dot_label($) {
597  my ($target) = @_;
598  if (is_file($target)) { $target = filenameOf($target); }
599  return '"'.$target.'"';
600}
601
602sub generateDependencyGraph(\@\@$) {
603  my ($depends_r,$targets_r,$gif) = @_;
604
605  my $base;
606  if ($gif =~ /\.gif$/) {
607    $base = $`;
608  }
609  else {
610    $base = $gif;
611    $gif = $base.'.gif';
612  }
613
614  my $dotfile = $base.'.dot';
615  my $maxsize_X = 20; # inch
616  my $maxsize_Y = 17; # inch
617
618  open(DOT,'>'.$dotfile) || die "can't write to '$dotfile' (Reason: $!)";
619  print DOT "digraph ARBLIBDEP {\n";
620  print DOT "  rankdir=LR;\n";
621  print DOT "  concentrate=true;\n";
622  print DOT "  searchsize=1000;\n";
623  print DOT "  Damping=2.0;\n";
624  print DOT "  size=\"$maxsize_X,$maxsize_Y\";\n";
625  print DOT "  orientation=portrait;\n";
626  print DOT "\n";
627
628  my %wanted_depend = map { $_ => 1; } @$depends_r;
629
630  my $seen_binary = 0;
631
632  my %execount = ();
633
634  foreach my $exe (keys %inheritants_of) {
635    if ($target_type{$exe}==$EXECUTABLE) {
636      my $deps_r = $all_dependencies_of{$exe};
637      foreach (keys %$deps_r) {
638        my $count = $execount{$_};
639        $count = (defined $count) ? $count+1 : 1;
640        $execount{$_} = $count;
641      }
642    }
643  }
644
645  my %is_target = map { $_ => 1; } @$targets_r;
646
647  foreach my $target (@$depends_r) {
648    my $deps_r = $dependencies_of{$target};
649    my $type = $target_type{$target};
650
651    if (not defined $type) {
652      use Carp;
653      Carp::confess("no target_type has been defined for '$target' (misspelled or directory missing?) ");
654    }
655
656    my $dtarget = dot_label($target);
657
658    my $color = 'black';
659    my $shape = 'box';
660    my $style = '';
661
662    if ($type==$EXECUTABLE)   { $color = 'green'; $shape = 'ellipse'; }
663    if ($type==$DYNAMIC_LIB)  { $color = 'blue'; }
664    if ($type==$STATIC_LIB)   { ; }
665    if ($type==$EXTRA_PARAMS) { $color = 'red'; $shape = 'box'; }
666
667    if ($is_target{$target}) {
668      $color = '"#ffbb66"';
669      $style = 'style=filled';
670    }
671
672    my $peri = $execount{$target};
673    $peri = defined $peri ? $peri : 1;
674
675    print DOT '    '.$dtarget.' [';
676    print DOT ' color='.$color;
677    print DOT ' shape='.$shape;
678    print DOT ' peripheries='.$peri;
679    print DOT ' '.$style;
680    print DOT '];'."\n";
681
682    if ($type==$EXECUTABLE) {
683      if ($seen_binary==0) {
684        print DOT '    executables [';
685        print DOT ' color=yellow';
686        print DOT '];'."\n";
687        $seen_binary = 1;
688      }
689      print DOT '    executables -> '.$dtarget.';'."\n";
690    }
691
692    foreach my $depend (keys %$deps_r) {
693      if (defined $wanted_depend{$depend}) {
694        my $ddepend = dot_label($depend);
695        print DOT '    '.$dtarget.' -> '.$ddepend.';'."\n";
696      }
697    }
698  }
699  print DOT "}\n";
700  close(DOT);
701  print STDERR "Wrote $dotfile\n";
702
703  my $cmd = 'dot -Tgif -o'.$gif.' '.$dotfile;
704  print STDERR $cmd."\n";
705  system($cmd)==0 || die "Failed to execute '$cmd'";
706
707  unlink($dotfile) || die "Failed to unlink '$dotfile' (Reason: $!)";
708}
709
710# --------------------------------------------------------------------------------
711
712sub pushDirsTo($\@\@) {
713  my ($pathPrefix,$depends_r,$out_r) = @_;
714  my @out = ();
715  foreach my $dep (@$depends_r) {
716    if (is_static_lib($dep)) {
717      my $dir  = dirOf($dep);
718      defined $dir || die "no dir for '$dep'";
719      my $name = filenameOf($dir);
720      push @out, prefix($pathPrefix,$dir.'/'.$name);
721    }
722    elsif (is_dynamic_lib($dep)) {
723      if ($dep =~ /^lib\/lib([A-Z_]+)\.so/) {
724        my $base = $1;
725        push @out, prefix($pathPrefix,$base.'/'.$base);
726      }
727      else {
728        die "malformed (unexpected) dependency name for shared lib ('$dep')";
729      }
730    }
731  }
732
733  foreach (sort @out) { push @$out_r, $_; }
734}
735
736sub pushFilesTo($\@\@) {
737  my ($pathPrefix,$depends_r,$out_r) = @_;
738  foreach my $dep (@$depends_r) {
739    if (is_file($dep)) {
740      push @$out_r, fixFileSuffix(prefix($pathPrefix,$dep));
741    }
742  }
743}
744
745sub sortLibsByDependency(\@) {
746  # sort libs for linker CL (fullfilling libs behind requesting libs)
747  my ($libs_r) = @_;
748  my @order = ();
749  my %added = map { $_ => 0; } @$libs_r;
750
751  while (scalar(@order) < scalar(@$libs_r)) {
752    my $didAdd = 0;
753    foreach my $lib (@$libs_r) {
754      if ($added{$lib}==0) { # not added yet
755        my $all_dep_r = $all_dependencies_of{$lib};
756        my $missing = 0;
757      CHECK: foreach my $dep (keys %$all_dep_r) {
758          my $was_added = $added{$dep};
759          if (defined $was_added) {
760            if ($was_added==0) { $missing = 1; last CHECK; }
761          }
762        }
763        if ($missing==0) {
764          push @order, $lib;
765          $added{$lib} = 1;
766          $didAdd = 1;
767        }
768      }
769    }
770    if ($didAdd==0) {
771      die "internal error: did not add any lib in last loop (undetected nested dependency?)";
772    }
773  }
774  @$libs_r = reverse @order;
775}
776
777sub pushStaticLibsTo($\@\@) {
778  my ($pathPrefix,$depends_r,$out_r) = @_;
779  my @libs = ();
780  foreach my $dep (@$depends_r) { if (is_static_lib($dep)) { push @libs, $dep; } }
781  sortLibsByDependency(@libs);
782  foreach (@libs) { push @$out_r, prefix($pathPrefix,$_); }
783}
784
785sub pushDynamicLibsTo(\@\@) {
786  my ($depends_r,$out_r) = @_;
787  my @dep = ();
788  foreach my $dep (@$depends_r) { if (is_dynamic_lib($dep)) { push @dep, $dep; } }
789  sortLibsByDependency(@dep);
790  foreach (@dep) { push @$out_r, '-l'.dynamic_name($_); }
791  foreach my $dep (@$depends_r) { if (is_extra_param($dep)) { push @$out_r, $dep; } }
792}
793
794# --------------------------------------------------------------------------------
795
796sub die_usage($) {
797  my ($err) = @_;
798  print "Usage: needed_libs.pl [options] [lib|obj|executable]\n";
799  print "Scans directories of 'lib|obj's for files named '$libdepend_file' or '$libdepend_file.libname'\n";
800  print "In case of an executable, it scans for a file named 'BINDEP/$libdepend_file.executable'.\n";
801  print "\n";
802  print "These files have to contain the name(s) of the libraries needed by 'lib', either\n";
803  print "as ARBHOME-relative path to the lib file or\n";
804  print "as link instruction (containing '-l') for non-ARB-libraries\n";
805  print "\n";
806  print "Libraries in directory '\$ARBHOME/lib' are handled special:\n";
807  print "- they need to be specified as lib/libNAME.so\n";
808  print "- their source directory is assumed to be \$ARBHOME/NAME\n";
809  print "- they are called 'dynamic' in the context of this script (even if \$LINK_STATIC=1, where they aren't dynamic)\n";
810  print "\n";
811  print "They may as well contain \${ENVVAR}\n";
812  print "If no '$libdepend_file' exists, the 'lib' is assumed to be independent.\n";
813  print "\n";
814  print "If the filename is 'DIR/$libdepend_file', the library is assumed to be 'DIR/DIR.a'\n";
815  print "\n";
816  print "options:\n";
817  print "  -D          output dirs lib depends on (e.g. ARBDB/ARBDB SL/ARB_TREE/ARB_TREE ..)\n";
818  print "  -F          output all libfiles the given lib depends on (e.g. ARBDB/libARBDB.so SL/ARB_TREE/ARB_TREE.a ..)\n";
819  print "              (suffix used for \"dynamic\" libs depends on setting of \$LINK_STATIC)\n";
820  print "  -l          output link params (e.g. -lARBDB SL/ARB_TREE/ARB_TREE.a ..)\n";
821  print "  -s          output names of \"static\" libs (e.g. SL/ARB_TREE/ARB_TREE.a ..)\n";
822  print "  -d          output names of \"dynamic\" libs (e.g. -lARBDB ..)\n";
823  print "  -A dir      prefix paths with 'dir' (not for \"dynamic\" libs)\n";
824  print "  -U          do not die on undefined environment variables\n";
825  print "  -G outgif   Draw dependency graph (using dot)\n";
826  print "  -V          Dump dependencies\n";
827  print "  -n          do not print nested dependencies\n";
828  print "  -I          Invert (print inheritants instead of dependencies)\n";
829  print "  -B          Both (print inheritants and dependencies)\n";
830  print "  -S          Include self (lib/exe given on command line)\n";
831  print "  -T          only show terminals (=those w/o dependencies and/or inheritants)\n";
832  die "Error: $err\n";
833}
834
835
836sub main() {
837  my @targets = ();
838
839  my $printDirs       = 0;
840  my $printFiles      = 0;
841  my $printStatic     = 0;
842  my $printDynamic    = 0;
843  my $pathPrefix      = undef;
844  my $dependencyGraph = undef;
845  my $dump            = 0;
846  my $trackDepends    = 1;
847  my $nestDepends     = 1;
848  my $trackInherits   = 0;
849  my $includeSelf     = 0;
850  my $onlyTerminals   = 0;
851
852  while (scalar(@ARGV)) {
853    $_ = shift @ARGV;
854    if ($_ =~ /^-/o) {
855      my $switch = $';
856      if    ($switch eq 'D') { $printDirs = 1; }
857      elsif ($switch eq 'F') { $printFiles = 1; }
858      elsif ($switch eq 'd') { $printDynamic = 1; }
859      elsif ($switch eq 's') { $printStatic = 1; }
860      elsif ($switch eq 'l') { $printStatic = 1; $printDynamic = 1; }
861      elsif ($switch eq 'A') { $pathPrefix = shift @ARGV; }
862      elsif ($switch eq 'U') { $dieOnUndefEnvvar = 0; }
863      elsif ($switch eq 'G') { $dependencyGraph = shift @ARGV; }
864      elsif ($switch eq 'V') { $dump = 1; }
865      elsif ($switch eq 'n') { $nestDepends = 0; }
866      elsif ($switch eq 'I') { $trackInherits = 1; $trackDepends = 0; }
867      elsif ($switch eq 'B') { $trackInherits = 1; }
868      elsif ($switch eq 'S') { $includeSelf = 1; }
869      elsif ($switch eq 'T') { $onlyTerminals = 1; }
870      elsif ($switch eq '?' or $switch eq 'help' or $switch eq 'h') { die_usage('help requested'); }
871      else { die "unknown switch '-$switch'"; }
872    }
873    else {
874      if ($_ ne '') { push @targets, $_; }
875    }
876  }
877
878  my $targets = scalar(@targets);
879
880  if ($targets>0) {
881    if ($targets>1) {
882      if (not defined $dependencyGraph) {
883        die_usage("You may only specify ONE target! (only with -G multiple targets are possible)");
884      }
885    }
886    @targets = map { $_ = libdepend_file_2_libname($_); } @targets;
887    @targets = map { $_ = ARBHOME_relative($_); } @targets;
888    if ($trackDepends==1 and $trackInherits==0) {
889      foreach (@targets) {
890        detect_type_and_declare_initial_target($_);
891      }
892    }
893    else {
894      declare_all_targets();
895    }
896  }
897  else {
898    declare_all_targets();
899  }
900
901  resolve_dependencies();
902  warn_bad_dependencies();
903  if_errors_abortNow();
904
905  my %track = ();
906  if ($trackDepends==1) {
907    if ($nestDepends==1) {
908      foreach (@targets) {
909        my $dep_r = $all_dependencies_of{$_};
910        foreach (keys %$dep_r) { $track{$_} = 1; }
911      }
912    }
913    else {
914      foreach (@targets) {
915        my $dep_r = $dependencies_of{$_};
916        foreach (keys %$dep_r) { $track{$_} = 1; }
917      }
918    }
919  }
920  if ($trackInherits==1) {
921    if ($targets>0) {
922      foreach my $inheritant (keys %inheritants_of) {
923        my $dep_r = $all_dependencies_of{$inheritant};
924        foreach (@targets) {
925          if (defined $$dep_r{$_}) { $track{$inheritant} = 1; }
926        }
927      }
928    }
929  }
930
931  if ($targets>0) {
932    if ($includeSelf==1) {
933      foreach (@targets) {
934        $track{$_} = 1;
935      }
936    }
937  }
938  else {
939    foreach (keys %inheritants_of) { $track{$_} = 1; }
940  }
941
942  if ($onlyTerminals==1) {
943    if ($trackInherits==1) {
944      # untrack all which have inheritants
945      foreach (keys %track) {
946        my $hash_r = $inheritants_of{$_};
947        if ((defined $hash_r) and (scalar(keys %$hash_r)>0)) {
948          delete $track{$_};
949        }
950      }
951    }
952    if ($trackDepends==1) {
953      # untrack all which have dependencies
954      foreach (keys %track) {
955        my $hash_r = $dependencies_of{$_};
956        if ((defined $hash_r) and (scalar(keys %$hash_r)>0)) {
957          delete $track{$_};
958        }
959      }
960    }
961  }
962
963  my @track = sort keys %track;
964
965  if ($dump==1) { dump_dependencies(); }
966  if (defined $dependencyGraph) { generateDependencyGraph(@track,@targets,$dependencyGraph); }
967
968  my @out = ();
969  if ($printDirs==1) { pushDirsTo($pathPrefix,@track,@out); }
970  if ($printFiles==1) { pushFilesTo($pathPrefix,@track,@out); }
971
972  {
973    my @libs = ();
974    if ($printStatic==1) { pushStaticLibsTo($pathPrefix,@track,@libs); }
975    if ($printDynamic==1) { pushDynamicLibsTo(@track,@libs); }
976
977    foreach (@libs) { push @out, $_; }
978  }
979
980  if (scalar(@out)>0) { print join(' ',@out)."\n"; }
981}
982
983main();
Note: See TracBrowser for help on using the repository browser.