[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[SCM] Debian package checker branch, master, updated. 2.2.13-7-ga5f818a



The following commit has been merged in the master branch:
commit a5f818a0c3b6ade7b4619fe65f1c093b91fa26e8
Author: Russ Allbery <rra@debian.org>
Date:   Tue Jul 21 15:28:46 2009 -0700

    Move build dependency debian/rules checks and fix pattern rules
    
    * checks/fields{,.desc}
      + [RA] Move debian/rules parsing to check build dependencies to
        checks/rules.
    * checks/rules{,.desc}:
      + [RA] Moved checking of build dependencies based on programs invoked
        in debian/rules from checks/fields to here.
      + [RA] Expand Lintian's understanding of which targets are run for the
        clean target to include targets invoked via pattern variable
        expansion.  (Closes: #536405)

diff --git a/checks/fields b/checks/fields
index 6235b7b..161a8ad 100644
--- a/checks/fields
+++ b/checks/fields
@@ -105,98 +105,6 @@ our %known_x_metapackages = map { $_ => 1 }
     ( 'x-window-system', 'x-window-system-dev', 'x-window-system-core',
       'xorg', 'xorg-dev', );
 
-# The allowed Python dependencies currently.  This is the list of alternatives
-# that, either directly or through transitive dependencies that can be relied
-# upon, ensure /usr/bin/python will exist for the use of dh_python.
-our $PYTHON_DEPEND = 'python | python-dev | python-all | python-all-dev | '
-    . join (' | ', map { "python$_ | python$_-dev" } qw(2.4 2.5));
-
-# Certain build tools must be listed in Build-Depends even if there are no
-# arch-specific packages because they're required in order to run the clean
-# rule.  (See Policy 7.6.)  The following is a list of package dependencies;
-# regular expressions that, if they match anywhere in the debian/rules file,
-# say that this package is allowed (and required) in Build-Depends; and
-# optional tags to use for reporting the problem if some information other
-# than the default is required.
-our @GLOBAL_CLEAN_DEPENDS = (
-	[ ant => qr'^include\s*/usr/share/cdbs/1/rules/ant\.mk' ],
-	[ cdbs => qr'^include\s+/usr/share/cdbs/' ],
-	[ cdbs => qr'^include\s+/usr/share/R/debian/r-cran\.mk' ],
-	[ dbs => qr'^include\s+/usr/share/dbs/' ],
-	[ 'dh-make-php' => qr'^include\s+/usr/share/cdbs/1/class/pear\.mk' ],
-	[ debhelper => qr'^include\s+/usr/share/cdbs/1/rules/debhelper\.mk' ],
-	[ debhelper => qr'^include\s+/usr/share/R/debian/r-cran\.mk' ],
-	[ dpatch => qr'^include\s+/usr/share/cdbs/1/rules/dpatch\.mk' ],
-	[ 'gnome-pkg-tools' => qr'^include\s+/usr/share/gnome-pkg-tools/' ],
-	[ quilt => qr'^include\s+/usr/share/cdbs/1/rules/patchsys-quilt\.mk' ],
-	[ dpatch => qr'^include\s+/usr/share/dpatch/' ],
-	[ quilt => qr'^include\s+/usr/share/quilt/' ],
-	[ 'ruby-pkg-tools' => qr'^include\s+/usr/share/ruby-pkg-tools/1/class/' ],
-	[ 'r-base-dev' => qr'^include\s+/usr/share/R/debian/r-cran\.mk' ],
-	[ $PYTHON_DEPEND => qr'/usr/share/cdbs/1/class/python-distutils\.mk', 'missing-python-build-dependency' ],
-);
-
-# These are similar, but the resulting dependency is only allowed, not
-# required.
-#
-# The xsfclean rule is specific to the packages maintained by the X Strike
-# Force, but there are enough of those to make the rule worthwhile.
-my @GLOBAL_CLEAN_ALLOWED = (
-	[ patchutils => qr'^include\s+/usr/share/cdbs/1/rules/dpatch\.mk' ],
-	[ patchutils => qr'^include\s+/usr/share/cdbs/1/rules/patchsys-quilt\.mk' ],
-	[ patchutils => qr'^include\s+/usr/share/cdbs/1/rules/simple-patchsys\.mk' ],
-	[ 'python-central' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pycentral' ],
-	[ 'python-support' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pysupport' ],
-	[ 'python-setuptools' => qr'/usr/share/cdbs/1/class/python-distutils\.mk' ],
-	[ quilt => qr'^clean:\s+xsfclean\b' ],
-);
-
-# A list of packages; regular expressions that, if they match anywhere in the
-# debian/rules file, this package must be listed in either Build-Depends or
-# Build-Depends-Indep as appropriate; and optional tags as above.
-my @GLOBAL_DEPENDS = (
-	[ $PYTHON_DEPEND => qr'^\t\s*dh_python\s', 'missing-dh_python-build-dependency' ],
-	[ 'python-central' => qr'^\t\s*dh_pycentral\s' ],
-	[ 'python-support' => qr'^\t\s*dh_pysupport\s' ],
-	[ 'python-central' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pycentral' ],
-	[ 'python-support' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pysupport' ],
-);
-
-# Similarly, this list of packages, regexes, and optional tags say that if the
-# regex matches in one of clean, build-arch, binary-arch, or a rule they
-# depend on, this package is allowed (and required) in Build-Depends.
-my @RULE_CLEAN_DEPENDS = (
-	[ ant => qr'^\t\s*(\S+=\S+\s+)*ant\s' ],
-	[ debhelper => qr'^\t\s*dh_.+' ],
-	[ dpatch => qr'^\t\s*(\S+=\S+\s+)*dpatch\s' ],
-	[ "po-debconf" => qr'^\t\s*debconf-updatepo\s' ],
-	[ $PYTHON_DEPEND => qr'^\t\s*python\s', 'missing-python-build-dependency' ],
-	[ $PYTHON_DEPEND => qr'\ssetup\.py\b', 'missing-python-build-dependency' ],
-	[ 'quilt (>= 0.46-7~)' => qr'\t\s*dh_quilt_.+' ],
-	[ quilt => qr'^\t\s*(\S+=\S+\s+)*quilt\s' ],
-	[ yada => qr'^\t\s*yada\s' ],
-);
-
-# Similar, but the resulting dependency is only allowed, not required.  We
-# permit a versioned dependency on perl-base because that used to be the
-# standard suggested dependency.  No package should be depending on just
-# perl-base, since it's Priority: required.
-my @RULE_CLEAN_ALLOWED = (
-	[ patch => q'^\t\s*(?:perl debian/)?yada\s+unpatch' ],
-	[ 'perl | perl-base (>= 5.6.0-16)' => qr'(^\t|\|\|)\s*(perl|\$\(PERL\))\s' ],
-	[ 'perl-modules (>= 5.10) | libmodule-build-perl' => qr'(^\t|\|\|)\s*(perl|\$\(PERL\))\s+Build\b' ],
-	[ 'python-setuptools' => qr'\ssetup\.py\b' ],
-);
-
-# A simple list of regular expressions which, if they match anywhere in
-# debian/rules, indicate the requirements for debian/rules clean are complex
-# enough that we can't know what packages are permitted in Build-Depends and
-# should bypass the build-depends-without-arch-dep check completely.
-my @GLOBAL_CLEAN_BYPASS = (
-	qr'^include\s*/usr/share/cdbs/1/class/ant\.mk',
-	qr'^\s+(\S+=\S+\s+)*dh\s+'
-);
-
 # Mapping of package names to section names
 my @NAME_SECTION_MAPPINGS = (
     [ qr/-docs?$/                => 'doc'      ],
@@ -722,71 +630,6 @@ if ($type eq "source") {
 		}
 	}
 
-	# Search through rules and determine which dependencies are required.
-	# The keys in %needed and %needed_clean are the dependencies; the
-	# values are the tags to use or the empty string to use the default
-	# tag.
-	my (%needed, %needed_clean, %allowed_clean, $bypass_needed_clean);
-	open (RULES, '<', "debfiles/rules")
-	    or fail("cannot read debfiles/rules: $!");
-	my $target = "none";
-	my @rules = qw(clean binary-arch build-arch);
-        my $maybe_skipping;
-	while (<RULES>) {
-		if (/^ifn?(eq|def)\s/) {
-			$maybe_skipping++;
-		} elsif (/^endif\s/) {
-			$maybe_skipping--;
-		}
-		for my $rule (@GLOBAL_CLEAN_DEPENDS) {
-			if ($_ =~ /$rule->[1]/) {
-				if ($maybe_skipping) {
-					$allowed_clean{$rule->[0]} = 1;
-				} else {
-					$needed_clean{$rule->[0]} = $rule->[2] || $needed_clean{$rule->[0]} || '';
-				}
-			}
-		}
-		for my $rule (@GLOBAL_CLEAN_ALLOWED) {
-			if ($_ =~ /$rule->[1]/) {
-				$allowed_clean{$rule->[0]} = 1;
-			}
-		}
-		for my $rule (@GLOBAL_CLEAN_BYPASS) {
-			if ($_ =~ /$rule/) {
-				$bypass_needed_clean = 1;
-			}
-		}
-		for my $rule (@GLOBAL_DEPENDS) {
-			if ($_ =~ /$rule->[1]/ && !$maybe_skipping) {
-				$needed{$rule->[0]} = $rule->[2] || $needed{$rule->[0]} || '';
-			}
-		}
-		if (/^(\S+?):+(.*)/) {
-			$target = $1;
-			if (grep ($_ eq $target, @rules)) {
-				push (@rules, split (' ', $2));
-			}
-		}
-		if (grep ($_ eq $target, @rules)) {
-			for my $rule (@RULE_CLEAN_DEPENDS) {
-				if ($_ =~ /$rule->[1]/) {
-					if ($maybe_skipping) {
-						$allowed_clean{$rule->[0]} = 1;
-					} else {
-						$needed_clean{$rule->[0]} = $rule->[2] || $needed_clean{$rule->[0]} || '';
-					}
-				}
-			}
-			for my $rule (@RULE_CLEAN_ALLOWED) {
-				if ($_ =~ /$rule->[1]/) {
-					$allowed_clean{$rule->[0]} = 1;
-				}
-			}
-		}
-	}
-	close RULES;
-
 	tag "build-depends-indep-without-arch-indep", ""
 		if (defined $info->field('build-depends-indep') && $arch_indep_packages == 0);
 
@@ -873,73 +716,6 @@ if ($type eq "source") {
 		}
 	}
 
-	# Make sure that all the required build dependencies are there.	 Don't
-	# issue missing-build-dependency errors for debhelper, since there's
-	# another test that does that and it would just be a duplicate.
-	my $build_regular = $info->relation('build-depends');
-	my $build_indep   = $info->relation('build-depends-indep');
-	for my $package (keys %needed_clean) {
-		my $tag = $needed_clean{$package} || 'missing-build-dependency';
-		unless ($build_regular->implies($package)) {
-			if ($build_indep->implies($package)) {
-				tag "clean-should-be-satisfied-by-build-depends", $package;
-			} else {
-				if ($tag eq 'missing-build-dependency') {
-					tag $tag, $package if $package ne 'debhelper';
-				} else {
-					tag $tag;
-				}
-			}
-		}
-	}
-	my $noarch = $info->relation_noarch('build-depends-all');
-	for my $package (keys %needed) {
-		my $tag = $needed{$package} || 'missing-build-dependency';
-
-		# dh_python deactivates itself if the new Python build policy
-		# is enabled.
-		if ($tag eq 'missing-dh_python-build-dependency') {
-			next if -f 'debfiles/pycomat';
-			next if defined $info->field('python-version');
-		}
-		unless ($noarch->implies($package)) {
-			if ($tag eq 'missing-build-dependency') {
-				tag $tag, $package;
-			} else {
-				tag $tag;
-			}
-		}
-	}
-
-	# This check is a bit tricky.  We want to allow in Build-Depends a
-	# dependency with any version, since reporting this tag over version
-	# mismatches would be confusing and quite likely wrong.	 The approach
-	# taken is to strip the version information off all dependencies
-	# allowed in Build-Depends, strip the version information off of the
-	# dependencies in Build-Depends, and then allow any dependency in
-	# Build-Depends that's implied by the dependencies we require or allow
-	# there.
-	#
-	# We also have to map | to , when building the list of allowed
-	# packages so that the implications will work properly.
-	#
-	# This is confusing.  There should be a better way to do this.
-	if (defined $info->field('build-depends') && $arch_dep_packages == 0 && !$bypass_needed_clean) {
-		my $build_depends = $info->field('build-depends');
-		my @packages = split /\s*,\s*/, $build_depends;
-		my @allowed = map { s/\([^\)]+\)//g; s/\|/,/g; $_ } keys (%needed_clean), keys (%allowed_clean);
-		my $dep = Lintian::Relation->new_noarch(join(',', @allowed));
-		foreach my $pkg (@packages) {
-			my $name = $pkg;
-			$name =~ s/[\[\(][^\)\]]+[\)\]]//g;
-			$name =~ s/\s+$//;
-			$name =~ s/\s+/ /g;
-			unless ($dep->implies($name)) {
-				tag "build-depends-without-arch-dep", $name;
-			}
-		}
-	}
-
 	my (@arch_dep_pkgs, @dbg_pkgs);
 	foreach my $binpkg (keys %$binpkgs) {
 		if ($binpkg =~ m/-dbg$/) {
diff --git a/checks/fields.desc b/checks/fields.desc
index 2b02602..ed33777 100644
--- a/checks/fields.desc
+++ b/checks/fields.desc
@@ -597,67 +597,6 @@ Ref: policy 7.7
 Info: The control file specifies source relations for architecture-independent
  packages, but no architecture-independent packages are built.
 
-Tag: build-depends-without-arch-dep
-Severity: minor
-Certainty: possible
-Ref: policy 7.7
-Info: The control file lists the given package in Build-Depends, but no
- architecture-dependent packages are built. If all the packages built are
- architecture-independent, the only packages that should be listed in
- Build-Depends are those required to run the clean target (such as
- debhelper if you use dh_clean). Other build dependencies should be listed
- in Build-Depends-Indep instead.
-
-Tag: clean-should-be-satisfied-by-build-depends
-Severity: important
-Certainty: certain
-Ref: policy 7.7
-Info: The specified package is required to run the clean target of
- <tt>debian/rules</tt> and therefore must be listed in Build-Depends, not
- Build-Depends-Indep, even if no architecture-dependent packages are
- built.
-
-Tag: missing-build-dependency
-Severity: important
-Certainty: certain
-Ref: policy 4.2
-Info: The package doesn't specify a build dependency on a package that is
- used in <tt>debian/rules</tt>.
- .
- lintian intentionally does not take into account transitive dependencies.
- Even if the package build-depends on some package that in turn
- depends on the needed package, an explicit build dependency should
- be added.  Otherwise, a latent bug is created that will appear without
- warning if the other package is ever updated to change its dependencies.
- Even if this seems unlikely, please always add explicit build
- dependencies on every non-essential, non-build-essential package that is
- used directly during the build.
-
-Tag: missing-python-build-dependency
-Severity: important
-Certainty: certain
-Ref: policy 4.2
-Info: The package appears to use Python as part of its build process in
- <tt>debian/rules</tt> but doesn't depend on Python.
- .
- Normally, packages that use Python as part of the build process should
- build-depend on one of python, python-all, python-dev, or python-all-dev
- depending on whether they support multiple versions of Python and whether
- they're building modules or only using Python as part of the package
- build process.  Packages that depend on a specific version of Python may
- build-depend on the appropriate pythonX.Y or pythonX.Y-dev package
- instead.
-
-Tag: missing-dh_python-build-dependency
-Severity: important
-Certainty: certain
-Ref: dh_python(1)
-Info: The package runs dh_python in <tt>debian/rules</tt> but doesn't
- build-depend on python or python-dev. dh_python requires
- <tt>/usr/bin/python</tt> to run, so packages using dh_python must
- build-depend on python (or python-dev or python-all-dev, which in turn
- depend on python), even if they don't otherwise need Python to build.
-
 Tag: build-conflicts-with-build-dependency
 Severity: important
 Certainty: certain
diff --git a/checks/rules b/checks/rules
index a598f64..f4c47c4 100644
--- a/checks/rules
+++ b/checks/rules
@@ -18,6 +18,103 @@ use strict;
 use Tags;
 use Util;
 
+# The allowed Python dependencies currently.  This is the list of alternatives
+# that, either directly or through transitive dependencies that can be relied
+# upon, ensure /usr/bin/python will exist for the use of dh_python.
+our $PYTHON_DEPEND = 'python | python-dev | python-all | python-all-dev | '
+    . join (' | ', map { "python$_ | python$_-dev" } qw(2.4 2.5));
+
+# Certain build tools must be listed in Build-Depends even if there are no
+# arch-specific packages because they're required in order to run the clean
+# rule.  (See Policy 7.6.)  The following is a list of package dependencies;
+# regular expressions that, if they match anywhere in the debian/rules file,
+# say that this package is allowed (and required) in Build-Depends; and
+# optional tags to use for reporting the problem if some information other
+# than the default is required.
+our @GLOBAL_CLEAN_DEPENDS =
+    (
+     [ ant => qr'^include\s*/usr/share/cdbs/1/rules/ant\.mk' ],
+     [ cdbs => qr'^include\s+/usr/share/cdbs/' ],
+     [ cdbs => qr'^include\s+/usr/share/R/debian/r-cran\.mk' ],
+     [ dbs => qr'^include\s+/usr/share/dbs/' ],
+     [ 'dh-make-php' => qr'^include\s+/usr/share/cdbs/1/class/pear\.mk' ],
+     [ debhelper => qr'^include\s+/usr/share/cdbs/1/rules/debhelper\.mk' ],
+     [ debhelper => qr'^include\s+/usr/share/R/debian/r-cran\.mk' ],
+     [ dpatch => qr'^include\s+/usr/share/cdbs/1/rules/dpatch\.mk' ],
+     [ 'gnome-pkg-tools' => qr'^include\s+/usr/share/gnome-pkg-tools/' ],
+     [ quilt => qr'^include\s+/usr/share/cdbs/1/rules/patchsys-quilt\.mk' ],
+     [ dpatch => qr'^include\s+/usr/share/dpatch/' ],
+     [ quilt => qr'^include\s+/usr/share/quilt/' ],
+     [ 'ruby-pkg-tools' => qr'^include\s+/usr/share/ruby-pkg-tools/1/class/' ],
+     [ 'r-base-dev' => qr'^include\s+/usr/share/R/debian/r-cran\.mk' ],
+     [ $PYTHON_DEPEND => qr'/usr/share/cdbs/1/class/python-distutils\.mk', 'missing-python-build-dependency' ],
+    );
+
+# These are similar, but the resulting dependency is only allowed, not
+# required.
+#
+# The xsfclean rule is specific to the packages maintained by the X Strike
+# Force, but there are enough of those to make the rule worthwhile.
+my @GLOBAL_CLEAN_ALLOWED = (
+	[ patchutils => qr'^include\s+/usr/share/cdbs/1/rules/dpatch\.mk' ],
+	[ patchutils => qr'^include\s+/usr/share/cdbs/1/rules/patchsys-quilt\.mk' ],
+	[ patchutils => qr'^include\s+/usr/share/cdbs/1/rules/simple-patchsys\.mk' ],
+	[ 'python-central' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pycentral' ],
+	[ 'python-support' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pysupport' ],
+	[ 'python-setuptools' => qr'/usr/share/cdbs/1/class/python-distutils\.mk' ],
+	[ quilt => qr'^clean:\s+xsfclean\b' ],
+);
+
+# A list of packages; regular expressions that, if they match anywhere in the
+# debian/rules file, this package must be listed in either Build-Depends or
+# Build-Depends-Indep as appropriate; and optional tags as above.
+my @GLOBAL_DEPENDS =
+    (
+     [ $PYTHON_DEPEND => qr'^\t\s*dh_python\s', 'missing-dh_python-build-dependency' ],
+     [ 'python-central' => qr'^\t\s*dh_pycentral\s' ],
+     [ 'python-support' => qr'^\t\s*dh_pysupport\s' ],
+     [ 'python-central' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pycentral' ],
+     [ 'python-support' => qr'^DEB_PYTHON_SYSTEM\s*:?=\s*pysupport' ],
+    );
+
+# Similarly, this list of packages, regexes, and optional tags say that if the
+# regex matches in one of clean, build-arch, binary-arch, or a rule they
+# depend on, this package is allowed (and required) in Build-Depends.
+my @RULE_CLEAN_DEPENDS =
+    (
+     [ ant => qr'^\t\s*(\S+=\S+\s+)*ant\s' ],
+     [ debhelper => qr'^\t\s*dh_.+' ],
+     [ dpatch => qr'^\t\s*(\S+=\S+\s+)*dpatch\s' ],
+     [ "po-debconf" => qr'^\t\s*debconf-updatepo\s' ],
+     [ $PYTHON_DEPEND => qr'^\t\s*python\s', 'missing-python-build-dependency' ],
+     [ $PYTHON_DEPEND => qr'\ssetup\.py\b', 'missing-python-build-dependency' ],
+     [ 'quilt (>= 0.46-7~)' => qr'\t\s*dh_quilt_.+' ],
+     [ quilt => qr'^\t\s*(\S+=\S+\s+)*quilt\s' ],
+     [ yada => qr'^\t\s*yada\s' ],
+    );
+
+# Similar, but the resulting dependency is only allowed, not required.  We
+# permit a versioned dependency on perl-base because that used to be the
+# standard suggested dependency.  No package should be depending on just
+# perl-base, since it's Priority: required.
+my @RULE_CLEAN_ALLOWED =
+    (
+     [ patch => q'^\t\s*(?:perl debian/)?yada\s+unpatch' ],
+     [ 'perl | perl-base (>= 5.6.0-16)' => qr'(^\t|\|\|)\s*(perl|\$\(PERL\))\s' ],
+     [ 'perl-modules (>= 5.10) | libmodule-build-perl' => qr'(^\t|\|\|)\s*(perl|\$\(PERL\))\s+Build\b' ],
+     [ 'python-setuptools' => qr'\ssetup\.py\b' ],
+    );
+
+# A simple list of regular expressions which, if they match anywhere in
+# debian/rules, indicate the requirements for debian/rules clean are complex
+# enough that we can't know what packages are permitted in Build-Depends and
+# should bypass the build-depends-without-arch-dep check completely.
+my @GLOBAL_CLEAN_BYPASS =
+    (
+     qr'^include\s*/usr/share/cdbs/1/class/ant\.mk',
+     qr'^\s+(\S+=\S+\s+)*dh\s+'
+    );
+
 # The following targets are required per Policy.
 my %required = map { $_ => 1 }
     qw(build binary binary-arch binary-indep clean);
@@ -62,6 +159,11 @@ my $start = <RULES>;
 tag "debian-rules-not-a-makefile", ""
     unless $start =~ m%^\#!\s*/usr/bin/make\s+-[re]?f[re]?\s*$%;
 
+# Holds which dependencies are required.  The keys in %needed and
+# %needed_clean are the dependencies; the values are the tags to use or the
+# empty string to use the default tag.
+my (%needed, %needed_clean, %allowed_clean, $bypass_needed_clean);
+
 # Scan debian/rules.  We would really like to let make do this for us, but
 # unfortunately there doesn't seem to be a way to get make to syntax-check and
 # analyze a makefile without running at least $(shell) commands.
@@ -72,9 +174,11 @@ tag "debian-rules-not-a-makefile", ""
 my $includes = 0;
 my %seen;
 local $_;
+my @arch_rules = (qr/^clean$/, qr/^binary-arch$/, qr/^build-arch$/);
 my @current_targets;
 my %rules_per_target;
 my $debhelper_group;
+my $maybe_skipping;
 while (<RULES>) {
     next if /^\s*\#/;
     $includes = 1 if m/^ *[s-]?include\s+/;
@@ -94,10 +198,45 @@ while (<RULES>) {
 	/^\t\s*(?:\$[\(\{]MAKE[\}\)]|make)\s(?:.*\s)?-\w*i.*(?:dist)?clean/) {
         tag "debian-rules-ignores-make-clean-error", "line $.";
     }
-    if (/$[\(\{]DEB_BUILD_OPTS[\)\}]/) {
+    if (/\$[\(\{]DEB_BUILD_OPTS[\)\}]/) {
         tag "debian-rules-uses-DEB_BUILD_OPTS", "line $.";
     }
 
+    # Keep track of whether this portion of debian/rules may be optional
+    if (/^ifn?(eq|def)\s/) {
+        $maybe_skipping++;
+    } elsif (/^endif\s/) {
+        $maybe_skipping--;
+    }
+
+    # Check for strings anywhere in debian/rules that have implications for
+    # our dependencies.
+    for my $rule (@GLOBAL_CLEAN_DEPENDS) {
+        if (/$rule->[1]/) {
+            if ($maybe_skipping) {
+                $allowed_clean{$rule->[0]} = 1;
+            } else {
+                $needed_clean{$rule->[0]}
+                    = $rule->[2] || $needed_clean{$rule->[0]} || '';
+            }
+        }
+    }
+    for my $rule (@GLOBAL_CLEAN_ALLOWED) {
+        if (/$rule->[1]/) {
+            $allowed_clean{$rule->[0]} = 1;
+        }
+    }
+    for my $rule (@GLOBAL_CLEAN_BYPASS) {
+        if (/$rule/) {
+            $bypass_needed_clean = 1;
+        }
+    }
+    for my $rule (@GLOBAL_DEPENDS) {
+        if (/$rule->[1]/ && !$maybe_skipping) {
+            $needed{$rule->[0]} = $rule->[2] || $needed{$rule->[0]} || '';
+        }
+    }
+
     # Listing a rule as a dependency of .PHONY is sufficient to make it
     # present for the purposes of GNU make and therefore the Policy
     # requirement.
@@ -108,17 +247,24 @@ while (<RULES>) {
         }
     }
 
-    if (/^([^\s:][^:]*):/) {
+    if (/^([^\s:][^:]*):+(.*)/) {
 	@current_targets = split (' ', $1);
-	for (@current_targets) {
-            if (m/%/) {
-                my $pattern = quotemeta $_;
+        my @depends = map {
+            s/\$\([^\):]+:([^=]+)=([^\)]+)\1\)/$2.*/g;
+            qr/^$_$/;
+        } split (' ', $2);
+	for my $target (@current_targets) {
+            if ($target =~ /%/) {
+                my $pattern = quotemeta $target;
                 $pattern =~ s/\\%/.*/g;
-                for my $target (keys %required) {
-                    $seen{$target}++ if $target =~ m/$pattern/;
+                for my $required (keys %required) {
+                    $seen{$required}++ if $required =~ m/$pattern/;
                 }
             } else {
-                $seen{$_}++ if $required{$_};
+                $seen{$target}++ if $required{$target};
+            }
+            if (grep { $target =~ /$_/ } @arch_rules) {
+                push (@arch_rules, @depends);
             }
 	}
         $debhelper_group = 0;
@@ -133,9 +279,28 @@ while (<RULES>) {
     	# targets and check whether debhelper programs are called in a
     	# reasonable order.
 	if (m/^\s+[^\#]/) {
-	    foreach my $target (@current_targets) {
-		$rules_per_target{$target} ||= [];
-		push @{$rules_per_target{$target}}, $_;
+            my $arch = 0;
+            for my $target (@current_targets) {
+                $rules_per_target{$target} ||= [];
+                push @{$rules_per_target{$target}}, $_;
+                $arch = 1 if (grep { $target =~ /$_/ } @arch_rules);
+            }
+            if ($arch) {
+                for my $rule (@RULE_CLEAN_DEPENDS) {
+                    if (/$rule->[1]/) {
+                        if ($maybe_skipping) {
+                            $allowed_clean{$rule->[0]} = 1;
+                        } else {
+                            $needed_clean{$rule->[0]}
+                                = $rule->[2] || $needed_clean{$rule->[0]} || '';
+                        }
+                    }
+                }
+                for my $rule (@RULE_CLEAN_ALLOWED) {
+                    if (/$rule->[1]/) {
+                        $allowed_clean{$rule->[0]} = 1;
+                    }
+                }
 	    }
             if (m/^\s+(dh_\S+)\b/ and $debhelper_order{$1}) {
                 my $command = $1;
@@ -173,7 +338,84 @@ if ($architecture eq "all" && scalar @{$rules_per_target{'binary-arch'}}) {
     }
     tag "binary-arch-rules-but-pkg-is-arch-indep" if $nonempty;
 }
+
+# Make sure that all the required build dependencies are there.	 Don't
+# issue missing-build-dependency errors for debhelper, since there's
+# another test that does that and it would just be a duplicate.
+my $build_regular = $info->relation('build-depends');
+my $build_indep   = $info->relation('build-depends-indep');
+for my $package (keys %needed_clean) {
+    my $tag = $needed_clean{$package} || 'missing-build-dependency';
+    unless ($build_regular->implies($package)) {
+        if ($build_indep->implies($package)) {
+            tag "clean-should-be-satisfied-by-build-depends", $package;
+        } else {
+            if ($tag eq 'missing-build-dependency') {
+                tag $tag, $package if $package ne 'debhelper';
+            } else {
+                tag $tag;
+            }
+        }
+    }
 }
+my $noarch = $info->relation_noarch('build-depends-all');
+for my $package (keys %needed) {
+    my $tag = $needed{$package} || 'missing-build-dependency';
+
+    # dh_python deactivates itself if the new Python build policy is enabled.
+    if ($tag eq 'missing-dh_python-build-dependency') {
+        next if -f 'debfiles/pycomat';
+        next if defined $info->field('python-version');
+    }
+    unless ($noarch->implies($package)) {
+        if ($tag eq 'missing-build-dependency') {
+            tag $tag, $package;
+        } else {
+            tag $tag;
+        }
+    }
+}
+
+# This check is a bit tricky.  We want to allow in Build-Depends a dependency
+# with any version, since reporting this tag over version mismatches would be
+# confusing and quite likely wrong.  The approach taken is to strip the
+# version information off all dependencies allowed in Build-Depends, strip the
+# version information off of the dependencies in Build-Depends, and then allow
+# any dependency in Build-Depends that's implied by the dependencies we
+# require or allow there.
+#
+# We also have to map | to , when building the list of allowed packages so
+# that the implications will work properly.
+#
+# This is confusing.  There should be a better way to do this.
+my $arch_dep_packages = 0;
+for my $binpkg (keys %{ $info->binaries } ) {
+    my $arch = $info->binary_field($binpkg, 'architecture');
+    $arch_dep_packages++ unless ($arch eq 'all');
+}
+if (defined $info->field('build-depends') and $arch_dep_packages == 0
+    and not $bypass_needed_clean) {
+    my $build_depends = $info->field('build-depends');
+    my @packages = split /\s*,\s*/, $build_depends;
+    my @allowed = map {
+        s/\([^\)]+\)//g;
+        s/\|/,/g;
+        $_
+    } keys (%needed_clean), keys (%allowed_clean);
+    my $dep = Lintian::Relation->new_noarch(join(',', @allowed));
+    for my $pkg (@packages) {
+        my $name = $pkg;
+        $name =~ s/[\[\(][^\)\]]+[\)\]]//g;
+        $name =~ s/\s+$//;
+        $name =~ s/\s+/ /g;
+        unless ($dep->implies($name)) {
+            tag "build-depends-without-arch-dep", $name;
+        }
+    }
+}
+
+}
+
 1;
 
 # Local Variables:
diff --git a/checks/rules.desc b/checks/rules.desc
index 6c36658..59ebd93 100644
--- a/checks/rules.desc
+++ b/checks/rules.desc
@@ -2,7 +2,7 @@ Check-Script: rules
 Author: Russ Allbery <rra@debian.org>
 Type: source
 Unpack-Level: 1
-Needs-Info: debfiles
+Needs-Info: debfiles, source-control-file
 Info: Check targets and actions in debian/rules.
 Abbrev: rul
 
@@ -101,3 +101,64 @@ Info: One of the targets in the <tt>debian/rules</tt> file for this
  dh_shlibdeps should be called before dh_gencontrol, and all should be
  called before dh_builddeb.  Calling them in the wrong order may cause
  incorrect or missing package files and metadata.
+
+Tag: missing-build-dependency
+Severity: important
+Certainty: certain
+Ref: policy 4.2
+Info: The package doesn't specify a build dependency on a package that is
+ used in <tt>debian/rules</tt>.
+ .
+ lintian intentionally does not take into account transitive dependencies.
+ Even if the package build-depends on some package that in turn
+ depends on the needed package, an explicit build dependency should
+ be added.  Otherwise, a latent bug is created that will appear without
+ warning if the other package is ever updated to change its dependencies.
+ Even if this seems unlikely, please always add explicit build
+ dependencies on every non-essential, non-build-essential package that is
+ used directly during the build.
+
+Tag: missing-python-build-dependency
+Severity: important
+Certainty: certain
+Ref: policy 4.2
+Info: The package appears to use Python as part of its build process in
+ <tt>debian/rules</tt> but doesn't depend on Python.
+ .
+ Normally, packages that use Python as part of the build process should
+ build-depend on one of python, python-all, python-dev, or python-all-dev
+ depending on whether they support multiple versions of Python and whether
+ they're building modules or only using Python as part of the package
+ build process.  Packages that depend on a specific version of Python may
+ build-depend on the appropriate pythonX.Y or pythonX.Y-dev package
+ instead.
+
+Tag: missing-dh_python-build-dependency
+Severity: important
+Certainty: certain
+Ref: dh_python(1)
+Info: The package runs dh_python in <tt>debian/rules</tt> but doesn't
+ build-depend on python or python-dev. dh_python requires
+ <tt>/usr/bin/python</tt> to run, so packages using dh_python must
+ build-depend on python (or python-dev or python-all-dev, which in turn
+ depend on python), even if they don't otherwise need Python to build.
+
+Tag: build-depends-without-arch-dep
+Severity: minor
+Certainty: possible
+Ref: policy 7.7
+Info: The control file lists the given package in Build-Depends, but no
+ architecture-dependent packages are built. If all the packages built are
+ architecture-independent, the only packages that should be listed in
+ Build-Depends are those required to run the clean target (such as
+ debhelper if you use dh_clean). Other build dependencies should be listed
+ in Build-Depends-Indep instead.
+
+Tag: clean-should-be-satisfied-by-build-depends
+Severity: important
+Certainty: certain
+Ref: policy 7.7
+Info: The specified package is required to run the clean target of
+ <tt>debian/rules</tt> and therefore must be listed in Build-Depends, not
+ Build-Depends-Indep, even if no architecture-dependent packages are
+ built.
diff --git a/debian/changelog b/debian/changelog
index 4e46d31..3af203b 100755
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,7 +1,15 @@
 lintian (2.2.14) unstable; urgency=low
 
-  * checks/fields:
+  * checks/fields{,.desc}
     + [FL] packages named lib*-camlp4-dev should be in section ocaml
+    + [RA] Move debian/rules parsing to check build dependencies to
+      checks/rules.
+  * checks/rules{,.desc}:
+    + [RA] Moved checking of build dependencies based on programs invoked
+      in debian/rules from checks/fields to here.
+    + [RA] Expand Lintian's understanding of which targets are run for the
+      clean target to include targets invoked via pattern variable
+      expansion.  (Closes: #536405)
 
   * lib/Spelling.pm:
     + [RA] Add spelling correction for precedence.
diff --git a/t/tests/debhelper-dh-clean-k-ok/debian/debian/control.in b/t/tests/rules-build-dep-pattern/debian/debian/control.in
similarity index 91%
copy from t/tests/debhelper-dh-clean-k-ok/debian/debian/control.in
copy to t/tests/rules-build-dep-pattern/debian/debian/control.in
index 76b52f1..85d12ac 100644
--- a/t/tests/debhelper-dh-clean-k-ok/debian/debian/control.in
+++ b/t/tests/rules-build-dep-pattern/debian/debian/control.in
@@ -3,7 +3,7 @@ Priority: extra
 Section: {$section}
 Maintainer: {$author}
 Standards-Version: {$standards_version}
-Build-Depends: debhelper (>= 6)
+Build-Depends: debhelper (>= 7), python
 
 Package: {$srcpkg}
 Architecture: {$architecture}
diff --git a/t/tests/rules-dh-unused-target-nonempty/debian/debian/rules b/t/tests/rules-build-dep-pattern/debian/debian/rules
similarity index 59%
copy from t/tests/rules-dh-unused-target-nonempty/debian/debian/rules
copy to t/tests/rules-build-dep-pattern/debian/debian/rules
index bb4437f..b0d1e14 100755
--- a/t/tests/rules-dh-unused-target-nonempty/debian/debian/rules
+++ b/t/tests/rules-build-dep-pattern/debian/debian/rules
@@ -5,8 +5,17 @@ build-stamp:
 	dh build
 	touch $@
 
-clean:
-	dh $@
+# From deejayd 0.8.2-1
+clean: $(PYVERS:%=clean-python%)
+
+clean-python%:
+	dh_testdir
+	dh_testroot
+
+	rm -f build-python*
+	python$* setup.py clean --all
+	find $(CURDIR) -name '*pyc' -exec rm -f {} \;
+	dh_clean
 
 install: install-stamp
 install-stamp: build-stamp
@@ -15,12 +24,9 @@ install-stamp: build-stamp
 
 binary-arch: install
 	dh $@
-	# This target is not empty, but it should be
-	-install foo bar
 
 binary-indep: install
 	dh $@
 
 binary: binary-arch binary-indep
-
 .PHONY: binary binary-arch binary-indep install clean build
diff --git a/t/tests/rules-build-dep-pattern/desc b/t/tests/rules-build-dep-pattern/desc
new file mode 100644
index 0000000..5d2d48d
--- /dev/null
+++ b/t/tests/rules-build-dep-pattern/desc
@@ -0,0 +1,6 @@
+Testname: rules-build-dep-pattern
+Sequence: 6000
+Version: 1.0
+Description: Check recognition of pattern dependencies
+Test-Against: build-depends-without-arch-dep
+References: Bug#536405
diff --git a/t/debs/deb-format-record-size/tags b/t/tests/rules-build-dep-pattern/tags
similarity index 100%
copy from t/debs/deb-format-record-size/tags
copy to t/tests/rules-build-dep-pattern/tags

-- 
Debian package checker


Reply to: