Преглед изворни кода

dpkg-shlibdeps: new warning about useless libraries, new --warnings option

* scripts/dpkg-shlibdeps.pl: Let the user configure the set of
warnings that he wants. Add a new warning for useless libraries
on all binaries analyzed. Disable by default the warning that
does the same but individually, for each binary analyzed.
* man/dpkg-shlibdeps.1: Update manual page accordingly.
Raphael Hertzog пре 18 година
родитељ
комит
15fbb138b6
4 измењених фајлова са 92 додато и 18 уклоњено
  1. 8 0
      ChangeLog
  2. 6 0
      debian/changelog
  3. 23 12
      man/dpkg-shlibdeps.1
  4. 55 6
      scripts/dpkg-shlibdeps.pl

+ 8 - 0
ChangeLog

@@ -1,3 +1,11 @@
+2008-03-25  Raphael Hertzog  <hertzog@debian.org>
+
+	* scripts/dpkg-shlibdeps.pl: Let the user configure the set of
+	warnings that he wants. Add a new warning for useless libraries
+	on all binaries analyzed. Disable by default the warning that
+	does the same but individually, for each binary analyzed.
+	* man/dpkg-shlibdeps.1: Update manual page accordingly.
+
 2008-03-25  Ian Jackson  <ian@davenant.greenend.org.uk>
 
 	* lib/dpkg-db.h (modstatdb_note_ifwrite): New prototype.

+ 6 - 0
debian/changelog

@@ -80,6 +80,12 @@ dpkg (1.14.17) UNRELEASED; urgency=low
     discarded one. Added a test case for this.
   * dpkg-shlibdeps properly accounts usage of symbols provided by private
     libraries without SONAME. Closes: #469838
+  * Add a new warning to dpkg-shlibdeps when a library NEEDED is in fact
+    not used by any of the binaries analyzed. Closes: #472332
+  * Add a new --warnings=<value> option to select the set of warnings to
+    activate. By default, do not activate the warning about useless
+    libraries at the binary level (instead the new warning above is activated
+    by default: it's less strict and more useful).
 
   [ Frank Lichtenheld ]
   * Add a warning in dpkg-buildpackage if the build-dependencies are not

+ 23 - 12
man/dpkg-shlibdeps.1

@@ -1,4 +1,4 @@
-.TH dpkg\-shlibdeps 1 "2007-07-16" "Debian Project" "dpkg utilities"
+.TH dpkg\-shlibdeps 1 "2008-03-25" "Debian Project" "dpkg utilities"
 .SH NAME
 dpkg\-shlibdeps \- generate shared library substvar dependencies
 .
@@ -199,6 +199,17 @@ Usage of this option is discouraged, all libraries should provide
 dependency information (either with shlibs files, or with symbols files)
 even if they are not yet used by other packages.  
 .TP
+.BI \-\-warnings= value
+\fIvalue\fP is a bit field defining the set of warnings that
+can be emitted by \fBdpkg-\-shlibdeps\fP.
+Bit 0 (value=1) enables the warning "symbol \fIsym\fP used by \fIbinary\fP
+found in none of the libraries", bit 1 (value=2) enables the warning
+"dependency on \fIlibrary\fP could be avoided" and bit 2 (value=4)
+enables the warning "\fIbinary\fP shouldn't be linked with \fIlibrary\fP".
+The default \fIvalue\fP is 3: the first two warnings are active by
+default, the last one is not. Set \fIvalue\fP to 7 if you want all
+warnings to be active.
+.TP
 .BI \-\-admindir= dir
 Change the location of the \fBdpkg\fR database. The default location is
 \fI/var/lib/dpkg\fP.
@@ -224,18 +235,18 @@ binary. The \fIbinary\fR is most likely a library and it needs to be linked
 with an additional library during the build process (option \fB-l\fR\fIlibrary\fR
 of the linker).
 .TP
+.BI "dependency on " library " could be avoided if " binaries " were not uselessly linked against it (they use none of its symbols)."
+None of the \fIbinaries\fP that are linked with \fPlibrary\fP use any of the
+symbols provided by the library. By fixing all the binaries, you would avoid
+the dependency associated to this library (unless the same dependency is
+also generated by another library that is really used).
+.TP
 .IB binary " shouldn't be linked with " library " (it uses none of its symbols)."
 The \fIbinary\fR is linked to a library that it doesn't need. It's not a
-problem but some small performance improvements in binary load time
-can be obtained by not linking this library to this binary. 
-
-Furthermore, in some cases, this will lead to a non-versioned dependency
-on the library that could have been avoided if the binary was only linked
-against libraries that it really uses. The exception to this rule is
-when several binaries are linked against the same set of libraries but
-each binary only uses a subset of those. You will have warnings on
-individual binaries, but the set of libraries needed at the package level
-is the same whether you fix the binaries or not.
+problem but some small performance improvements in binary load time can be
+obtained by not linking this library to this binary. This warning checks
+the same information than the previous one but does it for each binary
+instead of doing the check globally on all binaries analyzed.
 .SH ERRORS
 .B dpkg\-shlibdeps
 will fail if it can't find a public library used by a binary or if this
@@ -310,7 +321,7 @@ Copyright (C) 2000 Wichert Akkerman
 .br
 Copyright (C) 2006 Frank Lichtenheld
 .br
-Copyright (C) 2007 Rapha\[:e]l Hertzog
+Copyright (C) 2007-2008 Rapha\[:e]l Hertzog
 .sp
 This is free software; see the GNU General Public Licence version 2 or later
 for copying conditions. There is NO WARRANTY.

+ 55 - 6
scripts/dpkg-shlibdeps.pl

@@ -20,6 +20,12 @@ use Dpkg::Fields qw(capit);
 use Dpkg::Deps;
 use Dpkg::Control;
 
+use constant {
+    WARN_SYM_NOT_FOUND => 1,
+    WARN_DEP_AVOIDABLE => 2,
+    WARN_NOT_NEEDED => 4,
+};
+
 # By increasing importance
 my @depfields = qw(Suggests Recommends Depends Pre-Depends);
 my $i = 0; my %depstrength = map { $_ => $i++ } @depfields;
@@ -34,6 +40,7 @@ my $dependencyfield = 'Depends';
 my $varlistfile = 'debian/substvars';
 my $varnameprefix = 'shlibs';
 my $ignore_missing_info = 0;
+my $warnings = 3;
 my $debug = 0;
 my @exclude = ();
 my @pkg_dir_to_search = ();
@@ -82,6 +89,8 @@ foreach (@ARGV) {
 	}
     } elsif (m/^--ignore-missing-info$/) {
 	$ignore_missing_info = 1;
+    } elsif (m/^--warnings=(\d+)$/) {
+	$warnings = $1;
     } elsif (m/^-t(.*)$/) {
 	$packagetype = $1;
     } elsif (m/^-v$/) {
@@ -113,6 +122,12 @@ my $build_deps = Dpkg::Deps::parse($build_depends, reduce_arch => 1);
 my %dependencies;
 my %shlibs;
 
+# Statictics on soname seen in the whole run (with multiple analysis of
+# binaries)
+my %global_soname_notfound;
+my %global_soname_used;
+my %global_soname_needed;
+
 my $cur_field;
 foreach my $file (keys %exec) {
     $cur_field = $exec{$file};
@@ -130,6 +145,7 @@ foreach my $file (keys %exec) {
 	my $lib = my_find_library($soname, $obj->{RPATH}, $obj->{format}, $file);
 	unless (defined $lib) {
 	    $soname_notfound{$soname} = 1;
+	    $global_soname_notfound{$soname} = 1;
 	    my $msg = _g("couldn't find library %s needed by %s (its RPATH is '%s').\n" .
 			 "Note: libraries are not searched in other binary packages " .
 			 "that do not have any shlibs or symbols file.\nTo help dpkg-shlibdeps " .
@@ -228,7 +244,17 @@ foreach my $file (keys %exec) {
 
     # Scan all undefined symbols of the binary and resolve to a
     # dependency
-    my %used_sonames = map { $_ => 0 } @sonames;
+    my %soname_used;
+    foreach (@sonames) {
+        # Initialize statistics
+        $soname_used{$_} = 0;
+        $global_soname_used{$_} = 0 unless exists $global_soname_used{$_};
+        if (exists $global_soname_needed{$_}) {
+            push @{$global_soname_needed{$_}}, $file;
+        } else {
+            $global_soname_needed{$_} = [ $file ];
+        }
+    }
     my $nb_warnings = 0;
     my $nb_skipped_warnings = 0;
     # Disable warnings about missing symbols when we have not been able to
@@ -245,10 +271,12 @@ foreach my $file (keys %exec) {
 	my $symdep = $symfile->lookup_symbol($name, \@sonames);
 	if (defined($symdep)) {
             print " Found in symbols file of $symdep->{soname}\n" if $debug > 1;
-	    $used_sonames{$symdep->{soname}}++;
+	    $soname_used{$symdep->{soname}}++;
+	    $global_soname_used{$symdep->{soname}}++;
             if (exists $alt_soname{$symdep->{soname}}) {
                 # Also count usage on alternate soname
-                $used_sonames{$alt_soname{$symdep->{soname}}}++;
+                $soname_used{$alt_soname{$symdep->{soname}}}++;
+                $global_soname_used{$alt_soname{$symdep->{soname}}}++;
             }
 	    update_dependency_version($symdep->{depends},
 				      $symdep->{minver});
@@ -256,6 +284,7 @@ foreach my $file (keys %exec) {
 	    my $syminfo = $dumplibs_wo_symfile->locate_symbol($name);
 	    if (not defined($syminfo)) {
                 print " Not found\n" if $debug > 1;
+                next unless ($warnings & WARN_SYM_NOT_FOUND);
 		next if $disable_warnings;
 		# Complain about missing symbols only for executables
 		# and public libraries
@@ -277,9 +306,11 @@ foreach my $file (keys %exec) {
                 print " Found in $syminfo->{soname} ($syminfo->{objid})\n" if $debug > 1;
 		if (exists $alt_soname{$syminfo->{soname}}) {
 		    # Also count usage on alternate soname
-		    $used_sonames{$alt_soname{$syminfo->{soname}}}++;
+		    $soname_used{$alt_soname{$syminfo->{soname}}}++;
+		    $global_soname_used{$alt_soname{$syminfo->{soname}}}++;
 		}
-		$used_sonames{$syminfo->{soname}}++;
+		$soname_used{$syminfo->{soname}}++;
+		$global_soname_used{$syminfo->{soname}}++;
 	    }
 	}
     }
@@ -299,16 +330,31 @@ foreach my $file (keys %exec) {
 	}
 
 	# Warn about un-NEEDED libraries
-	unless ($soname_notfound{$soname} or $used_sonames{$soname}) {
+	unless ($soname_notfound{$soname} or $soname_used{$soname}) {
 	    # Ignore warning for libm.so.6 if also linked against libstdc++
 	    next if ($soname =~ /^libm\.so\.\d+$/ and
 		     scalar grep(/^libstdc\+\+\.so\.\d+/, @sonames));
+            next unless ($warnings & WARN_NOT_NEEDED);
 	    warning(_g("%s shouldn't be linked with %s (it uses none of its " .
 	               "symbols)."), $file, $soname);
 	}
     }
 }
 
+# Warn of unneeded libraries at the "package" level (i.e. over all
+# binaries that we have inspected)
+foreach my $soname (keys %global_soname_needed) {
+    unless ($global_soname_notfound{$soname} or $global_soname_used{$soname}) {
+        next if ($soname =~ /^libm\.so\.\d+$/ and scalar(
+                 grep(/^libstdc\+\+\.so\.\d+/, keys %global_soname_needed)));
+        next unless ($warnings & WARN_DEP_AVOIDABLE);
+        warning(_g("dependency on %s could be avoided if \"%s\" were not " .
+                   "uselessly linked against it (they use none of its " .
+                   "symbols)."), $soname,
+                   join(" ", @{$global_soname_needed{$soname}}));
+    }
+}
+
 # Open substvars file
 my $fh;
 if ($stdout) {
@@ -435,6 +481,9 @@ Options:
   -x<package>              exclude package from the generated dependencies.
   -S<pkgbuilddir>          search needed libraries in the given
                            package build directory first.
+  -v                       enable verbose mode (can be used multiple times).
+  --ignore-missing-info    don't fail if dependency information can't be found.
+  --warnings=<value>       define set of active warnings (see manual page).
   --admindir=<directory>   change the administrative directory.
   -h, --help               show this help message.
       --version            show the version.