5 # Copyright © 2001 Joey Hess <joeyh@debian.org>
6 # Copyright © 2006-2009, 2011-2015 Guillem Jover <guillem@debian.org>
7 # Copyright © 2007-2011 Raphael Hertzog <hertzog@debian.org>
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
25 use Getopt
::Long
qw(:config posix_default bundling_values no_ignorecase);
29 use Dpkg
::ErrorHandling
;
30 use Dpkg
::Arch
qw(get_host_arch);
31 use Dpkg
::Vendor
qw(run_vendor_hook);
32 use Dpkg
::BuildProfiles
qw(get_build_profiles set_build_profiles);
34 use Dpkg
::Control
::Info
;
36 textdomain
('dpkg-dev');
40 printf g_
("Debian %s version %s.\n"), $Dpkg::PROGNAME
, $Dpkg::PROGVERSION
;
45 'Usage: %s [<option>...] [<control-file>]')
48 -A ignore Build-Depends-Arch and Build-Conflicts-Arch.
49 -B ignore Build-Depends-Indep and Build-Conflicts-Indep.
50 -I ignore built-in build dependencies and conflicts.
51 -d build-deps use given string as build dependencies instead of
52 retrieving them from control file
53 -c build-conf use given string for build conflicts instead of
54 retrieving them from control file
55 -a arch assume given host architecture
56 -P profiles assume given build profiles (comma-separated list)
57 --admindir=<directory>
58 change the administrative directory.
59 -?, --help show this help message.
60 --version show the version.')
62 '<control-file> is the control file to process (default: debian/control).')
63 . "\n", $Dpkg::PROGNAME
;
66 my $ignore_bd_arch = 0;
67 my $ignore_bd_indep = 0;
68 my $ignore_bd_builtin = 0;
69 my ($bd_value, $bc_value);
71 my $host_arch = get_host_arch
();
72 my $admindir = $Dpkg::ADMINDIR
;
74 'help|?' => sub { usage
(); exit(0); },
75 'version' => sub { version
(); exit 0; },
76 'A' => \
$ignore_bd_arch,
77 'B' => \
$ignore_bd_indep,
78 'I' => \
$ignore_bd_builtin,
83 'admindir=s' => \
$admindir,
87 local $SIG{__WARN__
} = sub { usageerr
($_[0]) };
88 GetOptions
(@options_spec);
91 # Update currently active build profiles.
92 set_build_profiles
(split(/,/, $bp_value)) if ($bp_value);
93 my @build_profiles = get_build_profiles
();
95 my $controlfile = shift // 'debian/control';
97 my $control = Dpkg
::Control
::Info
->new($controlfile);
98 my $fields = $control->get_source();
100 my $facts = parse_status
("$admindir/status");
102 unless (defined($bd_value) or defined($bc_value)) {
104 push @bd_list, run_vendor_hook
('builtin-build-depends')
105 if not $ignore_bd_builtin;
106 push @bd_list, $fields->{'Build-Depends'};
107 push @bd_list, $fields->{'Build-Depends-Arch'} if not $ignore_bd_arch;
108 push @bd_list, $fields->{'Build-Depends-Indep'} if not $ignore_bd_indep;
109 $bd_value = deps_concat
(@bd_list);
112 push @bc_list, run_vendor_hook
('builtin-build-conflicts')
113 if not $ignore_bd_builtin;
114 push @bc_list, $fields->{'Build-Conflicts'};
115 push @bc_list, $fields->{'Build-Conflicts-Arch'} if not $ignore_bd_arch;
116 push @bc_list, $fields->{'Build-Conflicts-Indep'} if not $ignore_bd_indep;
117 $bc_value = deps_concat
(@bc_list);
119 my (@unmet, @conflicts);
122 my $dep = deps_parse
($bd_value, reduce_restrictions
=> 1,
123 build_dep
=> 1, build_profiles
=> \
@build_profiles,
124 host_arch
=> $host_arch);
125 error
(g_
('cannot parse %s field'),
126 'Build-Depends/Build-Depends-Arch/Build-Depends-Indep')
128 push @unmet, build_depends
($dep, $facts);
131 my $dep = deps_parse
($bc_value, reduce_restrictions
=> 1, union
=> 1,
132 build_dep
=> 1, build_profiles
=> \
@build_profiles,
133 host_arch
=> $host_arch);
134 error
(g_
('cannot parse %s field'),
135 'Build-Conflicts/Build-Conflicts-Arch/Build-Conflicts-Indep')
137 push @conflicts, build_conflicts
($dep, $facts);
141 errormsg
(g_
('Unmet build dependencies: %s'),
142 join(' ', map { $_->output() } @unmet));
145 errormsg
(g_
('Build conflicts: %s'),
146 join(' ', map { $_->output() } @conflicts));
148 exit 1 if @unmet || @conflicts;
150 # Silly little status file parser that returns a Dpkg::Deps::KnownFacts
154 my $facts = Dpkg
::Deps
::KnownFacts
->new();
156 open(my $status_fh, '<', $status)
157 or syserr
(g_
('cannot open %s'), $status);
158 while (<$status_fh>) {
159 next unless /^Status: .*ok installed$/m;
161 my ($package) = /^Package: (.*)$/m;
162 my ($version) = /^Version: (.*)$/m;
163 my ($arch) = /^Architecture: (.*)$/m;
164 my ($multiarch) = /^Multi-Arch: (.*)$/m;
165 $facts->add_installed_package($package, $version, $arch, $multiarch);
167 if (/^Provides: (.*)$/m) {
168 my $provides = deps_parse
($1, reduce_arch
=> 1, virtual
=> 1, union
=> 1);
169 next if not defined $provides;
170 foreach (grep { $_->isa('Dpkg::Deps::Simple') }
171 $provides->get_deps())
173 $facts->add_provided_package($_->{package},
174 $_->{relation
}, $_->{version
},
184 # This function checks the build dependencies passed in as the first
185 # parameter. If they are satisfied, returns false. If they are unsatisfied,
186 # a list of the unsatisfied depends is returned.
188 # Additional parameters that must be passed:
189 # * A reference to a hash of all "ok installed" the packages on the system,
190 # with the hash key being the package name, and the value being the
192 # * A reference to a hash, where the keys are package names, and the
193 # value is a true value iff some package installed on the system provides
194 # that package (all installed packages provide themselves)
196 # Optionally, the architecture the package is to be built for can be passed
197 # in as the 4th parameter. If not set, dpkg will be queried for the build
200 my ($dep_list, $facts) = @_;
202 $dep_list->simplify_deps($facts);
203 if ($dep_list->is_empty()) {
206 return $dep_list->get_deps();
210 # This function is exactly like build_depends(), except it
211 # checks for build conflicts, and returns a list of the packages
212 # that are installed and are conflicted with.
213 sub build_conflicts
{
214 my ($dep_list, $facts) = @_;
217 foreach my $dep ($dep_list->get_deps()) {
218 if ($dep->get_evaluation($facts)) {
219 push @conflicts, $dep;