#!/usr/bin/perl # Copyright (C) 2009-2011 Neil Williams # Copyright © 1998 Richard Braakman # Portions Copyright © 1999 Darren Benham # Portions Copyright © 2000 Sean 'Shaleh' Perry # Portions Copyright © 2004 Frank Lichtenheld # Portions Copyright © 2006 Russ Allbery # This package is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . use strict; use warnings; use File::Basename; use Cwd qw (realpath); use POSIX qw(locale_h); use Term::ANSIColor qw(:constants); use Config::IniFiles; use Locale::gettext; use Data::Dumper; use Dpkg::Deps; use Dpkg::Arch qw(get_host_arch debarch_is debarch_to_debtriplet); use Dpkg::ErrorHandling; use vars qw/ $progname $ourversion $name $deps $ret @list %res @constraint @series $splice $constraint $version $check $pkg $policy @bits $limit $c $msg $vendor $tools @dependencies @aptlist $use_sudo $pbuilding $arch $dryrun $cmd $pdebuild_dsc $pdebuild_dir $pdebuild_cmd $dir $build $pdebuild_target $pdebuild_opt $cmdline $buildconflict $archlimit %buildarchdep @buildarchdeps @hostarchdeps @buildalts $facts $verbose $configfile $vendor $noauth $vendor_name $config %crossres @unmet $use_dsc $preserve $multiarch /; setlocale(LC_MESSAGES, ""); textdomain("xapt"); $verbose = 1; $progname = basename($0); $ourversion = &scripts_version(); $build = `dpkg-architecture -qDEB_BUILD_ARCH`; $noauth=''; $preserve=''; $multiarch=''; # fix broken shell command line parsing my @arg=(); while( @ARGV ) { my @ar = split(/ /, shift); push @arg, @ar; } @ARGV=(); push @ARGV, @arg; while( @ARGV ) { $_= shift( @ARGV ); last if m/^--$/; if (!/^-/) { unshift(@ARGV,$_); shift; next; } elsif (/^(-\?|-h|--help|--version)$/) { &usageversion(); exit 0; } elsif (/^(-k|--preserve)$/) { $preserve = "-k"; } elsif (/^(-v|--verbose)$/) { $verbose++; } elsif (/^(-q|--quiet)$/) { $verbose--; } elsif (/^(-m|--multiarch)$/) { $multiarch = "-m"; } elsif (/^(-a|--arch)$/) { $arch = shift(@ARGV); undef $arch if ($arch eq $build); if (not defined (debarch_to_debtriplet ($arch))) { warn RED, "$progname: ".sprintf(_g("Unknown architecture: %s"),$arch), RESET, "\n"; undef $arch; } } elsif (/^(-d|--dir)$/) { $dir = shift; if (-d $dir) { $dir = realpath ($dir); chdir ($dir); } else { die RED, "$progname: ".sprintf(_g("Unable to find '%s' directory"),$dir), RESET, "\n"; } } elsif (/^(--use-sudo)$/) { $use_sudo++; } elsif (/^(--dsc)$/) { $use_dsc = shift; die RED, "$progname: "._g("Please specify a .dsc file"), RESET, "\n" if (not defined $use_dsc); # allow pbuilder to pass arguments } elsif (/^(--control)$/) { $pdebuild_dsc = shift(@ARGV); } elsif (/^(--internal-chrootexec)$/) { $pdebuild_cmd = shift(@ARGV); $pdebuild_cmd .= ' '.shift(@ARGV); } elsif (/^(--chroot)$/) { $pdebuild_dir = shift(@ARGV); } elsif (/^(--binary-all)$/) { $pdebuild_target = "--binary-all"; } elsif (/^(-n|--dry-run)$/) { $dryrun++; } else { &usageversion(); die RED, "$progname: "._g("Unknown option")." $_.\n", RESET; } } # work out if we need to use noauth using xapt config. $vendor = "debian"; if (-f "/usr/bin/dpkg-vendor") { $vendor_name = `LC_ALL=C dpkg-vendor --vendor $vendor --query vendor`; chomp ($vendor_name); $vendor_name = lc($vendor_name); } else { $vendor_name = "debian"; } $configfile = "/etc/xapt.d/$vendor_name.conf"; die (RED, "$progname:", sprintf(_g("Cannot read /etc/xapt.d/%s.conf"), $vendor_name), RESET, "\n") if (not -r "/etc/xapt.d/$vendor_name.conf"); $configfile = "/etc/xapt.d/$vendor_name.conf"; $config = new Config::IniFiles( -file => $configfile ); $noauth = " -o Apt::Get::AllowUnauthenticated=true " if ($config->val(lc($vendor_name), 'noauth') eq 'true'); # work out if this is a pbuilder call if (defined $pdebuild_dir and defined $pdebuild_cmd) { if (not -d $pdebuild_dir) { warn RED, "$progname:", _g("Unknown option"), "$pdebuild_dir", RESET, "\n"; exit 1; } else { $pbuilding++; } } if (not defined $use_dsc) { # make sure the data is where we can find it. if (not -f "debian/changelog") { print `pwd` if ($verbose >= 1); system ("ls -al") if ($verbose >= 2); } $name=`dpkg-parsechangelog|grep Source:`; chomp ($name); $name =~ s/Source: //; } else { open (DSC, "$use_dsc") or die (RED, "$progname:", sprintf(_g("Unable to open .dsc file: '%s'"), $use_dsc), RESET, "\n"); my @dsc=; close (DSC); foreach my $dline (@dsc) { if ($dline =~ /^Source: (.*)$/) { $name = $1; } } } # begin parsing native build dependencies. if (defined $pbuilding) { # now parse the native deps in the chroot $facts = &parse_status("$pdebuild_dir/var/lib/dpkg/status"); } else { # now parse the native deps outside, as req'd. $facts = &parse_status("/var/lib/dpkg/status"); } &get_build_deps($facts); if (($verbose > 0) and defined $deps) { print GREEN; printf (_g("Checking that build dependencies '%s' for %s are installed.\n"), $deps, $name); print RESET; } @unmet=(); if ($deps) { push @unmet, build_depends('Build-Depends/Build-Depends-Indep)', deps_parse($deps, reduce_arch => 1), $facts); } if (@unmet) { map { $_->output_pkg($_)} @unmet; } my $list = join (" ", sort keys %res); $cmd = (defined $use_sudo) ? "sudo" : ""; # overwrite this if inside pbuilder. $cmd = (defined $pbuilding) ? $pdebuild_cmd : ""; if (scalar keys %res <= 0) { if ($verbose > 0) { print GREEN; printf (_g("No build dependencies to install for %s\n"), $name); print RESET; } exit 0 if (not defined $arch); } else { if ($verbose > 0) { print GREEN; printf (_g("%s needs dependencies installed:\n"), $name); print RESET; } if (defined $pbuilding) { $cmdline = "$cmd /usr/bin/apt-get update"; &run_command ($cmdline); } $cmdline = "$cmd /usr/bin/apt-get -y $noauth install " . join (" ", sort keys %res); &run_command ($cmdline); exit 0 if (not defined $arch); } # clear the dependency stack ready for cross dependencies. undef $facts; undef $deps; %res=(); @unmet=(); # doesn't matter if this is outside the chroot, it remains empty # until Multi-Arch is available. my $status = `mktemp -t embuilddeps.XXXXXX`; chomp ($status); $facts = &parse_status($status); &get_build_deps($facts, $arch); if ($deps) { push @unmet, build_depends('Build-Depends/Build-Depends-Indep)', deps_parse($deps, use_arch => 1), $facts); } if (@unmet) { map { $_->output_pkg($_)} @unmet; } # drop architecture-specific deps which are not for us. foreach my $depname (keys %res) { # Translators: fields are package, architecture. if ($res{$depname}{$arch} == 0) { if ($verbose > 2) { print BLUE; # Translators: fields are architecture and package. printf(_g("Architecture limit: [!%s] %s\n"), $arch, $depname); print RESET; } delete $res{$depname}; } } %crossres = %res; # handle Build-Depends-Tools, if any if (scalar @buildarchdeps > 0) { print GREEN; printf (_g("%s needs dependencies installed:\n"), $name); print RESET; my $cmdline = "$cmd /usr/bin/apt-get -y $noauth install " . join (" ", sort @buildarchdeps); &run_command ($cmdline); } if (scalar keys %crossres <= 0) { if ($verbose > 0) { print GREEN; printf (_g("No cross dependencies to install for %s\n"), $name); print RESET; } exit 0; } if (($verbose > 0) and defined $deps) { print GREEN; printf (_g("Checking that cross build dependencies '%s' for %s are installed.\n"), $deps, $name); print RESET; } undef $facts; unlink ($status); # do not try to isolate build tools from build dependencies $list = join (" ", sort keys %crossres); if (defined $pbuilding) { if ($verbose > 0) { print GREEN; printf(ngettext("'%s' needs %d cross dependency installed: %s\n", "'%s' needs %d cross dependencies installed: %s\n", scalar keys %crossres), $name, scalar keys %crossres, join(" ", keys %crossres)); print RESET; } if (not -x "$pdebuild_dir/usr/sbin/xapt") { my $av = `LC_ALL=C $cmd /usr/bin/apt-cache policy xapt 2>/dev/null`; chomp ($av); if ($av =~ /xapt/) { system ("$cmd /usr/bin/apt-get -y $noauth install xapt"); } } # the addition of libc6 and libc6-dev is a nasty hack my $cmdline = "$cmd /usr/sbin/xapt -a $arch $multiarch $preserve $list libc6 libc6-dev"; &run_command ($cmdline); $cmdline = "$cmd /usr/bin/apt-get -y -f $noauth install"; &run_command ($cmdline); exit 0; } if ($verbose > 0) { print GREEN; printf(ngettext("'%s' needs %d cross dependency installed: %s\n", "'%s' needs %d cross dependencies installed: %s\n", scalar keys %crossres), $name, scalar keys %crossres, join (" ", keys %crossres)); print RESET; } my $cmdline = "$cmd /usr/sbin/xapt -a $arch $multiarch $preserve " . join (" ", sort keys %crossres); &run_command ($cmdline); exit 0; # sub routines sub run_command { my $cmdline = shift; if (defined $dryrun) { print "$cmdline\n"; } else { print "$cmdline\n" if ($verbose >= 1); my $retval = system ("$cmdline"); $retval >>= 8; exit ($retval) if ($retval != 0); } } sub get_build_deps { my $facts = shift; my $ctrl; if (defined $use_dsc ) { $ctrl = $use_dsc; } elsif (-f "debian/xcontrol" and (defined $arch)) { $ctrl = "debian/xcontrol"; } else { $ctrl = "debian/control"; } open (XC, "<$ctrl"); my @xc=; close (XC); &parse_build_depends (@xc); } sub parse_build_depends { my @xc = @_; # allow multi-lines my $str = join ("", @xc); $str =~ s/\n / /g; $str =~ s/ / /g; my @long = split ("\n", $str); @buildarchdeps=(); foreach my $line (@long) { if ($line =~ /^Build-Depends: /) { $line =~ s/^Build-Depends: //; $line =~ s/ +/ /g; $deps = $line; } if ($line =~ /^Build-Depends-Indep: /) { $line =~ s/^Build-Depends-Indep: //; $line =~ s/ +/ /g; $deps .= ", ". $line; } if ($line =~ /^Build-Depends-Tools: /) { $line =~ s/^Build-Depends-Tools: //; $line =~ s/ +/ /g; my @tools = split(/, /, $line); my $b = (&check_constraints($facts, @tools)); push @buildarchdeps, @$b; } if ($line =~ /^Build-Conflicts: /) { $line =~ s/^Build-Conflicts: //; $buildconflict = $line; } } if (defined $buildconflict) { if ($verbose > 0) { print BLUE; printf (_g("Checking Build-Conflict between '%s' and '%s'\n"), $name, $buildconflict); print RESET; } if (not defined $pbuilding) { my @conflicts=split(/, /,$buildconflict); foreach my $buildcflt (@conflicts) { my ($package, $constraint, $version, $instver, $retval); if ($buildcflt =~ m:^(.+)\s\((.+)\s(.+)\)$:) { $package = $1; $constraint = $2; $version = $3; $instver = `LC_ALL=C dpkg-query -W -f '\${Version}' $package 2>/dev/null`; if ($instver ne '') { $retval = system("LC_ALL=C dpkg --compare-versions $version \"$constraint\" ". "`dpkg-query -W -f'\${Version}' $package 2>/dev/null` 2>/dev/null"); $retval >>= 8; if ($retval) { print STDERR RED; warn sprintf(_g("%s: Error: Cannot build '%s': build conflict found with '%s'\n"), $progname, $name, $package); print STDERR RESET; print "\n"; exit 1; } } } else { $check = `LC_ALL=C dpkg-query -W -f '\${Status}' $buildcflt 2>/dev/null`; chomp ($check); if ($check =~ /^install ok installed$/) { print STDERR RED; warn sprintf(_g("%s: Error: Cannot build '%s': build conflict found with '%s'\n"), $progname, $name, $buildconflict); print STDERR RESET; print "\n"; exit 1; } } } } } my @chk= join(", ", $deps); &check_constraints ($facts, @chk); } sub Dpkg::Deps::Simple::output_pkg { my ($self, $fh) = @_; my $archlabel = (not defined $arch) ? 'arch' : $arch; my $pkg = $self->{package}; $res{$pkg}{'version'} = (defined $self->{version}) ? $self->{version}->as_string() : ''; if (defined($self->{'arches'})) { foreach my $deparch (@{$self->{arches}}) { $res{$pkg}{$archlabel} = 0 if (not exists $res{$pkg}{$archlabel}); my $retval = 1; if ($deparch =~ /^!/) { $deparch =~ s/!//; if (debarch_is($archlabel, $deparch) == 1) { if ($verbose > 1) { print BLUE; # Translators: fields are architecture and package. printf (_g("Architecture limit: [!%s] %s\n"), $archlabel, $pkg); print RESET; } $res{$pkg}{$archlabel} = 0; } else { $res{$pkg}{$archlabel} = 1; } next; } if (debarch_is($archlabel, $deparch) == 1) { if ($verbose > 1) { print BLUE; # Translators: fields are architecture and package. printf (_g("Architecture limit: [%s] %s\n"), $archlabel, $pkg); print RESET; } $res{$pkg}{$archlabel} = 1; } } } elsif ($pkg ne '') { $res{$pkg}{$archlabel} = 1; } } sub Dpkg::Deps::OR::output_pkg { my ($self, $fh) = @_; my $skip; push my @a, $self->get_deps(); my $archlabel = (not defined $arch) ? 'arch' : $arch; foreach my $dep (@a) { my $omit = &check_special ($self->get_deps()); if (defined $omit and scalar @$omit > 0) { foreach my $o (@$omit) { delete $res{$o}; } last; } if (ref($dep) !~ /ARRAY/) { if (defined $dep->{arches}) { foreach my $chk (@{$dep->{arches}}) { # doesn't work for linux-any anymore. if (debarch_is($arch, $chk) == 0) { if ($verbose > 1) { print BLUE; # Translators: fields are package, architecture, requirement printf (_g("Skipping %s, %s does not match %s\n"), $dep->{package}, $arch, $chk); print RESET; } next; } else { if ($verbose > 1) { print BLUE; # Translators: fields are package and architecture printf (_g("Using %s for %s\n"), $dep->{package}, $chk); print RESET; } $res{$dep->{package}}{'version'} = (defined $dep->{version}) ? $dep->{version}->as_string() : ''; $res{$dep->{package}}{$archlabel} = 1; $skip++; } } } # if the alternative has no arch dependency, use it unless already got one. if (not defined $dep->{arches} and not defined $skip) { my @iter = $self->{list}; foreach my $i (@iter) { foreach my $ii (@$i) { if (not defined ($ii->{arches})) { if (not defined $res{$dep->{package}}{'version'}) { if ($ii->{package} eq $dep->{package}) { if ($verbose > 1) { print BLUE; # Translators: fields are package and architecture printf (_g("Using %s for %s\n"), $dep->{package}, $arch); print RESET; } $res{$dep->{package}}{'version'} = (defined $dep->{version}) ? $dep->{version}->as_string() : ''; $res{$dep->{package}}{$archlabel} = 1; } elsif (defined $res{$ii->{package}}) { if ($verbose > 1) { print BLUE; # Translators: fields are package, architecture and alternative printf(_g("Omitting %s for %s - already selected %s\n"), $dep->{package}, $arch, $ii->{package}); print RESET; } delete ($res{$dep->{package}}); last; } } } } } } next; } if (ref($dep) =~ /ARRAY/ and scalar @{$dep->{arches}} > 0) { foreach my $deparch (@{$dep->{arches}}) { my $retval = ($deparch =~ /^!/) ? 0 : 1; $deparch =~ s/^!//; if (debarch_is($archlabel, $deparch) == $retval) { $res{$dep->{package}}{'version'} = (defined $dep->{version}) ? $dep->{version}->as_string() : ''; $res{$dep->{package}}{$archlabel} = 1; } elsif (not defined $res{$dep->{package}}{$arch}) { $res{$dep->{package}}{'version'} = (defined $dep->{version}) ? $dep->{version}->as_string() : ''; $res{$dep->{package}}{$archlabel} = 0; } } } else { my @alternatives = $self->{list}; foreach my $alt (@alternatives) { my $first; foreach my $a (@$alt) { $res{$a->{package}}{'version'} = (defined $dep->{version}) ? $dep->{version}->as_string() : ''; $res{$a->{package}}{$archlabel} = 1; $first = $a->{package}; last; } foreach my $a (@$alt) { next if ($first eq $a->{package}); ${$res{$first}{'alternate'}}{$a->{package}} = (defined $a->{version}) ? $a->{version}->as_string() : ''; } } } } } sub expand_arch_limit { my $check = shift; my $limit = shift; my @a = (debarch_to_debtriplet ($check)); my @c = split (/-/, $limit); my $ret = scalar @c; foreach my $str (@c) { if (grep(/\Q$str\E/, @a)) { $ret--; } } return $ret; } sub check_special { my @a = @_; my %omit=(); my $seq; my @ret=(); my $typehandling; foreach my $dep (@a) { $omit{$dep->{package}}++; } $typehandling = `apt-cache show type-handling|grep Provides`; chomp ($typehandling); foreach my $pkg (keys %omit) { if (grep (/\Q$pkg\E/, $typehandling)) { my $allow = $pkg; $allow =~ s/\Qnot+\E//; next if (expand_arch_limit($arch, $allow) == 0); delete $omit{$pkg}; $seq = join ('', keys %omit); if ($verbose > 1) { print BLUE; printf (_g("Constraint '%s' is a virtual package provided by 'type-handling', omitting %s for %s\n"), $pkg, $seq, $arch); print RESET; } @ret = keys %omit; return \@ret; } } return undef; } sub check_constraints { my $facts = shift; my @depends=@_; @constraint=(); my $installedok; my @virt=(); my @section = split(/, /, join (', ', @depends)); foreach $constraint (@section) { undef $limit; undef $version; undef $installedok; $constraint =~ s/^ +//; $constraint =~ s/,//; $constraint =~ s/\[.*\]//; $constraint =~ s/\|.*//; @bits=split(/ /, $constraint); $pkg = $bits[0]; next if (not defined $pkg); if (defined $bits[1]) { $limit = $bits[1]; $limit =~ s/\(//; } if (defined $bits[2]) { $version = $bits[2]; $version =~ s/\)//; } $pkg =~ s/ //g; # cannot usefully check versions inside the chroot from outside # or when cross-building before Multi-Arch is working if (defined $pbuilding or defined $arch) { my $typehandling; if (-x "/usr/bin/grep-available") { $typehandling = `grep-available -s Provides type-handling`; chomp ($typehandling); if (grep (/\Q$pkg\E/, $typehandling)) { print BLUE; printf (_g("Constraint '%s' is a virtual package provided by 'type-handling', omitting.\n"), $pkg); print RESET; next; } } $policy=`LC_ALL=C apt-cache policy $pkg 2>/dev/null|grep Candidate|cut -d':' -f2-3|tr -d ' '`; chomp ($policy); if ($policy eq "(none)") { print BLUE; printf (_g("Constraint '%s' is not available, omitting. (This could be a virtual package or a bug.)\n"), $pkg); print RESET; next; } push @constraint, $pkg; } else { $check = `LC_ALL=C dpkg-query -W -f '\${Status}' $pkg 2>/dev/null`; chomp ($check); if ($check !~ /^install ok installed$/) { # not installed, may be virtual but we can't tell from here push @constraint, $pkg; next if (not defined $limit); } else { $installedok++; } if (not defined $limit) { next; } # now check the version constraint $policy=`LC_ALL=C apt-cache policy $pkg 2>/dev/null|grep Candidate|cut -d':' -f2-3|tr -d ' '`; chomp ($policy); $msg = sprintf (_g("%s: Failed to read apt-cache policy for '%s'\n"), $progname, $pkg); die (RED, $msg, RESET) if ($policy eq "\n"); chomp ($policy); if (defined $version) { $check = ($policy ne '') ? `LC_ALL=C dpkg --compare-versions $policy \"$limit\" $version ; echo \$?` : 1; chomp ($check); print "Checking constraints for '$constraint':pkg=$pkg:policy=$policy:limit='$limit':version=$version\n" if ($verbose > 2); if ($check != 0) { warn RED, "$progname:", sprintf(_g("Unable to satisfy 'Build-Depends: %s (%s %s)' for %s."), $pkg, $limit, $version, $name), RESET, "\n"; if ($policy ne '') { warn RED, "$progname:", sprintf(_g("Latest available version of %s is %s"), $pkg, $policy), RESET, "\n"; } else { warn RED, "$progname:", sprintf(_g("'%s' does not appear to be available to apt!"), $pkg), RESET, "\n"; } exit 1; } else { # available and not installed already push @constraint, $pkg if (not defined $installedok); } next; } push @constraint, $pkg; } } return (\@constraint); } # Silly little status file parser that returns a Dpkg::Deps::KnownFacts sub parse_status { my $status = shift; my $facts = Dpkg::Deps::KnownFacts->new(); local $/ = ''; open(STATUS, "<$status") || die "$status: $!\n"; while () { next unless /^Status: .*ok installed$/m; my ($package) = /^Package: (.*)$/m; my ($version) = /^Version: (.*)$/m; $facts->add_installed_package($package, $version); if (/^Provides: (.*)$/m) { my $provides = deps_parse($1, reduce_arch => 1, union => 1); next if not defined $provides; foreach (grep { $_->isa('Dpkg::Deps::Simple') } $provides->get_deps()) { $facts->add_provided_package($_->{package}, $_->{relation}, $_->{version}, $package); } } } close STATUS; return $facts; } sub build_depends { return check_line(1, @_); } # 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 $fieldname=shift; my $dep_list=shift; my $facts=shift; my $host_arch = shift || get_host_arch(); chomp $host_arch; my @unmet=(); unless(defined($dep_list)) { error(_g("error occurred while parsing %s"), $fieldname); } if ($build_depends) { $dep_list->simplify_deps($facts); if ($dep_list->is_empty()) { return (); } else { return $dep_list->get_deps(); } } else { # Build-Conflicts my @conflicts = (); foreach my $dep ($dep_list->get_deps()) { if ($dep->get_evaluation($facts)) { push @conflicts, $dep; } } print "Conflicts:\n"; print Dumper (\@conflicts); return @conflicts; } } sub usageversion { printf STDERR (_g(" %s version %s Usage: %s [-a|--arch] [-d|--dir] [-q|--quiet] [-n|--dry-run] %s -?|-h|--help|--version Options: -a|--arch: Install cross packages for the specified arch. -d|--dir DIR: Location of the unpacked source (./debian/control) --dsc DSCFILE: Path to a .dsc file for the package. -m|--multiarch: Make dpkg-cross convert Multi-Arch packages. -v|--verbose: Make the output more verbose -q|--quiet: Make the output less verbose -n|--dry-run: Only output the commands which would be used. --use-sudo: Call apt-get using sudo. %s is a simple build dependency checker for cross-building. Native build dependencies are checked using the debian/control file in the source package being built and installed with apt-get. Cross build dependencies are checked using a debian/xcontrol file or the debian/control file if no xcontrol file exists. %s uses xapt to install cross build dependencies. "), $progname, $ourversion, $progname, $progname,$progname,$progname ); } sub scripts_version { my $query = `LC_ALL=C dpkg-query -W -f='\${Version}' xapt 2>/dev/null`; (defined $query) ? return $query : return ""; } sub _g { return gettext(shift); } =pod =head1 NAME embuilddeps - handle native and cross build-dependency installation. =head1 Usage embuilddeps [-a|--arch] [--use-sudo] embuilddeps -?|-h|--help|--version =head1 Options -a|--arch: Install cross packages for the specified arch. -d|--dir DIR: Location of the unpacked source (./debian/control) --dsc DSCFILE: Path to a .dsc file for the package. -m|--multiarch: Make dpkg-cross convert Multi-Arch packages. -k|--preserve: Pass the -k option down to xapt. -v|--verbose: Make the output more verbose -q|--quiet: Make the output less verbose -n|--dry-run: Only output the commands which would be used. --use-sudo: Call apt-get using sudo. =head1 Description C is a simple build dependency checker for cross-building. Native build dependencies are checked using the F file in the source package being built and installed with C. Cross build dependencies are checked using a F file or the F file if no xcontrol file exists. C uses C to install cross build dependencies. =head1 Output To see more about what is going on (and to check the results of parsing the dependencies and architecture limits. See also Term::ANSIColor (3) for information on ANSI_COLORS_DISABLED. =head1 pbuilder C can be used as a native and cross-dependency resolver in a pbuilder chroot using C, C or C and supports pbuilder options to locate the chroot and execute calls within the chroot. --control indicates the location of the .dsc file --internal-chrootexec indicates the command to execute inside the chroot --chroot indicates the location of the chroot --binary-all is supported as a no-op by C. If other build tools need particular options to be supported, please file a wishlist bug against C and describe the exact options which are necessary. C does require that C is installed inside the chroot - it will try to install it for you but it is much easier if you install it once and for all. C will add C when creating a new chroot. See pdebuild-cross (1) for more information on how to manipulate a pdebuild-cross chroot after creation. =head1 Source packages and dsc files C can also parse the build dependencies of a package via the F<.dsc> file. The rest of the source package (the files listed in the F<.dsc>) do B need to exist and the source does not need to have been unpacked. Use the C option. The alternative method is to parse the F<./debian/control> file at the location specified by the C<--dir> option which defaults to the current working directory. =head1 Multi-Arch transition Some packages already have multi-arch paths which dpkg-cross does not normally convert. This can cause missing dependencies when trying to install the converted packages. Use the C<--multiarch> option to C to pass this down to C and hence to C. =head1 Retaining downloaded binaries C can pass the C<-k> option to C to retain the foreign architecture packages downloaded by C and the packages built using C. Note that C should be asked to clean up the downloaded files once these lists have been handled by calling the C option which removes the contents of F. =cut