source: branches/stable/SOURCE_TOOLS/needed_libs.pl

Last change on this file was 17993, checked in by westram, 5 years ago
  • improve error message when wrong library specified (e.g. if path is missing).
  • Property svn:executable set to *
File size: 27.4 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 = 17; # inch
616
617  open(DOT,'>'.$dotfile) || die "can't write to '$dotfile' (Reason: $!)";
618  print DOT "digraph ARBLIBDEP {\n";
619  print DOT "  rankdir=LR;\n";
620  print DOT "  concentrate=true;\n";
621  print DOT "  searchsize=1000;\n";
622  print DOT "  Damping=2.0;\n";
623  print DOT "  size=\"$maxsize,$maxsize\";\n";
624  print DOT "  orientation=portrait;\n";
625  print DOT "\n";
626
627  my %wanted_depend = map { $_ => 1; } @$depends_r;
628
629  my $seen_binary = 0;
630
631  my %execount = ();
632
633  foreach my $exe (keys %inheritants_of) {
634    if ($target_type{$exe}==$EXECUTABLE) {
635      my $deps_r = $all_dependencies_of{$exe};
636      foreach (keys %$deps_r) {
637        my $count = $execount{$_};
638        $count = (defined $count) ? $count+1 : 1;
639        $execount{$_} = $count;
640      }
641    }
642  }
643
644  my %is_target = map { $_ => 1; } @$targets_r;
645
646  foreach my $target (@$depends_r) {
647    my $deps_r = $dependencies_of{$target};
648    my $type = $target_type{$target};
649
650    if (not defined $type) {
651      use Carp;
652      Carp::confess("no target_type has been defined for '$target' (misspelled or directory missing?) ");
653    }
654
655    my $dtarget = dot_label($target);
656
657    my $color = 'black';
658    my $shape = 'box';
659    my $style = '';
660
661    if ($type==$EXECUTABLE)   { $color = 'green'; $shape = 'ellipse'; }
662    if ($type==$DYNAMIC_LIB)  { $color = 'blue'; }
663    if ($type==$STATIC_LIB)   { ; }
664    if ($type==$EXTRA_PARAMS) { $color = 'red'; $shape = 'box'; }
665
666    if ($is_target{$target}) {
667      $color = '"#ffbb66"';
668      $style = 'style=filled';
669    }
670
671    my $peri = $execount{$target};
672    $peri = defined $peri ? $peri : 1;
673
674    print DOT '    '.$dtarget.' [';
675    print DOT ' color='.$color;
676    print DOT ' shape='.$shape;
677    print DOT ' peripheries='.$peri;
678    print DOT ' '.$style;
679    print DOT '];'."\n";
680
681    if ($type==$EXECUTABLE) {
682      if ($seen_binary==0) {
683        print DOT '    executables [';
684        print DOT ' color=yellow';
685        print DOT '];'."\n";
686        $seen_binary = 1;
687      }
688      print DOT '    executables -> '.$dtarget.';'."\n";
689    }
690
691    foreach my $depend (keys %$deps_r) {
692      if (defined $wanted_depend{$depend}) {
693        my $ddepend = dot_label($depend);
694        print DOT '    '.$dtarget.' -> '.$ddepend.';'."\n";
695      }
696    }
697  }
698  print DOT "}\n";
699  close(DOT);
700  print STDERR "Wrote $dotfile\n";
701
702  my $cmd = 'dot -Tgif -o'.$gif.' '.$dotfile;
703  print STDERR $cmd."\n";
704  system($cmd)==0 || die "Failed to execute '$cmd'";
705
706  unlink($dotfile) || die "Failed to unlink '$dotfile' (Reason: $!)";
707}
708
709# --------------------------------------------------------------------------------
710
711sub pushDirsTo($\@\@) {
712  my ($pathPrefix,$depends_r,$out_r) = @_;
713  my @out = ();
714  foreach my $dep (@$depends_r) {
715    if (is_static_lib($dep)) {
716      my $dir  = dirOf($dep);
717      defined $dir || die "no dir for '$dep'";
718      my $name = filenameOf($dir);
719      push @out, prefix($pathPrefix,$dir.'/'.$name);
720    }
721    elsif (is_dynamic_lib($dep)) {
722      if ($dep =~ /^lib\/lib([A-Z_]+)\.so/) {
723        my $base = $1;
724        push @out, prefix($pathPrefix,$base.'/'.$base);
725      }
726      else {
727        die "malformed (unexpected) dependency name for shared lib ('$dep')";
728      }
729    }
730  }
731
732  foreach (sort @out) { push @$out_r, $_; }
733}
734
735sub pushFilesTo($\@\@) {
736  my ($pathPrefix,$depends_r,$out_r) = @_;
737  foreach my $dep (@$depends_r) {
738    if (is_file($dep)) {
739      push @$out_r, fixFileSuffix(prefix($pathPrefix,$dep));
740    }
741  }
742}
743
744sub sortLibsByDependency(\@) {
745  # sort libs for linker CL (fullfilling libs behind requesting libs)
746  my ($libs_r) = @_;
747  my @order = ();
748  my %added = map { $_ => 0; } @$libs_r;
749
750  while (scalar(@order) < scalar(@$libs_r)) {
751    my $didAdd = 0;
752    foreach my $lib (@$libs_r) {
753      if ($added{$lib}==0) { # not added yet
754        my $all_dep_r = $all_dependencies_of{$lib};
755        my $missing = 0;
756      CHECK: foreach my $dep (keys %$all_dep_r) {
757          my $was_added = $added{$dep};
758          if (defined $was_added) {
759            if ($was_added==0) { $missing = 1; last CHECK; }
760          }
761        }
762        if ($missing==0) {
763          push @order, $lib;
764          $added{$lib} = 1;
765          $didAdd = 1;
766        }
767      }
768    }
769    if ($didAdd==0) {
770      die "internal error: did not add any lib in last loop (undetected nested dependency?)";
771    }
772  }
773  @$libs_r = reverse @order;
774}
775
776sub pushStaticLibsTo($\@\@) {
777  my ($pathPrefix,$depends_r,$out_r) = @_;
778  my @libs = ();
779  foreach my $dep (@$depends_r) { if (is_static_lib($dep)) { push @libs, $dep; } }
780  sortLibsByDependency(@libs);
781  foreach (@libs) { push @$out_r, prefix($pathPrefix,$_); }
782}
783
784sub pushDynamicLibsTo(\@\@) {
785  my ($depends_r,$out_r) = @_;
786  my @dep = ();
787  foreach my $dep (@$depends_r) { if (is_dynamic_lib($dep)) { push @dep, $dep; } }
788  sortLibsByDependency(@dep);
789  foreach (@dep) { push @$out_r, '-l'.dynamic_name($_); }
790  foreach my $dep (@$depends_r) { if (is_extra_param($dep)) { push @$out_r, $dep; } }
791}
792
793# --------------------------------------------------------------------------------
794
795sub die_usage($) {
796  my ($err) = @_;
797  print "Usage: needed_libs.pl [options] [lib|obj|executable]\n";
798  print "Scans directories of 'lib|obj's for files named '$libdepend_file' or '$libdepend_file.libname'\n";
799  print "In case of an executable, it scans for a file named 'BINDEP/$libdepend_file.executable'.\n";
800  print "\n";
801  print "These files have to contain the name(s) of the libraries needed by 'lib', either\n";
802  print "as ARBHOME-relative path to the lib file or\n";
803  print "as link instruction (containing '-l') for non-ARB-libraries\n";
804  print "\n";
805  print "Libraries in directory '\$ARBHOME/lib' are handled special:\n";
806  print "- they need to be specified as lib/libNAME.so\n";
807  print "- their source directory is assumed to be \$ARBHOME/NAME\n";
808  print "- they are called 'dynamic' in the context of this script (even if \$LINK_STATIC=1, where they aren't dynamic)\n";
809  print "\n";
810  print "They may as well contain \${ENVVAR}\n";
811  print "If no '$libdepend_file' exists, the 'lib' is assumed to be independent.\n";
812  print "\n";
813  print "If the filename is 'DIR/$libdepend_file', the library is assumed to be 'DIR/DIR.a'\n";
814  print "\n";
815  print "options:\n";
816  print "  -D          output dirs lib depends on (e.g. ARBDB/ARBDB SL/ARB_TREE/ARB_TREE ..)\n";
817  print "  -F          output all libfiles the given lib depends on (e.g. ARBDB/libARBDB.so SL/ARB_TREE/ARB_TREE.a ..)\n";
818  print "              (suffix used for \"dynamic\" libs depends on setting of \$LINK_STATIC)\n";
819  print "  -l          output link params (e.g. -lARBDB SL/ARB_TREE/ARB_TREE.a ..)\n";
820  print "  -s          output names of \"static\" libs (e.g. SL/ARB_TREE/ARB_TREE.a ..)\n";
821  print "  -d          output names of \"dynamic\" libs (e.g. -lARBDB ..)\n";
822  print "  -A dir      prefix paths with 'dir' (not for \"dynamic\" libs)\n";
823  print "  -U          do not die on undefined environment variables\n";
824  print "  -G outgif   Draw dependency graph (using dot)\n";
825  print "  -V          Dump dependencies\n";
826  print "  -n          do not print nested dependencies\n";
827  print "  -I          Invert (print inheritants instead of dependencies)\n";
828  print "  -B          Both (print inheritants and dependencies)\n";
829  print "  -S          Include self (lib/exe given on command line)\n";
830  print "  -T          only show terminals (=those w/o dependencies and/or inheritants)\n";
831  die "Error: $err\n";
832}
833
834
835sub main() {
836  my @targets = ();
837
838  my $printDirs       = 0;
839  my $printFiles      = 0;
840  my $printStatic     = 0;
841  my $printDynamic    = 0;
842  my $pathPrefix      = undef;
843  my $dependencyGraph = undef;
844  my $dump            = 0;
845  my $trackDepends    = 1;
846  my $nestDepends     = 1;
847  my $trackInherits   = 0;
848  my $includeSelf     = 0;
849  my $onlyTerminals   = 0;
850
851  while (scalar(@ARGV)) {
852    $_ = shift @ARGV;
853    if ($_ =~ /^-/o) {
854      my $switch = $';
855      if    ($switch eq 'D') { $printDirs = 1; }
856      elsif ($switch eq 'F') { $printFiles = 1; }
857      elsif ($switch eq 'd') { $printDynamic = 1; }
858      elsif ($switch eq 's') { $printStatic = 1; }
859      elsif ($switch eq 'l') { $printStatic = 1; $printDynamic = 1; }
860      elsif ($switch eq 'A') { $pathPrefix = shift @ARGV; }
861      elsif ($switch eq 'U') { $dieOnUndefEnvvar = 0; }
862      elsif ($switch eq 'G') { $dependencyGraph = shift @ARGV; }
863      elsif ($switch eq 'V') { $dump = 1; }
864      elsif ($switch eq 'n') { $nestDepends = 0; }
865      elsif ($switch eq 'I') { $trackInherits = 1; $trackDepends = 0; }
866      elsif ($switch eq 'B') { $trackInherits = 1; }
867      elsif ($switch eq 'S') { $includeSelf = 1; }
868      elsif ($switch eq 'T') { $onlyTerminals = 1; }
869      elsif ($switch eq '?' or $switch eq 'help' or $switch eq 'h') { die_usage('help requested'); }
870      else { die "unknown switch '-$switch'"; }
871    }
872    else {
873      if ($_ ne '') { push @targets, $_; }
874    }
875  }
876
877  my $targets = scalar(@targets);
878
879  if ($targets>0) {
880    if ($targets>1) {
881      if (not defined $dependencyGraph) {
882        die_usage("You may only specify ONE target! (only with -G multiple targets are possible)");
883      }
884    }
885    @targets = map { $_ = libdepend_file_2_libname($_); } @targets;
886    @targets = map { $_ = ARBHOME_relative($_); } @targets;
887    if ($trackDepends==1 and $trackInherits==0) {
888      foreach (@targets) {
889        detect_type_and_declare_initial_target($_);
890      }
891    }
892    else {
893      declare_all_targets();
894    }
895  }
896  else {
897    declare_all_targets();
898  }
899
900  resolve_dependencies();
901  warn_bad_dependencies();
902  if_errors_abortNow();
903
904  my %track = ();
905  if ($trackDepends==1) {
906    if ($nestDepends==1) {
907      foreach (@targets) {
908        my $dep_r = $all_dependencies_of{$_};
909        foreach (keys %$dep_r) { $track{$_} = 1; }
910      }
911    }
912    else {
913      foreach (@targets) {
914        my $dep_r = $dependencies_of{$_};
915        foreach (keys %$dep_r) { $track{$_} = 1; }
916      }
917    }
918  }
919  if ($trackInherits==1) {
920    if ($targets>0) {
921      foreach my $inheritant (keys %inheritants_of) {
922        my $dep_r = $all_dependencies_of{$inheritant};
923        foreach (@targets) {
924          if (defined $$dep_r{$_}) { $track{$inheritant} = 1; }
925        }
926      }
927    }
928  }
929
930  if ($targets>0) {
931    if ($includeSelf==1) {
932      foreach (@targets) {
933        $track{$_} = 1;
934      }
935    }
936  }
937  else {
938    foreach (keys %inheritants_of) { $track{$_} = 1; }
939  }
940
941  if ($onlyTerminals==1) {
942    if ($trackInherits==1) {
943      # untrack all which have inheritants
944      foreach (keys %track) {
945        my $hash_r = $inheritants_of{$_};
946        if ((defined $hash_r) and (scalar(keys %$hash_r)>0)) {
947          delete $track{$_};
948        }
949      }
950    }
951    if ($trackDepends==1) {
952      # untrack all which have dependencies
953      foreach (keys %track) {
954        my $hash_r = $dependencies_of{$_};
955        if ((defined $hash_r) and (scalar(keys %$hash_r)>0)) {
956          delete $track{$_};
957        }
958      }
959    }
960  }
961
962  my @track = sort keys %track;
963
964  if ($dump==1) { dump_dependencies(); }
965  if (defined $dependencyGraph) { generateDependencyGraph(@track,@targets,$dependencyGraph); }
966
967  my @out = ();
968  if ($printDirs==1) { pushDirsTo($pathPrefix,@track,@out); }
969  if ($printFiles==1) { pushFilesTo($pathPrefix,@track,@out); }
970
971  {
972    my @libs = ();
973    if ($printStatic==1) { pushStaticLibsTo($pathPrefix,@track,@libs); }
974    if ($printDynamic==1) { pushDynamicLibsTo(@track,@libs); }
975
976    foreach (@libs) { push @out, $_; }
977  }
978
979  if (scalar(@out)>0) { print join(' ',@out)."\n"; }
980}
981
982main();
Note: See TracBrowser for help on using the repository browser.