summaryrefslogtreecommitdiff
path: root/Debian/Debhelper
diff options
context:
space:
mode:
Diffstat (limited to 'Debian/Debhelper')
-rw-r--r--Debian/Debhelper/Buildsystem.pm16
-rw-r--r--Debian/Debhelper/Buildsystem/makefile.pm31
-rw-r--r--Debian/Debhelper/Dh_Buildsystems.pm42
-rw-r--r--Debian/Debhelper/Dh_Lib.pm42
4 files changed, 126 insertions, 5 deletions
diff --git a/Debian/Debhelper/Buildsystem.pm b/Debian/Debhelper/Buildsystem.pm
index 62c45b5d..677e3bf9 100644
--- a/Debian/Debhelper/Buildsystem.pm
+++ b/Debian/Debhelper/Buildsystem.pm
@@ -47,7 +47,12 @@ sub DEFAULT_BUILD_DIRECTORY {
# specified or empty, defaults to the current directory.
# - builddir - specifies build directory to use. Path is relative to the
# current (top) directory. If undef or empty,
-# DEFAULT_BUILD_DIRECTORY directory will be used.
+# DEFAULT_BUILD_DIRECTORY directory will be used.
+# - parallel - number of parallel process to be spawned for building
+# sources. Parallel building needs to be supported by the
+# underlying build system for this option to be effective.
+# Defaults to undef (i.e. parallel disabled, but do not try to
+# enforce this limit by messing with environment).
# Derived class can override the constructor to initialize common object
# parameters. Do NOT use constructor to execute commands or otherwise
# configure/setup build environment. There is absolutely no guarantee the
@@ -58,6 +63,7 @@ sub new {
my $this = bless({ sourcedir => '.',
builddir => undef,
+ parallel => undef,
cwd => Cwd::getcwd() }, $class);
if (exists $opts{sourcedir}) {
@@ -71,6 +77,9 @@ sub new {
if (exists $opts{builddir}) {
$this->_set_builddir($opts{builddir});
}
+ if (defined $opts{parallel} && $opts{parallel} >= 1) {
+ $this->{parallel} = $opts{parallel};
+ }
return $this;
}
@@ -243,6 +252,11 @@ sub get_source_rel2builddir {
return $dir;
}
+sub get_parallel {
+ my $this=shift;
+ return $this->{parallel};
+}
+
# When given a relative path to the build directory, converts it
# to the path that is relative to the source directory. If $path is
# not given, returns a path to the build directory that is relative
diff --git a/Debian/Debhelper/Buildsystem/makefile.pm b/Debian/Debhelper/Buildsystem/makefile.pm
index 3809d594..6629d25b 100644
--- a/Debian/Debhelper/Buildsystem/makefile.pm
+++ b/Debian/Debhelper/Buildsystem/makefile.pm
@@ -7,7 +7,7 @@
package Debian::Debhelper::Buildsystem::makefile;
use strict;
-use Debian::Debhelper::Dh_Lib qw(escape_shell);
+use Debian::Debhelper::Dh_Lib qw(escape_shell get_make_jobserver_status);
use base 'Debian::Debhelper::Buildsystem';
sub get_makecmd_C {
@@ -30,13 +30,38 @@ sub exists_make_target {
return length($ret);
}
+sub do_make {
+ my $this=shift;
+
+ # Always clean MAKEFLAGS from unavailable jobserver options. If parallel
+ # is enabled, do more extensive clean up from all job control specific
+ # options and start our own jobserver if parallel building (> 1) was
+ # requested.
+ my ($status, $makeflags) = get_make_jobserver_status();
+ if ($status eq "jobserver-unavailable" || defined $this->get_parallel()) {
+ if (defined $makeflags) {
+ $ENV{MAKEFLAGS} = $makeflags;
+ }
+ else {
+ delete $ENV{MAKEFLAGS} if exists $ENV{MAKEFLAGS};
+ }
+ }
+
+ # Start a new jobserver if parallel building was requested
+ if (defined $this->get_parallel()) {
+ unshift @_, "-j" . ($this->get_parallel() > 1 ? $this->get_parallel() : 1);
+ }
+
+ $this->doit_in_builddir($this->{makecmd}, @_);
+}
+
sub make_first_existing_target {
my $this=shift;
my $targets=shift;
foreach my $target (@$targets) {
if ($this->exists_make_target($target)) {
- $this->doit_in_builddir($this->{makecmd}, $target, @_);
+ $this->do_make($target, @_);
return $target;
}
}
@@ -71,7 +96,7 @@ sub check_auto_buildable {
sub build {
my $this=shift;
- $this->doit_in_builddir($this->{makecmd}, @_);
+ $this->do_make(@_);
}
sub test {
diff --git a/Debian/Debhelper/Dh_Buildsystems.pm b/Debian/Debhelper/Dh_Buildsystems.pm
index 49862675..39081458 100644
--- a/Debian/Debhelper/Dh_Buildsystems.pm
+++ b/Debian/Debhelper/Dh_Buildsystems.pm
@@ -30,6 +30,7 @@ my $opt_buildsys;
my $opt_sourcedir;
my $opt_builddir;
my $opt_list;
+my $opt_parallel;
sub create_buildsystem_instance {
my $system=shift;
@@ -47,6 +48,9 @@ sub create_buildsystem_instance {
if (!exists $bsopts{sourcedir} && defined $opt_sourcedir) {
$bsopts{sourcedir} = ($opt_sourcedir eq "") ? undef : $opt_sourcedir;
}
+ if (!exists $bsopts{parallel}) {
+ $bsopts{parallel} = $opt_parallel;
+ }
return $module->new(%bsopts);
}
@@ -122,9 +126,47 @@ sub buildsystems_init {
"l" => \$opt_list,
"list" => \$opt_list,
+
+ "j:i" => \$opt_parallel,
+ "parallel:i" => \$opt_parallel,
);
$args{options}{$_} = $options{$_} foreach keys(%options);
Debian::Debhelper::Dh_Lib::init(%args);
+
+ # Post-process parallel building option. Initially $opt_parallel may have
+ # such values:
+ # * undef - no --parallel option was specified. This tells buildsystem class
+ # not to mess with MAKEFLAGS (with the exception of cleaning MAKEFLAGS
+ # from pointless unavailable jobserver options to avoid warnings) nor
+ # enable parallel.
+ # * 1 - --parallel=1 option was specified, hence the package should never be
+ # built in parallel mode. Cleans MAKEFLAGS if needed.
+ # * 0 - --parallel was specified without interger argument meaning package
+ # does not want to enforce limit on maximum number of parallel processes.
+ # * N > 1 - --parallel=N was specified where N is the maximum number parallel
+ # processes the package wants to enforce.
+ # Taken DEB_BUILD_OPTIONS and all this into account, set $opt_parallel to the
+ # number of parallel processes to be used for *this* build.
+ if (defined $opt_parallel) {
+ if ($opt_parallel >= 0 && exists $ENV{DEB_BUILD_OPTIONS}) {
+ # Parse parallel=n tag
+ my $n;
+ foreach my $opt (split(/\s+/, $ENV{DEB_BUILD_OPTIONS})) {
+ $n = $1 if $opt =~ /^parallel=(\d+)$/;
+ }
+ if (defined $n && $n > 0) {
+ $opt_parallel = $n if $opt_parallel == 0 || $n < $opt_parallel;
+ }
+ else {
+ # Invalid value in the parallel tag. Disable.
+ $opt_parallel = 1;
+ }
+ }
+ else {
+ # In case invalid number was passed
+ $opt_parallel = 1;
+ }
+ }
}
sub buildsystems_list {
diff --git a/Debian/Debhelper/Dh_Lib.pm b/Debian/Debhelper/Dh_Lib.pm
index 2d1934be..ebf7db7e 100644
--- a/Debian/Debhelper/Dh_Lib.pm
+++ b/Debian/Debhelper/Dh_Lib.pm
@@ -16,7 +16,7 @@ use vars qw(@ISA @EXPORT %dh);
&compat &addsubstvar &delsubstvar &excludefile &package_arch
&is_udeb &udeb_filename &debhelper_script_subst &escape_shell
&inhibit_log &load_log &write_log &dpkg_architecture_value
- &sourcepackage);
+ &sourcepackage &get_make_jobserver_status);
my $max_compat=7;
@@ -205,6 +205,46 @@ sub _error_exitcode {
}
}
+# A helper subroutine for detecting (based on MAKEFLAGS) if make jobserver
+# is enabled, if it is available or MAKEFLAGS contains "jobs" option.
+# It returns current status (jobserver, jobserver-unavailable or jobs-N where
+# N is number of jobs, 0 if infinite) and MAKEFLAGS cleaned up from
+# job control options.
+sub get_make_jobserver_status {
+ my $jobsre = qr/(?:^|\s)(?:(?:-j\s*|--jobs(?:=|\s+))(\d+)?|--jobs)\b/;
+ my $status = "";
+ my $makeflags;
+
+ if (exists $ENV{MAKEFLAGS}) {
+ $makeflags = $ENV{MAKEFLAGS};
+ if ($makeflags =~ /(?:^|\s)--jobserver-fds=(\d+)/) {
+ $status = "jobserver";
+ if (!open(my $in, "<&", "$1")) {
+ # Job server is unavailable
+ $status .= "-unavailable";
+ }
+ else {
+ close $in;
+ }
+ # Clean makeflags up
+ $makeflags =~ s/(?:^|\s)--jobserver-fds=\S+//g;
+ $makeflags =~ s/(?:^|\s)-j\b//g;
+ }
+ elsif (my @m = ($makeflags =~ /$jobsre/g)) {
+ # Job count is specified in MAKEFLAGS. Whenever make reads it, a new
+ # jobserver will be started. Job count returned is 0 if infinite.
+ $status = "jobs-" . (defined $m[$#m] ? $m[$#m] : "0");
+ # Clean makeflags up from "jobs" option(s)
+ $makeflags =~ s/$jobsre//g;
+ }
+ }
+ if ($status) {
+ # MAKEFLAGS could be unset if it is empty
+ $makeflags = undef if $makeflags =~ /^\s*$/;
+ }
+ return wantarray ? ($status, $makeflags) : $status;
+}
+
# Run a command that may have a huge number of arguments, like xargs does.
# Pass in a reference to an array containing the arguments, and then other
# parameters that are the command and any parameters that should be passed to