=head1 SYNOPSIS
-B<dh> sequence [B<--with> I<addon>] [B<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining>] [S<I<debhelper options>>]
+B<dh> I<sequence> [B<--with> I<addon>[B<,>I<addon> ...]] [B<--list>] [B<--until> I<cmd>] [B<--before> I<cmd>] [B<--after> I<cmd>] [B<--remaining>] [S<I<debhelper options>>]
=head1 DESCRIPTION
-dh runs a sequence of debhelper commands. The supported sequences
-correspond to the targets of a debian/rules file: "build", "clean",
-"install", "binary-arch", "binary-indep", and "binary".
+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>,
+B<install>, B<binary-arch>, B<binary-indep>, and B<binary>.
-Commands in the binary-indep sequence are passed the "-i" option to ensure
+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
-binary-arch sequences are passed the "-a" option to ensure they only work
+B<binary-arch> sequences are passed the B<-a> option to ensure they only work
on architecture dependent packages.
-Each debhelper command will record when it's successfully run in
-debian/package.debhelper.log. (Which dh_clean deletes.) So dh can tell
-which commands have already been run, for which packages, and skip running
-those commands again.
-
-Each time dh is run, it examines the log, and finds the last logged command
-that is in the specified sequence. It then continues with the next command
-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 gets to that command in the sequence, dh will run that
-target from the rules file, rather than running the actual command. The
-override target can then run the command with additional options, or run
-entirely different commands instead. (Note that to use this feature,
-you should Build-Depend on debhelper 7.0.50 or above.)
+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
+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>
+=item B<--with> I<addon>[B<,>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, 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.
+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 F<PROGRAMMING> file for documentation about
+the sequence addon interface.
+
+=item B<--without> I<addon>
+
+The inverse of B<--with>, disables using the given addon.
+
+=item B<--list>, B<-l>
+
+List all available addons.
=item B<--until> I<cmd>
Run all commands in the sequence that have yet to be run.
-=back
-
-All other options passed to dh are passed on to each command it runs. This
-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.
+=item B<--no-act>
-=head1 SEQUENCE ADDONS
+Prints commands that would run for a given sequence, but does not run them.
-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)
+=back
-Remove I<existing_command> from the list of commands to run.
+All other options passed to B<dh> are passed on to each command it runs. This
+can be used to set an option like B<-v> or B<-X> or B<-N>, as well as for more
+specialised options.
-=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
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.
+Sometimes the automated L<dh_auto_configure(1)> and L<dh_auto_build(1)>
+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_fixperms
chmod 4755 debian/foo/usr/bin/foo
-If your package is a python package, dh will use dh_pysupport by
-default. This is how to use dh_pycentral instead.
+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.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --with python-central
+
+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
+at build time, you can use some commands provided in B<autotools-dev>
+that automate it, like this.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --with autotools_dev
+
+Here is how to force use of Perl's B<Module::Build> build system,
+which can be necessary if debhelper wrongly detects that the package
+uses MakeMaker.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --buildsystem=perl_build
+
+To patch your package using quilt, you can tell B<dh> to use quilt's B<dh>
+sequence addons like this:
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --with quilt
+
+Here is an example of overriding where the B<dh_auto_>I<*> commands find
+the package's source, for a package where the source is located in a
+subdirectory.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --sourcedirectory=src
+
+And here is an example of how to tell the B<dh_auto_>I<*> commands to build
+in a subdirectory, which will be removed on B<clean>.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --builddirectory=build
+
+If your package can be built in parallel, you can support parallel building
+as follows. Then B<dpkg-buildpackage -j> will work.
+
+ #!/usr/bin/make -f
+ %:
+ dh $@ --parallel
+
+Here is a way to prevent B<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:
+
+Sometimes, you may need to make an override target only run commands when a
+particular package is being built. This can be accomplished using
+L<dh_listpackages(1)> to test what is being built. For example:
+
+ #!/usr/bin/make -f
+ %:
+ dh $@
+
+ override_dh_fixperms:
+ dh_fixperms
+ ifneq (,$(findstring 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.
#!/usr/bin/make -f
%:
- dh --with python-central $@
+ dh $@
+
+ build: build-arch build-indep ;
+ build-indep:
+ $(MAKE) docs
+ build-arch:
+ $(MAKE) bins
+
+=head1 INTERNALS
+
+If you're curious about B<dh>'s internals, here's how it works under the hood.
+
+Each debhelper command will record when it's successfully run in
+F<debian/package.debhelper.log>. (Which B<dh_clean> deletes.) So B<dh> can tell
+which commands have already been run, for which packages, and skip running
+those commands again.
+
+Each time B<dh> is run, it examines the log, and finds the last logged command
+that is in the specified sequence. It then continues with the next command
+in the sequence. The B<--until>, B<--before>, B<--after>, and B<--remaining>
+options can override this behavior.
+
+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
+might suggest, is subject to change at any time.
=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" => \&list_addons,
+ "list" => \&list_addons,
},
-});
+ # Disable complaints about unknown options; they are passed on to
+ # the debhelper commands.
+ ignore_unknown_options => 1,
+ # Bundling does not work well since there are unknown options.
+ bundling => 0,
+);
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_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};
+ }
+}
+
+sub list_addons {
+ 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: $@");
}
}
-# Get the sequence of commands to run.
-if (! @ARGV) {
+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";
}
-my $sequence=shift;
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
-}
+ # make -B causes the rules file to be run as a target.
+ # Also 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.
# Check for override targets in debian/rules and
# run them instead of running the command directly.
my $override_command;
- if (rules_explicit_target("override_".$command)) {
+ my $has_explicit_target = rules_explicit_target("override_".$command);
+ if (defined $has_explicit_target) {
$override_command=$command;
- # This passes the options through to commands called
- # inside the target.
- $ENV{DH_INTERNAL_OPTIONS}=join(" ", @options);
- $command="debian/rules";
- @options="override_".$override_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;
+ $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};
}
- # 3 space indent lines the command being run up under the
- # sequence name after "dh ".
- print " ".escape_shell($command, @options)."\n";
+ 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;
- }
- elsif ($ret) {
- exit 1;
+ if (defined $command) {
+ my $ret=system($command, @options);
+ if ($ret >> 8 != 0) {
+ exit $ret >> 8;
+ }
+ 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.
- my %packages=map { $_ => 1 } @packages;
- map { delete $packages{$_} } @exclude;
- write_log($override_command, keys %packages);
+ 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
+ # 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 rules_explicit_target {
# Checks if a specified target exists as an explicit target
- # in debian/rules.
+ # 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) {
+
+ 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) {
$not_a_target = 1;
}
else {
- if (!$not_a_target && /^([^#:]+)::?/) {
- # Target is defined.
- # NOTE: if it is a depenency
- # of .PHONY it will be
- # defined too but that's ok.
- $targets{$1} = 1;
+ 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$/) {
+ }
+ elsif (/^# Files$/) {
$processing_targets = 1;
}
}
$rules_parsed = 1;
}
- return exists $targets{$target};
+ return $targets{$target};
}
}