=head1 DESCRIPTION
B<dh> runs a sequence of debhelper commands. The supported I<sequence>s
-correspond to the targets of a F<debian/rules> file: B<build>, B<clean>,
+correspond to the targets of a F<debian/rules> file: B<build-arch>,
+B<build-indep>, B<build>, B<clean>, B<install-indep>, B<install-arch>,
B<install>, B<binary-arch>, B<binary-indep>, and B<binary>.
-Commands in the B<binary-indep> sequence are passed the B<-i> option to ensure
-they only work on binary independent packages, and commands in the
-B<binary-arch> sequences are passed the B<-a> option to ensure they only work
-on architecture dependent packages.
+Commands in the B<build-indep>, B<install-indep> and B<binary-indep>
+sequences are passed the B<-i> option to ensure they only work on
+architecture independent packages, and commands in the B<build-arch>,
+B<install-arch> and B<binary-arch> sequences are passed the B<-a>
+option to ensure they only work on architecture dependent packages.
If F<debian/rules> contains a target with a name like B<override_>I<dh_command>,
then when it would normally run I<dh_command>, B<dh> will instead call that
=item B<--until> I<cmd>
Run commands in the sequence until and including I<cmd>, then stop.
+(Deprecated)
=item B<--before> I<cmd>
Run commands in the sequence before I<cmd>, then stop.
+(Deprecated)
=item B<--after> I<cmd>
Run commands in the sequence that come after I<cmd>.
+(Deprecated)
=item B<--remaining>
Run all commands in the sequence that have yet to be run.
+(Deprecated)
=item B<--no-act>
dh_fixperms
chmod 4755 debian/foo/usr/bin/foo
-If your package is a Python package, B<dh> will use B<dh_pysupport> by
-default. This is how to use B<dh_pycentral> instead.
+Python tools are not run by dh by default, due to the continual change
+in that area. (Before compatability level v9, dh does run B<dh_pysupport>.)
+Here is how to use B<dh_python2>.
#!/usr/bin/make -f
%:
- dh $@ --with python-central
+ dh $@ --with python2
If your package uses autotools and you want to freshen F<config.sub> and
F<config.guess> with newer versions from the B<autotools-dev> package
override_dh_fixperms:
dh_fixperms
- ifneq (,$(findstring foo, $(shell dh_listpackages)))
+ ifneq (,$(filter foo, $(shell dh_listpackages)))
chmod 4755 debian/foo/usr/bin/foo
endif
Finally, remember that you are not limited to using override targets in the
rules file when using B<dh>. You can also explicitly define any of the regular
rules file targets when it makes sense to do so. A common reason to do this
-is if your package needs different B<build-arch> and B<build-indep> targets. For
-example, a package with a long document build process can put it in
-B<build-indep> to avoid build daemons redundantly building the documentation.
+is when your package needs different B<build-arch> and B<build-indep> targets.
+For example, a package with a long document build process can put it in
+B<build-indep>.
#!/usr/bin/make -f
%:
dh $@
- build: build-arch build-indep ;
build-indep:
$(MAKE) docs
build-arch:
$(MAKE) bins
+Note that in the example above, dh will arrange for "debian/rules build"
+to call your build-indep and build-arch targets. You do not need to
+explicitly define those dependencies in the rules file when using dh with
+compatibility level v9. This example would be more complicated with
+earlier compatibility levels.
+
=head1 INTERNALS
If you're curious about B<dh>'s internals, here's how it works under the hood.
in the sequence. The B<--until>, B<--before>, B<--after>, and B<--remaining>
options can override this behavior.
+A sequence can also run dependent targets in debian/rules. For
+example, the "binary" sequence runs the "install" target.
+
+B<dh> sets environment variables listed by B<dpkg-buildflags>, unless
+they are already set. It supports DEB_BUILD_OPTIONS=noopt too.
+
B<dh> uses the B<DH_INTERNAL_OPTIONS> environment variable to pass information
through to debhelper commands that are run inside override targets. The
contents (and indeed, existence) of this environment variable, as the name
# Stash this away before init modifies it.
my @ARGV_orig=@ARGV;
-# python-support is enabled by default, at least for now
-# (and comes first so python-central loads later and can disable it).
-unshift @ARGV, "--with=python-support";
+if (compat(8)) {
+ # python-support was enabled by default before v9.
+ # (and comes first so python-central loads later and can disable it).
+ unshift @ARGV, "--with=python-support";
+}
init(options => {
"until=s" => \$dh{UNTIL},
bundling => 0,
);
inhibit_log();
-
+set_buildflags();
+warn_deprecated();
# If make is using a jobserver, but it is not available
# to this process, clean out MAKEFLAGS. This avoids
clean_jobserver_makeflags();
}
+# Process the sequence parameter.
+my $sequence;
+if (! compat(7)) {
+ # From v8, the sequence is the very first parameter.
+ $sequence=shift @ARGV_orig;
+ if (defined $sequence && $sequence=~/^-/) {
+ error "Unknown sequence $sequence (options should not come before the sequence)";
+ }
+}
+else {
+ # Before v8, the sequence could be at any position in the parameters,
+ # so was what was left after parsing.
+ $sequence=shift;
+ if (defined $sequence) {
+ @ARGV_orig=grep { $_ ne $sequence } @ARGV_orig;
+ }
+}
+if (! defined $sequence) {
+ error "specify a sequence to run";
+}
+# make -B causes the rules file to be run as a target.
+# Also support completly empty override targets.
+# Note: it's not safe to use rules_explicit_target before this check,
+# since it causes dh to be run.
+my $dummy_target="debhelper-fail-me";
+if ($sequence eq 'debian/rules' ||
+ $sequence =~ /^override_dh_/ ||
+ $sequence eq $dummy_target) {
+ exit 0;
+}
+
+
# Definitions of sequences.
my %sequences;
-$sequences{build} = [qw{
+my @bd_minimal = qw{
+ dh_testdir
+};
+my @bd = qw{
dh_testdir
dh_auto_configure
dh_auto_build
dh_auto_test
-}],
-$sequences{clean} = [qw{
- dh_testdir
- dh_auto_clean
- dh_clean
-}];
-$sequences{install} = [@{$sequences{build}}, qw{
+};
+my @i = qw{
dh_testroot
dh_prep
dh_installdirs
dh_installudev
dh_installwm
dh_installxfonts
+ dh_installgsettings
dh_bugfiles
+ dh_ucf
dh_lintian
dh_gconf
dh_icons
dh_link
dh_compress
dh_fixperms
-}];
+};
+my @ba=qw{
+ dh_strip
+ dh_makeshlibs
+ dh_shlibdeps
+};
my @b=qw{
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
};
-$sequences{'binary-indep'} = [@{$sequences{install}}, @b];
-$sequences{binary} = [@{$sequences{install}}, qw{
- dh_strip
- dh_makeshlibs
- dh_shlibdeps
-}, @b];
-$sequences{'binary-arch'} = [@{$sequences{binary}}];
+$sequences{clean} = [qw{
+ dh_testdir
+ dh_auto_clean
+ dh_clean
+}];
+$sequences{'build-indep'} = [@bd];
+$sequences{'build-arch'} = [@bd];
+if (! compat(8)) {
+ # From v9, sequences take standard rules targets into account.
+ $sequences{build} = [@bd_minimal, rules("build-arch"), rules("build-indep")];
+ $sequences{'install-indep'} = [rules("build-indep"), @i];
+ $sequences{'install-arch'} = [rules("build-arch"), @i];
+ $sequences{'install'} = [rules("build"), rules("install-arch"), rules("install-indep"), @i];
+ $sequences{'binary-indep'} = [rules("install-indep"), @b];
+ $sequences{'binary-arch'} = [rules("install-arch"), @ba, @b];
+ $sequences{binary} = [rules("install"), rules("binary-arch"), rules("binary-indep")];
+}
+else {
+ $sequences{build} = [@bd];
+ $sequences{'install'} = [@{$sequences{build}}, @i];
+ $sequences{'install-indep'} = [@{$sequences{'build-indep'}}, @i];
+ $sequences{'install-arch'} = [@{$sequences{'build-arch'}}, @i];
+ $sequences{binary} = [@{$sequences{install}}, @ba, @b];
+ $sequences{'binary-indep'} = [@{$sequences{'install-indep'}}, @b];
+ $sequences{'binary-arch'} = [@{$sequences{'install-arch'}}, @ba, @b];
+}
# Additional command options
my %command_opts;
exit 0;
}
+# Load addons, which can modify sequences.
foreach my $addon (@{$dh{WITH}}) {
my $mod="Debian::Debhelper::Sequence::$addon";
$mod=~s/-/_/g;
}
}
-my $sequence;
-if (! compat(7)) {
- # From v8, the sequence is the very first parameter.
- $sequence=shift @ARGV_orig;
- if ($sequence=~/^-/) {
- error "Unknown sequence $sequence (options should not come before the sequence)";
- }
-}
-else {
- # Before v8, the sequence could be at any position in the parameters,
- # so was what was left after parsing.
- $sequence=shift;
- if (defined $sequence) {
- @ARGV_orig=grep { $_ ne $sequence } @ARGV_orig;
- }
-}
-if (! defined $sequence) {
- error "specify a sequence to run";
-}
-if ($sequence eq 'debian/rules' ||
- $sequence =~ /^override_dh_/) {
- # make -B causes the rules file to be run as a target.
- # Also support completly empty override targets.
- exit 0;
-}
-elsif (! exists $sequences{$sequence}) {
+if (! exists $sequences{$sequence}) {
error "Unknown sequence $sequence (choose from: ".
join(" ", sort keys %sequences).")";
}
-my @sequence=@{$sequences{$sequence}};
+my @sequence=optimize_sequence(@{$sequences{$sequence}});
# The list of all packages that can be acted on.
my @packages=@{$dh{DOPACKAGES}};
# Get the options to pass to commands in the sequence.
# Filter out options intended only for this program.
my @options;
-if ($sequence eq 'binary-arch') {
+if ($sequence eq 'build-arch' ||
+ $sequence eq 'install-arch' ||
+ $sequence eq 'binary-arch') {
push @options, "-a";
# as an optimisation, remove from the list any packages
# that are not arch dependent
my %arch_packages = map { $_ => 1 } getpackages("arch");
@packages = grep { $arch_packages{$_} } @packages;
}
-elsif ($sequence eq 'binary-indep') {
+elsif ($sequence eq 'build-indep' ||
+ $sequence eq 'install-indep' ||
+ $sequence eq 'binary-indep') {
push @options, "-i";
# ditto optimisation for arch indep
my %indep_packages = map { $_ => 1 } getpackages("indep");
# run them instead of running the command directly.
my $override_command;
my $has_explicit_target = rules_explicit_target("override_".$command);
- if (defined $has_explicit_target) {
+
+ my $rules_target = rules_target($command);
+ if (defined $rules_target) {
+ # Don't pass DH_ environment variables, since this is
+ # a fresh invocation of debian/rules and any sub-dh
+ # commands.
+ $override_command=$command;
+ delete $ENV{DH_INTERNAL_OPTIONS};
+ delete $ENV{DH_INTERNAL_OVERRIDE};
+ $command="debian/rules";
+ @options=$rules_target;
+ }
+ elsif (defined $has_explicit_target) {
$override_command=$command;
# Check if target isn't noop
if ($has_explicit_target) {
# This passes the options through to commands called
# inside the target.
$ENV{DH_INTERNAL_OPTIONS}=join("\x1e", @options);
- # Prevent commands called inside the target from
- # logging.
- $ENV{DH_INHIBIT_LOG}=$command;
+ $ENV{DH_INTERNAL_OVERRIDE}=$command;
$command="debian/rules";
@options="override_".$override_command;
}
else {
print " ", "# Skipping ", $override_command, " - empty override", "\n";
}
-
+
if (! $dh{NO_ACT}) {
if (defined $command) {
my $ret=system($command, @options);
+
if ($ret >> 8 != 0) {
exit $ret >> 8;
}
}
if (defined $override_command) {
- delete $ENV{DH_INTERNAL_OPTIONS};
- delete $ENV{DH_INHIBIT_LOG};
# Update log for overridden command now that it has
# finished successfully.
# (But avoid logging for dh_clean since it removes
my %packages=map { $_ => 1 } @packages;
map { delete $packages{$_} } @exclude;
write_log($override_command, keys %packages);
+ commit_override_log(keys %packages);
}
+
+ delete $ENV{DH_INTERNAL_OPTIONS};
+ delete $ENV{DH_INTERNAL_OVERRIDE};
+ }
+ }
+}
+
+sub optimize_sequence {
+ my @sequence;
+ my %seen;
+ my $add=sub {
+ # commands can appear multiple times when sequences are
+ # inlined together; only the first should be needed
+ my $command=shift;
+ if (! $seen{$command}) {
+ $seen{$command}=1;
+ push @sequence, $command;
+ }
+ };
+ foreach my $command (@_) {
+ my $rules_target=rules_target($command);
+ if (defined $rules_target &&
+ ! defined rules_explicit_target($rules_target)) {
+ # inline the sequence for this implicit target
+ $add->($_) foreach optimize_sequence(@{$sequences{$rules_target}});
+ }
+ else {
+ $add->($command);
}
}
+ return @sequence;
+}
+
+sub rules_target {
+ my $command=shift;
+ if ($command =~ /^debian\/rules\s+(.*)/) {
+ return $1
+ }
+ else {
+ return undef;
+ }
+}
+
+sub rules {
+ return "debian/rules ".join(" ", @_);
}
{
my $processing_targets = 0;
my $not_a_target = 0;
my $current_target;
- open(MAKE, "LC_ALL=C make -Rrnpsf debian/rules debhelper-fail-me 2>/dev/null |");
+ open(MAKE, "LC_ALL=C make -Rrnpsf debian/rules $dummy_target 2>/dev/null |");
while (<MAKE>) {
if ($processing_targets) {
if (/^# Not a target:/) {
if (defined $current_target) {
if (/^#/) {
# Check if target has commands to execute
- if (/^#\s*commands to execute/) {
+ if (/^#\s*(commands|recipe) to execute/) {
$targets{$current_target} = 1;
}
}
}
+sub warn_deprecated {
+ foreach my $deprecated ('until', 'after', 'before', 'remaining') {
+ if (defined $dh{uc $deprecated}) {
+ warning("The --$deprecated option is deprecated. Use override targets instead.");
+ }
+ }
+}
+
=head1 SEE ALSO
L<debhelper(7)>