=head1 SYNOPSIS
-B<dh> sequence [B<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining>] [B<--with> I<addon>] [S<I<debhelper options>>]
+B<dh> sequence [B<--with> I<addon>[,I<addon>,...]] [B<--list>] [B<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining>] [S<I<debhelper options>>]
=head1 DESCRIPTION
in the sequence. The B<--until>, B<--before>, B<--after>, and B<--remaining>
options can override this behavior.
+If debian/rules contains a target with a name like "override_I<dh_command>",
+then when it would normally run I<dh_command>, dh will instead call that
+target. The override target can then run the command with additional options,
+or run entirely different commands instead. See examples below. (Note that to
+use this feature, you should Build-Depend on debhelper 7.0.50 or above.)
+
=head1 OPTIONS
=over 4
+=item B<--with> I<addon>[,I<addon>,...]
+
+Add the debhelper commands specified by the given addon to appropriate places
+in the sequence of commands that is run. This option can be repeated more
+than once, or multiple addons can be listed, separated by commas.
+This is used when there is a third-party package that provides
+debhelper commands. See the PROGRAMMING file for documentation about
+the sequence addon interface.
+
+=item B<--without> I<addon>
+
+The inverse of --with, disables using the given addon.
+
+=item B<--list>, B<-l>
+
+List all available addons.
+
=item B<--until> I<cmd>
Run commands in the sequence until and including I<cmd>, then stop.
Run all commands in the sequence that have yet to be run.
-=item B<--with> I<addon>
+=item B<--no-act>
-Add the debhelper commands specified by the given addon to appropriate places
-in the sequence of commands that is run. This option can be repeated more
-than once, and is used when there is a third-party package that provides
-debhelper commands. See "SEQUENCE ADDONS" below for documentation about what
-such packages should do to be supported by --with.
+Prints commands that would run for a given sequence, but does not run them.
=back
can be used to set an option like "-v" or "-X" or "-N", as well as for more
specialised options.
-=head1 COMMAND SPECIFICATION
-
-I<cmd> can be a full name of a debhelper command, or a substring. It'll first
-search for a command in the sequence exactly matching the name, to avoid any
-ambiguity. If there are multiple substring matches, the last one in the
-sequence will be used.
-
-=head1 SEQUENCE ADDONS
-
-When B<--with> I<addon> is used, dh loads the perl module
-Debian::Debhelper::Sequence::I<addon>. Two functions are provided to let
-the module add its commands to sequences:
-
-=over 4
-
-=item Debian::Debhelper::Dh_Lib::insert_before(existing_command, new_command)
-
-Insert I<new_command> in sequences before I<existing_command>.
-
-=item Debian::Debhelper::Dh_Lib::insert_after(existing_command, new_command)
-
-Insert I<new_command> in sequences after I<existing_command>.
-
-=item Debian::Debhelper::Dh_Lib::remove_command(existing_command)
-
-Remove I<existing_command> from the list of commands to run.
-
-=back
+In the above options, I<cmd> can be a full name of a debhelper command, or
+a substring. It'll first search for a command in the sequence exactly
+matching the name, to avoid any ambiguity. If there are multiple substring
+matches, the last one in the sequence will be used.
=cut
%:
dh $@
-This is a simple rules file that is a good starting place for customisation.
-(It's also available in F</usr/share/doc/debhelper/examples/rules.simple>
+Often you'll want to pass an option to a specific debhelper command. The
+easy way to do with is by adding an override target for that command.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@
+
+ override_dh_strip:
+ dh_strip -Xfoo
+
+ override_dh_installdocs:
+ dh_installdocs README TODO
+
+Sometimes the automated dh_auto_configure and dh_auto_build can't guess
+what to do for a strange package. Here's how to avoid running either
+and instead run your own commands.
#!/usr/bin/make -f
+ %:
+ dh $@
- build: build-stamp
- build-stamp:
- dh build
- touch build-stamp
+ override_dh_auto_configure:
+ ./mondoconfig
- clean:
- dh clean
+ override_dh_auto_build:
+ make universe-explode-in-delight
- install: build install-stamp
- install-stamp:
- dh install
- touch install-stamp
+Another common case is wanting to do something manually before or
+after a particular debhelper command is run.
- binary-arch: install
- dh binary-arch
+ #!/usr/bin/make -f
+ %:
+ dh $@
- binary-indep: install
- dh binary-indep
+ override_dh_fixperms:
+ dh_fixperms
+ chmod 4755 debian/foo/usr/bin/foo
- binary: binary-arch binary-indep
+If your package is a python package, dh will use dh_pysupport by
+default. This is how to use dh_pycentral instead.
-Often you'll want to pass an option to ./configure. This uses dh to run all
-commands before L<dh_auto_configure(1)>, then runs that command by hand,
-and then finishes up by running the rest of the sequence. You could also
-run ./configure by hand, instead of bothering with using dh_auto_configure.
-And if necessary, you can add commands to run automake, etc here too.
+ #!/usr/bin/make -f
+ %:
+ dh $@ --with python-central
- build: build-stamp
- build-stamp:
- dh build --before configure
- dh_auto_configure -- --kitchen-sink=yes
- dh build --after configure
- touch build-stamp
+Here is how to force use of perl's Module::Build build system,
+which can be necessary if debhelper wrongly detects that the package
+uses MakeMaker.
-Here's how to skip two automated steps in a row (configure and build), and
-instead run the commands by hand.
+ #!/usr/bin/make -f
+ %:
+ dh $@ --buildsystem=perl_build
- build: build-stamp
- build-stamp:
- dh build --before configure
- ./mondoconfig
- make universe-explode-in-delight
- dh build --after build
- touch build-stamp
+To patch your package using quilt, you can tell dh to use quilt's dh
+sequence addons like this:
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --with quilt
-Another common case is wanting to run some code manually after a particular
-debhelper command is run.
+Here is an example of overriding where the dh_auto_* commands find
+the package's source, for a package where the source is located in a
+subdirectory.
- install: build install-stamp
- install-stamp:
- dh install --until dh_fixperms
- # dh_fixperms has run, now override it for one program
- chmod 4755 debian/foo/usr/bin/foo
- # and continue
- dh install --after dh_fixperms
- touch install-stamp
-
-It's also fine to run debhelper commands early. Just make sure that at
-least dh_prep is run from the sequence first, and be sure to use the
-B<--remaining> option to ensure that commands that normally come before
-those in the sequence are still run.
-
- install: build install-stamp
- install-stamp:
- dh install --until dh_prep
- dh_installdocs README TODO
- dh_installchangelogs Changes
- dh install --remaining
- touch install-stamp
+ #!/usr/bin/make -f
+ %:
+ dh $@ --sourcedirectory=src
+
+And here is an example of how to tell the dh_auto_* commands to build
+in a subdirectory, which will be removed on clean.
- binary-arch: install
- dh_strip -X foo
- dh binary-arch --remaining
+ #!/usr/bin/make -f
+ %:
+ dh $@ --builddirectory=build
+
+Finally, here is a way to prevent dh from running several commands
+that you don't want it to run, by defining empty override targets for each
+command.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@
+
+ # Commands not to run:
+ override_dh_auto_test override_dh_compress override_dh_fixperms:
=cut
# 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";
+
init(options => {
- "until=s" => \$dh{UNTIL},
- "after=s" => \$dh{AFTER},
- "before=s" => \$dh{BEFORE},
- "remaining" => \$dh{REMAINING},
- "with=s" => sub {
- my ($option,$value)=@_;
- push @{$dh{WITH}},$value;
+ "until=s" => \$dh{UNTIL},
+ "after=s" => \$dh{AFTER},
+ "before=s" => \$dh{BEFORE},
+ "remaining" => \$dh{REMAINING},
+ "with=s" => sub {
+ my ($option,$value)=@_;
+ push @{$dh{WITH}},split(",", $value);
+ },
+ "without=s" => sub {
+ my ($option,$value)=@_;
+ @{$dh{WITH}} = grep { $_ ne $value } @{$dh{WITH}};
+ },
+ "l" => \$dh{LIST},
+ "list" => \$dh{LIST},
},
-});
+ # Disable complaints about unknown options; they are passed on the
+ # debhelper commands.
+ ignore_unknown_options => 1,
+);
inhibit_log();
+
+# If make is using a jobserver, but it is not available
+# to this process, clean out MAKEFLAGS. This avoids
+# ugly warnings when calling make.
+if (is_make_jobserver_unavailable()) {
+ clean_jobserver_makeflags();
+}
+
# Definitions of sequences.
my %sequences;
$sequences{build} = [qw{
dh_installcatalogs
dh_installcron
dh_installdebconf
- dh_installcatalogs
dh_installemacsen
dh_installifupdown
dh_installinfo
dh_installudev
dh_installwm
dh_installxfonts
+ dh_bugfiles
dh_lintian
- dh_desktop
dh_gconf
dh_icons
dh_perl
- dh_scrollkeeper
dh_usrlocal
dh_link
}, @b];
$sequences{'binary-arch'} = [@{$sequences{binary}}];
-# --with python-support is enabled by default, at least for now
-unshift @{$dh{WITH}}, "python-support";
+# Additional command options
+my %command_opts;
# sequence addon interface
sub _insert {
}
}
+sub add_command {
+ my $command=shift;
+ my $sequence=shift;
+ unshift @{$sequences{$sequence}}, $command;
+}
+sub add_command_options {
+ my $command=shift;
+ push @{$command_opts{$command}}, @_;
+}
+sub remove_command_options {
+ my $command=shift;
+ if (@_) {
+ # Remove only specified options
+ if (my $opts = $command_opts{$command}) {
+ foreach my $opt (@_) {
+ $opts = [ grep { $_ ne $opt } @$opts ];
+ }
+ $command_opts{$command} = $opts;
+ }
+ }
+ else {
+ # Clear all additional options
+ delete $command_opts{$command};
+ }
+}
+
+if ($dh{LIST}) {
+ my %addons;
+
+ for my $inc (@INC) {
+ eval q{use File::Spec};
+ my $path = File::Spec->catdir($inc, "Debian/Debhelper/Sequence");
+ if (-d $path) {
+ for my $module_path (glob "$path/*.pm") {
+ my $name = basename($module_path);
+ $name =~ s/\.pm$//;
+ $name =~ s/_/-/g;
+ $addons{$name} = 1;
+ }
+ }
+ }
+
+ for my $name (sort keys %addons) {
+ print "$name\n";
+ }
+
+ exit 0;
+}
+
foreach my $addon (@{$dh{WITH}}) {
my $mod="Debian::Debhelper::Sequence::$addon";
$mod=~s/-/_/g;
eval "use $mod";
if ($@) {
- error("--with $addon not supported or failed to load module $mod");
+ error("unable to load addon $addon: $@");
}
}
error "specify a sequence to run";
}
my $sequence=shift;
-if (! exists $sequences{$sequence}) {
+if ($sequence eq 'debian/rules' ||
+ $sequence =~ /^override_dh_/) {
+ # make -B causes the rules file to be run as a target
+ # and support completly empty override targets
+ exit 0
+}
+elsif (! exists $sequences{$sequence}) {
error "Unknown sequence $sequence (choose from: ".
join(" ", sort keys %sequences).")";
}
while (@ARGV_orig) {
my $opt=shift @ARGV_orig;
next if $opt eq $sequence;
- if ($opt =~ /^--?(after|until|before|with)$/) {
+ if ($opt =~ /^--?(after|until|before|with|without)$/) {
shift @ARGV_orig;
next;
}
- elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with)=)/) {
+ elsif ($opt =~ /^--?(no-act|remaining|(after|until|before|with|without)=)/) {
next;
}
- push @options, $opt;
+ elsif ($opt=~/^-/) {
+ push @options, "-O".$opt;
+ }
+ elsif (@options) {
+ if ($options[$#options]=~/^-O--/) {
+ $options[$#options].="=".$opt;
+ }
+ else {
+ $options[$#options].=$opt;
+ }
+ }
}
# Figure out at what point in the sequence to start for each package.
my %logged;
my %startpoint;
foreach my $package (@packages) {
- my @log=loadlog($package);
+ my @log=load_log($package, \%logged);
if ($dh{AFTER}) {
# Run commands in the sequence that come after the
# specified command.
# no commands remain to run after it, communicating to
# future dh instances that the specified command should not
# be run again.
- writelog($package, $sequence[$startpoint{$package}-1]);
+ write_log($sequence[$startpoint{$package}-1], $package);
}
elsif ($dh{REMAINING}) {
# Start at the beginning so all remaining commands will get
# Command already done for all packages.
next;
}
- elsif (! @exclude) {
- # Run command for all packages.
- run($sequence[$i], @options);
- }
- else {
- # Run command for only a subset of packages.
- run($sequence[$i], @options,
- map { "-N$_" } @exclude);
- }
+
+ run($sequence[$i], \@packages, \@exclude, @options);
}
sub run {
my $command=shift;
+ my @packages=@{shift()};
+ my @exclude=@{shift()};
my @options=@_;
- # 3 space indent lines the command being run up under the
- # sequence name after "dh ".
- print " ".escape_shell($command, @options)."\n";
+ # If some packages are excluded, add flags
+ # to prevent them from being acted on.
+ push @options, map { "-N$_" } @exclude;
+
+ # Check for override targets in debian/rules and
+ # 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) {
+ $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);
+ $command="debian/rules";
+ @options="override_".$override_command;
+ }
+ else {
+ $command = undef;
+ }
+ }
+ else {
+ # Pass additional command options if any
+ unshift @options, @{$command_opts{$command}} if exists $command_opts{$command};
+ }
+
+ if (defined $command) {
+ # 3 space indent lines the command being run up under the
+ # sequence name after "dh ".
+ print " ".escape_shell($command, @options)."\n";
+ }
+ else {
+ print " ", "# Skipping ", $override_command, " - empty override", "\n";
+ }
if (! $dh{NO_ACT}) {
- my $ret=system($command, @options);
- if ($ret >> 8 != 0) {
- exit $ret >> 8;
+ if (defined $command) {
+ my $ret=system($command, @options);
+ if ($ret >> 8 != 0) {
+ exit $ret >> 8;
+ }
+ elsif ($ret) {
+ exit 1;
+ }
}
- elsif ($ret) {
- exit 1;
+
+ if (defined $override_command) {
+ delete $ENV{DH_INTERNAL_OPTIONS};
+ # Need to handle logging for overriden commands here,
+ # because the actual debhelper command may not have
+ # been run by the rules file target.
+ # (But avoid logging for dh_clean since it removes
+ # the log earlier.)
+ if ($override_command ne 'dh_clean') {
+ my %packages=map { $_ => 1 } @packages;
+ map { delete $packages{$_} } @exclude;
+ write_log($override_command, keys %packages);
+ }
}
}
}
-sub loadlog {
- my $package=shift;
- my $ext=pkgext($package);
-
- my @log;
- open(LOG, "<", "debian/${ext}debhelper.log") || return;
- while (<LOG>) {
- chomp;
- push @log, $_;
- $logged{$package}{$_}=1;
+{
+my %targets;
+my $rules_parsed;
+
+sub rules_explicit_target {
+ # Checks if a specified target exists as an explicit target
+ # in debian/rules.
+ # undef is returned if target does not exist, 0 if target is noop
+ # and 1 if target has dependencies or executes commands.
+ my $target=shift;
+
+ if (! $rules_parsed) {
+ 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 |");
+ while (<MAKE>) {
+ if ($processing_targets) {
+ if (/^# Not a target:/) {
+ $not_a_target = 1;
+ }
+ else {
+ if (!$not_a_target && /^([^#:]+)::?\s*(.*)$/) {
+ # Target is defined. NOTE: if it is a depenency of
+ # .PHONY it will be defined too but that's ok.
+ # $2 contains target dependencies if any.
+ $current_target = $1;
+ $targets{$current_target} = ($2) ? 1 : 0;
+ }
+ else {
+ if (defined $current_target) {
+ if (/^#/) {
+ # Check if target has commands to execute
+ if (/^#\s*commands to execute/) {
+ $targets{$current_target} = 1;
+ }
+ }
+ else {
+ # Target parsed.
+ $current_target = undef;
+ }
+ }
+ }
+ # "Not a target:" is always followed by
+ # a target name, so resetting this one
+ # here is safe.
+ $not_a_target = 0;
+ }
+ }
+ elsif (/^# Files$/) {
+ $processing_targets = 1;
+ }
+ }
+ close MAKE;
+ $rules_parsed = 1;
}
- close LOG;
- return @log;
+
+ return $targets{$target};
}
-
-sub writelog {
- my $package=shift;
- my $cmd=shift;
- my $ext=pkgext($package);
-
- open(LOG, ">>", "debian/${ext}debhelper.log") || error("failed to write to log");
- print LOG $cmd."\n";
- close LOG;
+
}
=head1 SEE ALSO