summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--build-deps.control3
-rwxr-xr-xsrc/mk-build-deps543
3 files changed, 547 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index d341da5..b5d2a36 100644
--- a/Makefile
+++ b/Makefile
@@ -21,8 +21,8 @@ stack:
21 21
22build-deps: build-deps-stamp 22build-deps: build-deps-stamp
23build-deps-stamp: build-deps.control 23build-deps-stamp: build-deps.control
24 sudo apt --no-upgrade install equivs 24 sudo apt --no-upgrade install equivs libdpkg-perl
25 sudo mk-build-deps --root-cmd sudo build-deps.control --install --remove 25 sudo ./src/mk-build-deps --root-cmd sudo build-deps.control --install --remove
26 touch $@ 26 touch $@
27 27
28dynmenu: src/dynmenu.cpp | build-deps 28dynmenu: src/dynmenu.cpp | build-deps
diff --git a/build-deps.control b/build-deps.control
index a946554..9810ca5 100644
--- a/build-deps.control
+++ b/build-deps.control
@@ -2,8 +2,9 @@ Source: sami
2Build-Depends: bridge-utils, 2Build-Depends: bridge-utils,
3 build-essential, 3 build-essential,
4 cryptsetup, 4 cryptsetup,
5 devscripts, 5 equivs,
6 libbz2-dev, 6 libbz2-dev,
7 libdpkg-perl,
7 libncurses-dev, 8 libncurses-dev,
8 libssl-dev, 9 libssl-dev,
9 parted, 10 parted,
diff --git a/src/mk-build-deps b/src/mk-build-deps
new file mode 100755
index 0000000..61b309c
--- /dev/null
+++ b/src/mk-build-deps
@@ -0,0 +1,543 @@
1#!/usr/bin/perl
2
3# mk-build-deps: make a dummy package to satisfy build-deps of a package
4# Copyright 2008 by Vincent Fourmond
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20# Changes:
21# * (Vincent Fourmond 4/4/2008): now take Build-Depends-Indep
22# into consideration
23
24=head1 NAME
25
26mk-build-deps - build a package satisfying a package's build-dependencies
27
28=head1 SYNOPSIS
29
30B<mk-build-deps> B<--help>|B<--version>
31
32B<mk-build-deps> [I<options>] I<control file> | I<package name> ...
33
34=head1 DESCRIPTION
35
36Given a I<package name> and/or I<control file>, B<mk-build-deps>
37will use B<equivs> to generate a binary package which may be installed to
38satisfy all the build dependencies of the given package.
39
40If B<--build-dep> and/or B<--build-indep> are given, then the resulting binary
41package(s) will depend solely on the Build-Depends/Build-Depends-Indep
42dependencies, respectively.
43
44=head1 OPTIONS
45
46=over 4
47
48=item B<-i>, B<--install>
49
50Install the generated packages and its build-dependencies.
51
52=item B<-t>, B<--tool>
53
54When installing the generated package use the specified tool.
55(default: B<apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends>)
56
57=item B<-r>, B<--remove>
58
59Remove the package file after installing it. Ignored if used without
60the B<--install> switch.
61
62=item B<-a> I<foo>, B<--arch> I<foo>
63
64Set the architecture of the produced binary package to I<foo>. If this option
65is not given, fall back to the value given by B<--host-arch>. If neither this
66option nor B<--host-arch> are given but the Build-Depends contain architecture
67restrictions, use the value printed by `dpkg-architecture -qDEB_HOST_ARCH`.
68Otherwise, use I<all>.
69
70The package architecture must be equal to the host architecture except if the
71package architecture is I<all>.
72
73The package architecture cannot be I<all> if the build and host architecture
74differ.
75
76=item B<--host-arch> I<foo>
77
78Set the host architecture the binary package is built for. This defaults to
79the value printed by `dpkg-architecture -qDEB_HOST_ARCH`. Use this option to
80create a binary package that is able to satisfy crossbuild dependencies.
81
82If this option is used together with B<--arch>, then they must be equal except
83if the value of B<--arch> is I<all>.
84
85If B<--arch> is not given, then this option also sets the package architecture.
86
87=item B<--build-arch> I<foo>
88
89Set the build architecture the binary package is built for. This defaults to
90the value printed by `dpkg-architecture -qDEB_BUILD_ARCH`. Use this option to
91create a binary package that is able to satisfy crossbuild dependencies.
92
93=item B<-B>, B<--build-dep>
94
95Generate a package which only depends on the source package's Build-Depends
96dependencies.
97
98=item B<-A>, B<--build-indep>
99
100Generate a package which only depends on the source package's
101Build-Depends-Indep dependencies.
102
103=item B<-h>, B<--help>
104
105Show a summary of options.
106
107=item B<-v>, B<--version>
108
109Show version and copyright information.
110
111=item B<-s>, B<--root-cmd>
112
113Use the specified tool to gain root privileges before installing.
114Ignored if used without the B<--install> switch.
115
116=back
117
118=head1 AUTHOR
119
120B<mk-build-deps> is copyright by Vincent Fourmond and was modified for the
121devscripts package by Adam D. Barratt <adam@adam-barratt.org.uk>.
122
123This program comes with ABSOLUTELY NO WARRANTY.
124You are free to redistribute this code under the terms of the GNU
125General Public License, version 2 or later.
126
127=cut
128
129use 5.01;
130use strict;
131use warnings;
132use Getopt::Long qw(:config bundling permute no_getopt_compat);
133use File::Basename;
134use Pod::Usage;
135use Dpkg::Control;
136use Dpkg::Version;
137use Dpkg::IPC;
138use Dpkg::Deps;
139use FileHandle;
140use Text::ParseWords;
141
142my $progname = basename($0);
143my $opt_install;
144my $opt_remove=0;
145my ($opt_help, $opt_version, $opt_arch, $opt_dep, $opt_indep, $opt_hostarch, $opt_buildarch);
146my $control;
147my $install_tool;
148my $root_cmd;
149my @packages;
150
151my @config_files = ('/etc/devscripts.conf', '~/.devscripts');
152my %config_vars = (
153 'MKBUILDDEPS_TOOL' => '/usr/bin/apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends',
154 'MKBUILDDEPS_REMOVE_AFTER_INSTALL' => 'no',
155 'MKBUILDDEPS_ROOTCMD' => '',
156 );
157my %config_default = %config_vars;
158
159my $shell_cmd;
160# Set defaults
161foreach my $var (keys %config_vars) {
162 $shell_cmd .= qq[$var="$config_vars{$var}";\n];
163}
164$shell_cmd .= 'for file in ' . join(" ",@config_files) . "; do\n";
165$shell_cmd .= '[ -f $file ] && . $file; done;' . "\n";
166# Read back values
167foreach my $var (keys %config_vars) { $shell_cmd .= "echo \$$var;\n" }
168my $shell_out = `/bin/bash -c '$shell_cmd'`;
169@config_vars{keys %config_vars} = split /\n/, $shell_out, -1;
170
171# Check validity
172$config_vars{'MKBUILDDEPS_TOOL'} =~ /./
173 or $config_vars{'MKBUILDDEPS_TOOL'}=$config_default{'MKBUILDDEPS_TOOL'};
174$config_vars{'MKBUILDDEPS_REMOVE_AFTER_INSTALL'} =~ /^(yes|no)$/
175 or $config_vars{'MKBUILDDEPS_REMOVE_AFTER_INSTALL'}=$config_default{'MKBUILDDEPS_REMOVE_AFTER_INSTALL'};
176$config_vars{'MKBUILDDEPS_ROOTCMD'} =~ /./
177 or $config_vars{'MKBUILDDEPS_ROOTCMD'}=$config_default{'MKBUILDDEPS_ROOTCMD'};
178
179$install_tool = $config_vars{'MKBUILDDEPS_TOOL'};
180
181if ($config_vars{'MKBUILDDEPS_REMOVE_AFTER_INSTALL'} =~ /yes/) {
182 $opt_remove=1;
183}
184
185sub usage {
186 my ($exitval) = @_;
187
188 my $verbose = $exitval ? 0 : 1;
189 pod2usage({ -exitval => 'NOEXIT', -verbose => $verbose });
190
191 if ($verbose) {
192 my $modified_conf_msg;
193 foreach my $var (sort keys %config_vars) {
194 if ($config_vars{$var} ne $config_default{$var}) {
195 $modified_conf_msg .= " $var=$config_vars{$var}\n";
196 }
197 }
198 $modified_conf_msg ||= " (none)\n";
199 chomp $modified_conf_msg;
200 print <<EOF;
201Default settings modified by devscripts configuration files:
202$modified_conf_msg
203EOF
204 }
205
206 exit $exitval;
207}
208
209GetOptions("help|h" => \$opt_help,
210 "version|v" => \$opt_version,
211 "install|i" => \$opt_install,
212 "remove|r" => \$opt_remove,
213 "tool|t=s" => \$install_tool,
214 "arch|a=s" => \$opt_arch,
215 "host-arch=s" => \$opt_hostarch,
216 "build-arch=s" => \$opt_buildarch,
217 "build-dep|B" => \$opt_dep,
218 "build-indep|A" => \$opt_indep,
219 "root-cmd|s=s" => \$root_cmd,
220 )
221 or usage(1);
222
223usage(0) if ($opt_help);
224
225if ($opt_version) { version(); exit 0; }
226
227if (!@ARGV) {
228 if (-r 'debian/control') {
229 push(@ARGV, 'debian/control');
230 }
231}
232
233usage(1) unless @ARGV;
234
235system("command -v equivs-build >/dev/null 2>&1");
236if ($?) {
237 die "$progname: You must have equivs installed to use this program.\n";
238}
239
240while ($control = shift) {
241 my ($name, $fh, $descr, $pid);
242 if (-r $control and -f $control) {
243 open $fh, $control;
244 unless (defined $fh) {
245 warn "Unable to open $control: $!\n";
246 next;
247 }
248 $name = 'Source';
249 $descr = "control file `$control'";
250 }
251 else {
252 $fh = FileHandle->new();
253 $pid = spawn(exec => ['apt-cache', 'showsrc', $control],
254 from_file => '/dev/null',
255 to_pipe => $fh);
256 unless (defined $pid) {
257 warn "Unable to run apt-cache: $!\n";
258 next;
259 }
260 $name = 'Package';
261 $descr = "`apt-cache showsrc $control'";
262 }
263
264 my (@pkgInfo, @versions);
265 until (eof $fh) {
266 my $ctrl = Dpkg::Control->new(allow_pgp => 1, type => CTRL_UNKNOWN);
267 # parse() dies if the file isn't syntactically valid and returns undef
268 # if there simply weren't any fields parsed
269 unless ($ctrl->parse($fh, $descr)) {
270 warn "$progname: Unable to find package name in $descr\n";
271 next;
272 }
273 unless (exists $ctrl->{$name}) {
274 next;
275 }
276 my $args = '';
277 my $arch = 'all';
278 my ($build_deps, $build_dep, $build_indep);
279 my ($build_conflicts, $conflict_arch, $conflict_indep);
280
281 if (exists $ctrl->{'Build-Depends'}) {
282 $build_dep = $ctrl->{'Build-Depends'};
283 $build_dep =~ s/\n/ /g;
284 $build_deps = $build_dep;
285 }
286 if (exists $ctrl->{'Build-Depends-Indep'}) {
287 $build_indep = $ctrl->{'Build-Depends-Indep'};
288 $build_indep =~ s/\n/ /g;
289 $build_deps .= ', ' if $build_deps;
290 $build_deps .= $build_indep;
291 }
292 if (exists $ctrl->{'Build-Conflicts'}) {
293 $conflict_arch = $ctrl->{'Build-Conflicts'};
294 $conflict_arch =~ s/\n/ /g;
295 $build_conflicts = $conflict_arch;
296 }
297 if (exists $ctrl->{'Build-Conflicts-Indep'}) {
298 $conflict_indep = $ctrl->{'Build-Conflicts-Indep'};
299 $conflict_indep =~ s/\n/ /g;
300 $build_conflicts .= ', ' if $build_conflicts;
301 $build_conflicts .= $conflict_indep;
302 }
303
304 die "$progname: Unable to find build-deps for $ctrl->{$name}\n" unless $build_deps;
305
306 if (exists $ctrl->{Version}) {
307 push(@versions, $ctrl->{Version});
308 }
309 elsif ($name eq 'Source') {
310 (my $changelog = $control) =~ s@control$@changelog@;
311 if (-f $changelog) {
312 require Dpkg::Changelog::Parse;
313 my $log = Dpkg::Changelog::Parse::changelog_parse(file => $changelog);
314 if ($ctrl->{$name} eq $log->{$name}) {
315 $ctrl->{Version} = $log->{Version};
316 push(@versions, $log->{Version});
317 }
318 }
319 }
320
321 # Only build a package with both B-D and B-D-I in Depends if the
322 # B-D/B-D-I specific packages weren't requested
323 if (!($opt_dep || $opt_indep)) {
324 push(@pkgInfo,
325 { depends => $build_deps,
326 conflicts => $build_conflicts,
327 name => $ctrl->{$name},
328 type => 'build-deps',
329 version => $ctrl->{Version} });
330 next;
331 }
332 if ($opt_dep) {
333 push(@pkgInfo,
334 { depends => $build_dep,
335 conflicts => $conflict_arch,
336 name => $ctrl->{$name},
337 type => 'build-deps-depends',
338 version => $ctrl->{Version} });
339 }
340 if ($opt_indep) {
341 push(@pkgInfo,
342 { depends => $build_indep,
343 conflicts => $conflict_indep,
344 name => $ctrl->{$name},
345 type => 'build-deps-indep',
346 version => $ctrl->{Version} });
347 }
348 }
349 wait_child($pid, nocheck => 1) if defined $pid;
350 # Only use the newest version. We'll only have this if processing showsrc
351 # output or a dsc file.
352 if (@versions) {
353 @versions = map { $_->[0] }
354 sort { $b->[1] <=> $a->[1] }
355 map { [$_, Dpkg::Version->new($_)] } @versions;
356 push(@packages, map { build_equiv($_) }
357 grep { $versions[0] eq $_->{version} } @pkgInfo);
358 }
359 elsif (@pkgInfo) {
360 push(@packages, build_equiv($pkgInfo[0]));
361 }
362 else {
363 die "$progname: Unable to find package name in $descr\n";
364 }
365}
366
367if ($opt_install) {
368 my @root;
369 if ($root_cmd) {
370 push(@root, shellwords($root_cmd));
371 }
372
373 my (@pkg_names, @deb_files, %uniq);
374 for my $package (@packages) {
375 if ($uniq{$package->{deb_file}}++ == 0) {
376 push @pkg_names, $package->{package};
377 push @deb_files, $package->{deb_file};
378 }
379 }
380
381 system @root, 'dpkg', '--unpack', @deb_files;
382 die("$progname: dpkg --unpack failed\n") if ( ($?>>8) != 0 );
383 system @root, shellwords($install_tool), '-f', 'install';
384 my $err = $? >> 8;
385 if (!$err) {
386 # $install_tool succeeded. Did the packages get installed? It's
387 # possible that they didn't because $install_tool may have realized
388 # that installation was impossible, and it could have given up,
389 # successfully.
390 for (my $i = 0; $i < @pkg_names; $i++) {
391 my $pkg = $pkg_names[$i];
392 my $status;
393 spawn(exec => ['dpkg-query', '-W', '-f', '${db:Status-Status}', $pkg],
394 to_string => \$status,
395 error_to_file => '/dev/null',
396 nocheck => 1,
397 wait_child => 1);
398 if ($status ne 'installed' || ($? >> 8)) {
399 # Restore system to previous state, since $install_tool wasn't
400 # able to resolve a proper way to get the build-dep packages
401 # installed
402 warn "$progname: Unable to install $pkg";
403 $err = 1;
404 }
405 elsif ($opt_remove) {
406 unlink $deb_files[$i];
407 }
408 }
409 if ($err) {
410 die "$progname: Unable to install all build-dep packages\n";
411 }
412 }
413 else {
414 # Restore system to previous state, since $install_tool wasn't able to
415 # resolve a proper way to get the build-dep packages installed
416 system @root, 'dpkg', '--remove', @pkg_names;
417 die("$progname: Unable to install all build-dep packages\n");
418 }
419}
420
421sub version {
422 print <<"EOF";
423This is $progname, from the Debian devscripts package, version 2.17.6+deb9u2
424Copyright (C) 2008 Vincent Fourmond
425
426This program comes with ABSOLUTELY NO WARRANTY.
427You are free to redistribute this code under the terms of the
428GNU General Public License, version 2, or (at your option) any
429later version.
430EOF
431}
432
433sub build_equiv
434{
435 my ($opts) = @_;
436 my $args = '';
437
438 my $packagearch = 'all';
439
440 if (defined $opt_arch) {
441 $packagearch = $opt_arch;
442 } elsif (defined $opt_hostarch) {
443 $packagearch = $opt_hostarch;
444 } elsif ($opts->{depends} =~ m/\[|\]/) {
445 chomp($packagearch = `dpkg-architecture -qDEB_HOST_ARCH`);
446 }
447 if ($packagearch ne "all") {
448 $args .= "--arch=$packagearch ";
449 }
450
451 chomp(my $buildarch = `dpkg-architecture -qDEB_BUILD_ARCH`);
452 if (defined $opt_buildarch) {
453 $buildarch = $opt_buildarch;
454 }
455
456 chomp(my $hostarch = `dpkg-architecture -qDEB_HOST_ARCH`);
457 if (defined $opt_hostarch) {
458 $hostarch = $opt_hostarch;
459 }
460
461 if ($packagearch eq "all") {
462 if ($buildarch ne $hostarch) {
463 die "build architecture \"$buildarch\" is unequal host architecture \"$hostarch\" in which case the package architecture must not be \"all\" (but \"$hostarch\" instead)\n";
464 }
465 } elsif ($packagearch ne $hostarch) {
466 die "The package architecture must be equal to the host architecture except if the package architecture is \"all\"\n";
467 }
468
469 my $build_profiles = [ split /\s+/, ($ENV{'DEB_BUILD_PROFILES'} // "") ];
470
471 my $positive = deps_parse($opts->{depends} // "",
472 reduce_arch => 1,
473 host_arch => $hostarch,
474 build_arch => $buildarch,
475 build_dep => 1,
476 reduce_profiles => 1,
477 build_profiles => $build_profiles);
478 my $negative = deps_parse($opts->{conflicts} // "",
479 reduce_arch => 1,
480 host_arch => $hostarch,
481 build_arch => $buildarch,
482 build_dep => 1,
483 union => 1,
484 reduce_profiles => 1,
485 build_profiles => $build_profiles);
486
487 # either remove :native for native builds or replace it by the build
488 # architecture
489 my $handle_native_archqual = sub {
490 my ($dep) = @_;
491 if ($dep->{archqual} && $dep->{archqual} eq "native") {
492 if ($hostarch eq $buildarch) {
493 $dep->{archqual} = undef;
494 } else {
495 $dep->{archqual} = $buildarch;
496 }
497 }
498 return 1;
499 };
500 deps_iterate($positive, $handle_native_archqual);
501 deps_iterate($negative, $handle_native_archqual);
502
503 my $pkgname;
504 my $buildess = "build-essential:$buildarch";
505 if ($buildarch eq $hostarch) {
506 $pkgname = "$opts->{name}-$opts->{type}";
507 } else {
508 $pkgname = "$opts->{name}-cross-$opts->{type}";
509 $buildess .= ", crossbuild-essential-$hostarch:$buildarch";
510 }
511
512 my $readme = '/usr/share/devscripts/README.mk-build-deps';
513 open EQUIVS, "| equivs-build $args-"
514 or die "$progname: Failed to execute equivs-build: $!\n";
515 print EQUIVS "Section: devel\n" .
516 "Priority: optional\n".
517 "Standards-Version: 3.7.3\n\n".
518 "Package: $pkgname\n".
519 "Architecture: $packagearch\n".
520 "Depends: $buildess, $positive\n";
521
522 print EQUIVS "Conflicts: $negative\n" if $negative;
523
524 # Allow the file not to exist to ease testing
525 print EQUIVS "Readme: $readme\n" if -r $readme;
526
527 my $version = $opts->{version} || '1.0';
528 print EQUIVS "Version: $version\n";
529
530 print EQUIVS "Description: build-dependencies for $opts->{name}\n" .
531 " Dependency package to build the '$opts->{name}' package\n";
532
533 close EQUIVS;
534
535 my $v = Dpkg::Version->new($version);
536 # The version in the .deb filename will not contain the epoch
537 $version = $v->as_string(omit_epoch => 1);
538 my $deb_file = "${pkgname}_${version}_${packagearch}.deb";
539 return {
540 package => $pkgname,
541 deb_file => $deb_file
542 };
543}