--- /dev/null
+#!/usr/bin/perl -w
+# GPL copyright 2001 by Joey Hess <joeyh@debian.org>
+
+use strict;
+use Getopt::Long;
+
+sub usage {
+ print STDERR <<EOF;
+Usage: dpkg-checkbuild [-B] [control-file]
+ -B binary-only, ignore -Indep
+ control-file control file to process [Default: debian/control]
+EOF
+}
+
+my ($me)=$0=~m:.*/(.+):;
+
+my $binary_only=0;
+my $want_help=0;
+if (! GetOptions('-B' => \$binary_only,
+ '-h' => \$want_help)) {
+ usage();
+ exit(2);
+}
+if ($want_help) {
+ usage();
+ exit(0);
+}
+
+my $control=shift || "debian/control";
+
+open (CONTROL, $control) || die "$control: $!\n";
+my @status=parse_status();
+my (@unmet, @conflicts);
+while (<CONTROL>) {
+ chomp;
+ last if $_ eq ''; # end of first stanza
+
+ if (/^Build-Depends:\s+(.*)/i) {
+ push @unmet, build_depends($1, @status);
+ }
+ elsif (/^Build-Conflicts:\s+(.*)/i) {
+ push @conflicts, build_conflicts($1, @status);
+ }
+ elsif (! $binary_only && /^Build-Depends-Indep:\s+(.*)/i) {
+ push @unmet, build_depends($1, @status);
+ }
+ elsif (! $binary_only && /^Build-Conflicts-Indep:\s+(.*)/i) {
+ push @conflicts, build_conflicts($1, @status);
+ }
+}
+close CONTROL;
+
+if (@unmet) {
+ print STDERR "$me: Unmet build dependancies: ";
+ print STDERR join(", ", @unmet), "\n";
+}
+if (@conflicts) {
+ print STDERR "$me: Build conflicts: ";
+ print STDERR join(", ", @conflicts), "\n";
+}
+exit 1 if @unmet || @conflicts;
+
+# This part could be replaced. Silly little status file parser.
+# thanks to Matt Zimmerman. Returns two hash references that
+# are exactly what the other functions need...
+sub parse_status {
+ my $status=shift || "/var/lib/dpkg/status";
+
+ my %providers;
+ my %version;
+ local $/ = '';
+ open(STATUS, "<$status") || die "$status: $!\n";
+ while (<STATUS>) {
+ next unless /^Status: .*ok installed$/m;
+
+ my ($package) = /^Package: (.*)$/m;
+ push @{$providers{$package}}, $package;
+ ($version{$package}) = /^Version: (.*)$/m;
+
+ if (/^Provides: (.*)$/m) {
+ foreach (split(/,\s+/, $1)) {
+ push @{$providers{$_}}, $package;
+ }
+ }
+ }
+ close STATUS;
+
+ return \%version, \%providers;
+}
+
+# This function checks the build dependancies passed in as the first
+# parameter. If they are satisfied, returns false. If they are unsatisfied,
+# an list of the unsatisfied depends is returned.
+#
+# Additional parameters that must be passed:
+# * A reference to a hash of all "ok installed" the packages on the system,
+# with the hash key being the package name, and the value being the
+# installed version.
+# * A reference to a hash, where the keys are package names, and the
+# value is a true value iff some package installed on the system provides
+# that package (all installed packages provide themselves)
+#
+# Optionally, the architecture the package is to be built for can be passed
+# in as the 4th parameter. If not set, dpkg will be queried for the build
+# architecture.
+sub build_depends {
+ return check_line(1, @_);
+}
+
+# This function is exactly like unmet_build_depends, except it
+# checks for build conflicts, and returns a list of the packages
+# that are installed and are conflicted with.
+sub build_conflicts {
+ return check_line(0, @_);
+}
+
+# This function does all the work. The first parameter is 1 to check build
+# deps, and 0 to check build conflicts.
+sub check_line {
+ my $build_depends=shift;
+ my $line=shift;
+ my %version=%{shift()};
+ my %providers=%{shift()};
+ my $build_arch=shift || `dpkg --print-architecture`;
+ chomp $build_arch;
+
+ my @unmet=();
+ foreach my $dep (split(/,\s+/, $line)) {
+ my $ok=0;
+ my @possibles=();
+ALTERNATE: foreach my $alternate (split(/\s*\|\s*/, $dep)) {
+ my ($package, $rest)=split(/\s+/, $alternate, 2);
+
+ # Check arch specifications.
+ if (defined $rest && $rest=~m/\[(.*?)\]/) {
+ my $arches=lc($1);
+ my $seen_arch='';
+ foreach my $arch (split(' ', $arches)) {
+ if ($arch eq $build_arch) {
+ $seen_arch=1;
+ next;
+ }
+ elsif ($arch eq "!$build_arch") {
+ next ALTERNATE;
+ }
+ elsif ($arch =~ /!/) {
+ # This is equivilant to
+ # having seen the current arch,
+ # unless the current arch
+ # is also listed..
+ $seen_arch=1;
+ }
+ }
+ if (! $seen_arch) {
+ next;
+ }
+ }
+
+ # This is a possibile way to meet the dependancy.
+ # Remove the arch stuff from $alternate.
+ $alternate=~s/\s+\[.*?\]//;
+ push @possibles, $alternate;
+
+ # Check version.
+ if (defined $rest && $rest=~m/\((..)\s+(.*?)\)/) {
+ my $relation=$1;
+ my $version=$2;
+
+ if (! exists $version{$package}) {
+ # Not installed at all, so fail.
+ next;
+ }
+ else {
+ # Compare installed and needed
+ # version number.
+ system("dpkg", "--compare-versions",
+ $version{$package}, $relation,
+ $version);
+ if (($? >> 8) != 0) {
+ next; # fail
+ }
+ }
+ }
+ elsif (! defined $providers{$package}) {
+ # It's not a versioned dependancy, and
+ # nothing provides it, so fail.
+ next;
+ }
+
+ # If we get to here, the dependancy was met.
+ $ok=1;
+ }
+
+ if (@possibles && (($build_depends && ! $ok) ||
+ (! $build_depends && $ok))) {
+ # TODO: this could return a more complex
+ # data structure instead to save re-parsing.
+ push @unmet, join (" | ", @possibles);
+ }
+ }
+
+ return @unmet;
+}