source: branches/profile/SOURCE_TOOLS/needed_libs.pl

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