Explorar o código

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 %!s(int64=18) %!d(string=hai) anos
pai
achega
15fbb138b6
Modificáronse 4 ficheiros con 92 adicións e 18 borrados
  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>
 2008-03-25  Ian Jackson  <ian@davenant.greenend.org.uk>
 
 
 	* lib/dpkg-db.h (modstatdb_note_ifwrite): New prototype.
 	* 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.
     discarded one. Added a test case for this.
   * dpkg-shlibdeps properly accounts usage of symbols provided by private
   * dpkg-shlibdeps properly accounts usage of symbols provided by private
     libraries without SONAME. Closes: #469838
     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 ]
   [ Frank Lichtenheld ]
   * Add a warning in dpkg-buildpackage if the build-dependencies are not
   * 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
 .SH NAME
 dpkg\-shlibdeps \- generate shared library substvar dependencies
 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)
 dependency information (either with shlibs files, or with symbols files)
 even if they are not yet used by other packages.  
 even if they are not yet used by other packages.  
 .TP
 .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
 .BI \-\-admindir= dir
 Change the location of the \fBdpkg\fR database. The default location is
 Change the location of the \fBdpkg\fR database. The default location is
 \fI/var/lib/dpkg\fP.
 \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
 with an additional library during the build process (option \fB-l\fR\fIlibrary\fR
 of the linker).
 of the linker).
 .TP
 .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)."
 .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
 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
 .SH ERRORS
 .B dpkg\-shlibdeps
 .B dpkg\-shlibdeps
 will fail if it can't find a public library used by a binary or if this
 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
 .br
 Copyright (C) 2006 Frank Lichtenheld
 Copyright (C) 2006 Frank Lichtenheld
 .br
 .br
-Copyright (C) 2007 Rapha\[:e]l Hertzog
+Copyright (C) 2007-2008 Rapha\[:e]l Hertzog
 .sp
 .sp
 This is free software; see the GNU General Public Licence version 2 or later
 This is free software; see the GNU General Public Licence version 2 or later
 for copying conditions. There is NO WARRANTY.
 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::Deps;
 use Dpkg::Control;
 use Dpkg::Control;
 
 
+use constant {
+    WARN_SYM_NOT_FOUND => 1,
+    WARN_DEP_AVOIDABLE => 2,
+    WARN_NOT_NEEDED => 4,
+};
+
 # By increasing importance
 # By increasing importance
 my @depfields = qw(Suggests Recommends Depends Pre-Depends);
 my @depfields = qw(Suggests Recommends Depends Pre-Depends);
 my $i = 0; my %depstrength = map { $_ => $i++ } @depfields;
 my $i = 0; my %depstrength = map { $_ => $i++ } @depfields;
@@ -34,6 +40,7 @@ my $dependencyfield = 'Depends';
 my $varlistfile = 'debian/substvars';
 my $varlistfile = 'debian/substvars';
 my $varnameprefix = 'shlibs';
 my $varnameprefix = 'shlibs';
 my $ignore_missing_info = 0;
 my $ignore_missing_info = 0;
+my $warnings = 3;
 my $debug = 0;
 my $debug = 0;
 my @exclude = ();
 my @exclude = ();
 my @pkg_dir_to_search = ();
 my @pkg_dir_to_search = ();
@@ -82,6 +89,8 @@ foreach (@ARGV) {
 	}
 	}
     } elsif (m/^--ignore-missing-info$/) {
     } elsif (m/^--ignore-missing-info$/) {
 	$ignore_missing_info = 1;
 	$ignore_missing_info = 1;
+    } elsif (m/^--warnings=(\d+)$/) {
+	$warnings = $1;
     } elsif (m/^-t(.*)$/) {
     } elsif (m/^-t(.*)$/) {
 	$packagetype = $1;
 	$packagetype = $1;
     } elsif (m/^-v$/) {
     } elsif (m/^-v$/) {
@@ -113,6 +122,12 @@ my $build_deps = Dpkg::Deps::parse($build_depends, reduce_arch => 1);
 my %dependencies;
 my %dependencies;
 my %shlibs;
 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;
 my $cur_field;
 foreach my $file (keys %exec) {
 foreach my $file (keys %exec) {
     $cur_field = $exec{$file};
     $cur_field = $exec{$file};
@@ -130,6 +145,7 @@ foreach my $file (keys %exec) {
 	my $lib = my_find_library($soname, $obj->{RPATH}, $obj->{format}, $file);
 	my $lib = my_find_library($soname, $obj->{RPATH}, $obj->{format}, $file);
 	unless (defined $lib) {
 	unless (defined $lib) {
 	    $soname_notfound{$soname} = 1;
 	    $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" .
 	    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 " .
 			 "Note: libraries are not searched in other binary packages " .
 			 "that do not have any shlibs or symbols file.\nTo help dpkg-shlibdeps " .
 			 "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
     # Scan all undefined symbols of the binary and resolve to a
     # dependency
     # 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_warnings = 0;
     my $nb_skipped_warnings = 0;
     my $nb_skipped_warnings = 0;
     # Disable warnings about missing symbols when we have not been able to
     # 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);
 	my $symdep = $symfile->lookup_symbol($name, \@sonames);
 	if (defined($symdep)) {
 	if (defined($symdep)) {
             print " Found in symbols file of $symdep->{soname}\n" if $debug > 1;
             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}}) {
             if (exists $alt_soname{$symdep->{soname}}) {
                 # Also count usage on alternate 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},
 	    update_dependency_version($symdep->{depends},
 				      $symdep->{minver});
 				      $symdep->{minver});
@@ -256,6 +284,7 @@ foreach my $file (keys %exec) {
 	    my $syminfo = $dumplibs_wo_symfile->locate_symbol($name);
 	    my $syminfo = $dumplibs_wo_symfile->locate_symbol($name);
 	    if (not defined($syminfo)) {
 	    if (not defined($syminfo)) {
                 print " Not found\n" if $debug > 1;
                 print " Not found\n" if $debug > 1;
+                next unless ($warnings & WARN_SYM_NOT_FOUND);
 		next if $disable_warnings;
 		next if $disable_warnings;
 		# Complain about missing symbols only for executables
 		# Complain about missing symbols only for executables
 		# and public libraries
 		# and public libraries
@@ -277,9 +306,11 @@ foreach my $file (keys %exec) {
                 print " Found in $syminfo->{soname} ($syminfo->{objid})\n" if $debug > 1;
                 print " Found in $syminfo->{soname} ($syminfo->{objid})\n" if $debug > 1;
 		if (exists $alt_soname{$syminfo->{soname}}) {
 		if (exists $alt_soname{$syminfo->{soname}}) {
 		    # Also count usage on alternate 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
 	# 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++
 	    # Ignore warning for libm.so.6 if also linked against libstdc++
 	    next if ($soname =~ /^libm\.so\.\d+$/ and
 	    next if ($soname =~ /^libm\.so\.\d+$/ and
 		     scalar grep(/^libstdc\+\+\.so\.\d+/, @sonames));
 		     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 " .
 	    warning(_g("%s shouldn't be linked with %s (it uses none of its " .
 	               "symbols)."), $file, $soname);
 	               "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
 # Open substvars file
 my $fh;
 my $fh;
 if ($stdout) {
 if ($stdout) {
@@ -435,6 +481,9 @@ Options:
   -x<package>              exclude package from the generated dependencies.
   -x<package>              exclude package from the generated dependencies.
   -S<pkgbuilddir>          search needed libraries in the given
   -S<pkgbuilddir>          search needed libraries in the given
                            package build directory first.
                            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.
   --admindir=<directory>   change the administrative directory.
   -h, --help               show this help message.
   -h, --help               show this help message.
       --version            show the version.
       --version            show the version.