source: tags/old_import_filter/SOURCE_TOOLS/needed_libs.pl

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