]> git.donarmstrong.com Git - debhelper.git/blobdiff - dh
Updated French man page translation. Closes: #685560
[debhelper.git] / dh
diff --git a/dh b/dh
index cbc5f10c12deb0e47a4bdbf48fdeb1ad311f335d..17919dce794f365c6028235c78c2a22cdc07b84f 100755 (executable)
--- a/dh
+++ b/dh
@@ -11,125 +11,68 @@ use Debian::Debhelper::Dh_Lib;
 
 =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>] [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-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 binary-indep sequence are passed the "-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
-on architecture dependent packages.
+=head1 OVERRIDE TARGETS
 
-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.
+A F<debian/rules> file using B<dh> can override the command that is run
+at any step in a sequence, by defining an override target.
 
-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.
+To override I<dh_command>, add a target named B<override_>I<dh_command> to
+the rules file. 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.)
 
-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.2 or above.)
+Override targets can also be defined to run only when building
+architecture dependent or architecture independent packages.
+Use targets with names like B<override_>I<dh_command>B<-arch>
+and B<override_>I<dh_command>B<-indep>.
+(Note that to use this feature, you should Build-Depend on
+debhelper 8.9.7 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.
-
-=item B<--until> I<cmd>
-
-Run commands in the sequence until and including I<cmd>, then stop.
+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<--before> I<cmd>
+=item B<--without> I<addon>
 
-Run commands in the sequence before I<cmd>, then stop.
+The inverse of B<--with>, disables using the given addon. This option
+can be repeated more than once, or multiple addons to disable can be
+listed, separated by commas.
 
-=item B<--after> I<cmd>
+=item B<--list>, B<-l>
 
-Run commands in the sequence that come after I<cmd>.
+List all available addons.
 
-=item B<--remaining>
+=item B<--no-act>
 
-Run all commands in the sequence that have yet to be run.
+Prints commands that would run for a given sequence, but does not run them.
 
 =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
+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.
 
-=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
-
-=cut
-
-sub command_pos {
-       my $command=shift;
-       my @sequence=@_;
-
-       foreach my $i (0..$#sequence) {
-               if ($command eq $sequence[$i]) {
-                       return $i;
-               }
-       }
-
-       my @matches;
-       foreach my $i (0..$#sequence) {
-               if ($sequence[$i] =~ /\Q$command\E/) {
-                       push @matches, $i;
-               }
-       }
-       if (! @matches) {
-               error "command specification \"$command\" does not match any command in the sequence"
-       }
-       else {
-               return pop @matches;
-       }
-}
-
 =head1 EXAMPLES
 
 To see what commands are included in a sequence, without actually doing
@@ -146,20 +89,20 @@ commands work with no additional options.
 
 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
+       
+       override_dh_auto_configure:
+               dh_auto_configure -- --with-foo --disable-bar
 
-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
        %:
@@ -182,46 +125,235 @@ after a particular debhelper command is run.
                dh_fixperms
                chmod 4755 debian/foo/usr/bin/foo
 
-If the package's source tree might get files with names
-like build or clean in it, the rules file would not
-run targets with the same names. This issue can be worked
-around by passing -B to make.
+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
+
+Python tools are not run by dh by default, due to the continual change
+in that area. (Before compatibility level v9, dh does run B<dh_pysupport>.)
+Here is how to use B<dh_python2>.
+
+       #!/usr/bin/make -f
+       %:
+               dh $@ --with python2
+
+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
+
+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 -Bf
+       #!/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:
+
+A long build process for a separate documentation package can
+be separated out using architecture independent overrides.
+These will be skipped when running build-arch and binary-arch sequences.
+
+       #!/usr/bin/make -f
+       %:
+               dh $@
+       
+       override_dh_auto_build-indep:
+               $(MAKE) -C docs
+
+       # No tests needed for docs
+       override_dh_auto_test-indep:
+
+       override_dh_auto_install-indep:
+               $(MAKE) -C docs install
+
+Adding to the example above, suppose you need to chmod a file, but only
+when building the architecture dependent package, as it's not present
+when building only documentation.
+
+       override_dh_fixperms-arch:
+               dh_fixperms
+               chmod 4755 debian/foo/usr/bin/foo
+
+=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.
+
+A sequence can also run dependent targets in debian/rules.  For
+example, the "binary" sequence runs the "install" target.
+
+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.
+
+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.
+
+=head1 DEPRECATED OPTIONS
+
+The following options are deprecated. It's much 
+better to use override targets instead.
+
+=over 4
+
+=item B<--until> I<cmd>
+
+Run commands in the sequence until and including I<cmd>, then stop.
+
+=item B<--before> I<cmd>
+
+Run commands in the sequence before I<cmd>, then stop.
+
+=item B<--after> I<cmd>
+
+Run commands in the sequence that come after I<cmd>.
+
+=item B<--remaining>
+
+Run all commands in the sequence that have yet to be 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
 
 # Stash this away before init modifies it.
 my @ARGV_orig=@ARGV;
 
+if (compat(8, 1)) {
+       # 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},
-       "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)=@_;
+                       my %without = map { $_ => 1 } split(",", $value);
+                       @{$dh{WITH}} = grep { ! $without{$_} } @{$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();
+set_buildflags();
+warn_deprecated();
+
+# 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();
+}
+
+# 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 completely 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
@@ -236,7 +368,6 @@ $sequences{install} = [@{$sequences{build}}, qw{
        dh_installcatalogs
        dh_installcron
        dh_installdebconf
-       dh_installcatalogs
        dh_installemacsen
        dh_installifupdown
        dh_installinfo
@@ -251,34 +382,62 @@ $sequences{install} = [@{$sequences{build}}, qw{
        dh_installudev
        dh_installwm
        dh_installxfonts
+       dh_installgsettings
+       dh_bugfiles
+       dh_ucf
        dh_lintian
-       dh_desktop
        dh_gconf
        dh_icons
        dh_perl
-       dh_scrollkeeper
        dh_usrlocal
 
        dh_link
        dh_compress
        dh_fixperms
-}];
+};
+my @ba=qw{
+       dh_strip
+       dh_makeshlibs
+       dh_shlibdeps
+};
+if (! getpackages("arch")) {
+       @ba=();
+}
 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")];
+       $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];
+}
 
-# --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 {
@@ -315,31 +474,70 @@ sub remove_command {
        }
        
 }
+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;
+}
+
+# Load addons, which can modify sequences.
 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) {
-       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
-}      
-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}};
@@ -347,14 +545,18 @@ 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");
@@ -362,22 +564,31 @@ elsif ($sequence eq 'binary-indep') {
 }
 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.
@@ -387,7 +598,7 @@ foreach my $package (@packages) {
                # 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
@@ -421,94 +632,178 @@ elsif ($dh{BEFORE}) {
 
 # Now run the commands in the sequence.
 foreach my $i (0..$stoppoint) {
+       my $command=$sequence[$i];
+
        # Figure out which packages need to run this command.
-       my @exclude;
+       my @todo;
+       my @opts=@options;
        foreach my $package (@packages) {
                if ($startpoint{$package} > $i ||
                    $logged{$package}{$sequence[$i]}) {
-                       push @exclude, $package;
+                       push @opts, "-N$package";
+               }
+               else {
+                       push @todo, $package;
                }
        }
-       
-       if (@exclude eq @packages) {
-               # Command already done for all packages.
+       next unless @todo;
+
+       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.
+               delete $ENV{DH_INTERNAL_OPTIONS};
+               delete $ENV{DH_INTERNAL_OVERRIDE};
+               run("debian/rules", $rules_target);
                next;
        }
+       
+       # Check for override targets in debian/rules, and run instead of
+       # the usual command. (The non-arch-specific override is tried first,
+       # for simplest semantics; mixing it with arch-specific overrides
+       # makes little sense.)
+       my @oldtodo=@todo;
+       foreach my $override_type (undef, "arch", "indep") {
+               @todo = run_override($override_type, $command, \@todo, @opts);
+       }
+       next unless @todo;
+
+       # No need to run the command for any packages handled by the
+       # override targets.
+       my %todo=map { $_ => 1 } @todo;
+       foreach my $package (@oldtodo) {
+               if (! $todo{$package}) {
+                       push @opts, "-N$package";
+               }
+       }
 
-       run($sequence[$i], \@packages, \@exclude, @options);
+       run($command, @opts);
 }
 
 sub run {
+       my $command=shift;
+       my @options=@_;
+
+       # Include 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";
+
+       return if $dh{NO_ACT};
+                       
+       my $ret=system($command, @options);
+       if ($ret >> 8 != 0) {
+               exit $ret >> 8;
+       }
+       elsif ($ret) {
+               exit 1;
+       }
+}
+
+# Tries to run an override target for a command. Returns the list of
+# packages that it was unable to run an override target for.
+sub run_override {
+       my $override_type=shift; # arch, indep, or undef
        my $command=shift;
        my @packages=@{shift()};
-       my @exclude=@{shift()};
        my @options=@_;
-       
-       # 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)) {
-               $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;
+
+       my $override="override_$command".
+               (defined $override_type ? "-".$override_type : "");
+
+       # Check which packages are of the right architecture for the
+       # override_type.
+       my (@todo, @rest);
+       if (defined $override_type) {
+               foreach my $package (@packages) {
+                       my $isall=package_arch($package) eq 'all';
+                       if (($override_type eq 'indep' && $isall) ||
+                           ($override_type eq 'arch' && !$isall)) {
+                               push @todo, $package;
+                       }
+                       else {
+                               push @rest, $package;
+                               push @options, "-N$package";
+                       }
+               }
        }
        else {
-               # If some packages are excluded, add flags
-               # to prevent them from being acted on.
-               push @options, map { "-N$_" } @exclude;
+               @todo=@packages;
        }
 
-       # 3 space indent lines the command being run up under the 
-       # sequence name after "dh ".
-       print "   ".escape_shell($command, @options)."\n";
+       my $has_explicit_target = rules_explicit_target($override);
+       return @packages unless defined $has_explicit_target; # no such override
+       return @rest if ! $has_explicit_target; # has empty override
+       return @rest unless @todo; # has override, but no packages to act on
+
+       if (defined $override_type) {
+               # Ensure appropriate -a or -i option is passed when running
+               # an arch-specific override target.
+               my $opt=$override_type eq "arch" ? "-a" : "-i";
+               push @options, $opt unless grep { $_ eq $opt } @options;
+       }
+
+       # This passes the options through to commands called
+       # inside the target.
+       $ENV{DH_INTERNAL_OPTIONS}=join("\x1e", @options);
+       $ENV{DH_INTERNAL_OVERRIDE}=$command;
+       run("debian/rules", $override);
+       delete $ENV{DH_INTERNAL_OPTIONS};
+       delete $ENV{DH_INTERNAL_OVERRIDE};
+
+       # Update log for overridden command now that it has
+       # finished successfully.
+       # (But avoid logging for dh_clean since it removes
+       # the log earlier.)
+       if (! $dh{NO_ACT} && $command ne 'dh_clean') {
+               write_log($command, @todo);
+               commit_override_log(@todo);
+       }
 
-       if (! $dh{NO_ACT}) {
-               my $ret=system($command, @options);
-               if ($ret >> 8 != 0) {
-                       exit $ret >> 8;
+       return @rest;
+}
+
+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;
                }
-               elsif ($ret) {
-                       exit 1;
+       };
+       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}});
                }
-
-               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;
-                       Debian::Debhelper::Dh_Lib::write_log($override_command, keys %packages);
+               else {
+                       $add->($command);
                }
        }
+       return @sequence;
 }
 
-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;
+sub rules_target {
+       my $command=shift;
+       if ($command =~ /^debian\/rules\s+(.*)/) {
+               return $1
+       }
+       else {
+               return undef;
        }
-       close LOG;
-       return @log;
 }
-               
-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;
+
+sub rules {
+       return "debian/rules ".join(" ", @_);
 }
 
 {
@@ -517,32 +812,50 @@ my $rules_parsed;
 
 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;
-               open(MAKE, "make -Rrnpsf debian/rules debhelper-fail-me 2>/dev/null |");
+               my $current_target;
+               open(MAKE, "LC_ALL=C make -Rrnpsf debian/rules $dummy_target 2>/dev/null |");
                while (<MAKE>) {
                        if ($processing_targets) {
                                if (/^# Not a target:/) {
                                        $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 dependency 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|recipe) 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;
                        }
                }
@@ -550,9 +863,41 @@ sub rules_explicit_target {
                $rules_parsed = 1;
        }
 
-       return exists $targets{$target};
+       return $targets{$target};
+}
+
 }
 
+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.");
+               }
+       }
+}
+
+sub command_pos {
+       my $command=shift;
+       my @sequence=@_;
+
+       foreach my $i (0..$#sequence) {
+               if ($command eq $sequence[$i]) {
+                       return $i;
+               }
+       }
+
+       my @matches;
+       foreach my $i (0..$#sequence) {
+               if ($sequence[$i] =~ /\Q$command\E/) {
+                       push @matches, $i;
+               }
+       }
+       if (! @matches) {
+               error "command specification \"$command\" does not match any command in the sequence"
+       }
+       else {
+               return pop @matches;
+       }
 }
 
 =head1 SEE ALSO