summaryrefslogtreecommitdiff
path: root/lib/Debian/Debhelper/Buildsystem.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Debian/Debhelper/Buildsystem.pm')
-rw-r--r--lib/Debian/Debhelper/Buildsystem.pm203
1 files changed, 187 insertions, 16 deletions
diff --git a/lib/Debian/Debhelper/Buildsystem.pm b/lib/Debian/Debhelper/Buildsystem.pm
index 4d2ee728..8176c7bf 100644
--- a/lib/Debian/Debhelper/Buildsystem.pm
+++ b/lib/Debian/Debhelper/Buildsystem.pm
@@ -16,10 +16,22 @@ use Debian::Debhelper::Dh_Lib;
# name. Do not override this method unless you know what you are
# doing.
sub NAME {
- my $this=shift;
- my $class = ref($this) || $this;
+ my ($this) = @_;
+ my $class = ref($this);
+ my $target_name;
+ if ($class) {
+ # Do not assume that the target buildsystem has been provided.
+ # NAME could be called during an error in the constructor.
+ if ($this->IS_GENERATOR_BUILD_SYSTEM and $this->get_targetbuildsystem) {
+ $target_name = $this->get_targetbuildsystem->NAME;
+ }
+ } else {
+ $class = $this;
+ }
if ($class =~ m/^.+::([^:]+)$/) {
- return $1;
+ my $name = $1;
+ return "${name}+${target_name}" if defined($target_name);
+ return $name;
}
else {
error("ınvalid build system class name: $class");
@@ -37,6 +49,43 @@ sub DEFAULT_BUILD_DIRECTORY {
"obj-" . dpkg_architecture_value("DEB_HOST_GNU_TYPE");
}
+# Return 1 if the build system generator
+sub IS_GENERATOR_BUILD_SYSTEM {
+ return 0;
+}
+
+# Generator build-systems only
+# The name of the supported target systems. The first one is
+# assumed to be the default if DEFAULT_TARGET_BUILD_SYSTEM is
+# not overridden.
+sub SUPPORTED_TARGET_BUILD_SYSTEMS {
+ error("class lacking SUPPORTED_TARGET_BUILD_SYSTEMS");
+}
+
+# Generator build-systems only
+# Name of default target build system if target is unspecified
+# (e.g. --buildsystem=cmake instead of cmake+makefile).
+sub DEFAULT_TARGET_BUILD_SYSTEM {
+ my ($this) = @_;
+ my @targets = $this->SUPPORTED_TARGET_BUILD_SYSTEMS;
+ # Assume they are listed in order.
+ return $targets[0];
+}
+
+# For regular build systems, the same as DESCRIPTION
+# For generator based build systems, the DESCRIPTION of the generator build
+# system + the target build system. Do not override this method unless you
+# know what you are doing.
+sub FULL_DESCRIPTION {
+ my ($this) = @_;
+ my $description = $this->DESCRIPTION;
+ return $description if not exists($this->{'targetbuildsystem'});
+ my $target_build_system = $this->{'targetbuildsystem'};
+ return $description if not defined($target_build_system);
+ my $target_desc = $target_build_system->FULL_DESCRIPTION;
+ return "${description} combined with ${target_desc}";
+}
+
# Constructs a new build system object. Named parameters:
# - sourcedir- specifies source directory (relative to the current (top)
# directory) where the sources to be built live. If not
@@ -46,6 +95,8 @@ sub DEFAULT_BUILD_DIRECTORY {
# DEFAULT_BUILD_DIRECTORY directory will be used.
# - parallel - max number of parallel processes to be spawned for building
# sources (-1 = unlimited; 1 = no parallel)
+# - targetbuildsystem - The target build system for generator based build
+# systems. Only set for generator build systems.
# 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
@@ -59,6 +110,23 @@ sub new {
parallel => undef,
cwd => Cwd::getcwd() }, $class);
+ # Setup the target buildsystem early, so e.g. _set_builddir also
+ # applies to the target build system. Useful if the generator
+ # and target does not agree on (e.g.) the default build dir.
+ my $target_bs_name;
+ if (exists $opts{targetbuildsystem}) {
+ $target_bs_name = $opts{targetbuildsystem};
+ }
+
+ $target_bs_name //= $this->DEFAULT_TARGET_BUILD_SYSTEM if $this->IS_GENERATOR_BUILD_SYSTEM;
+
+ if (defined($target_bs_name)) {
+ my %target_opts = %opts;
+ delete($target_opts{'targetbuildsystem'});
+ my $target_system =_create_buildsystem_instance($target_bs_name, 1, %target_opts);
+ $this->set_targetbuildsystem($target_system);
+ }
+
if (exists $opts{sourcedir}) {
# Get relative sourcedir abs_path (without symlinks)
my $abspath = Cwd::abs_path($opts{sourcedir});
@@ -73,6 +141,7 @@ sub new {
if (defined $opts{parallel}) {
$this->{parallel} = $opts{parallel};
}
+
return $this;
}
@@ -101,9 +170,42 @@ sub _set_builddir {
}
}
$this->{builddir} = $builddir;
+ # Use get as guard because this method is (also) called from the
+ # constructor before the target build system is setup.
+ if ($this->get_targetbuildsystem) {
+ $this->get_targetbuildsystem->{builddir} = $builddir;
+ };
return $builddir;
}
+sub set_targetbuildsystem {
+ my ($this, $target_system) = @_;
+ my $ok = 0;
+ my $target_bs_name = $target_system->NAME;
+ if (not $this->IS_GENERATOR_BUILD_SYSTEM) {
+ my $name = $this->NAME;
+ error("Cannot set a target build system: Buildsystem ${name} is not a generator build system");
+ }
+ for my $supported_bs_name ($this->SUPPORTED_TARGET_BUILD_SYSTEMS) {
+ if ($supported_bs_name eq $target_bs_name) {
+ $ok = 1;
+ last;
+ }
+ }
+ if (not $ok) {
+ my $name = $this->NAME;
+ error("Buildsystem ${name} does not support ${target_bs_name} as target build system.");
+ }
+ $this->{'targetbuildsystem'} = $target_system
+}
+
+# Returns the target build system if it is provided
+sub get_targetbuildsystem {
+ my $this = shift;
+ return if not exists($this->{'targetbuildsystem'});
+ return $this->{'targetbuildsystem'};
+}
+
# This instance method is called to check if the build system is able
# to build a source package. It will be called during the build
# system auto-selection process, inside the root directory of the debian
@@ -137,6 +239,11 @@ sub enforce_in_source_building {
$this->{warn_insource} = 1;
$this->{builddir} = undef;
}
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->enforce_in_source_building(@_);
+ # Only warn in one build system.
+ delete($this->{warn_insource});
+ }
}
# Derived class can call this method in its constructor to *prefer*
@@ -155,6 +262,9 @@ sub prefer_out_of_source_building {
error("default build directory is the same as the source directory." .
" Please specify a custom build directory");
}
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->prefer_out_of_source_building(@_);
+ }
}
}
@@ -263,6 +373,9 @@ sub get_parallel {
sub disable_parallel {
my ($this) = @_;
$this->{parallel} = 1;
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->disable_parallel;
+ }
}
# When given a relative path to the build directory, converts it
@@ -291,6 +404,17 @@ sub mkdir_builddir {
}
}
+sub check_auto_buildable_clean_oos_buildir {
+ my $this = shift;
+ my ($step) = @_;
+ # This only applies to clean
+ return 0 if $step ne 'clean';
+ my $builddir = $this->get_builddir;
+ # If there is no builddir, then this rule does not apply.
+ return 0 if not defined($builddir) or not -d $builddir;
+ return 1;
+}
+
sub _cd {
my ($this, $dir)=@_;
verbose_print("cd $dir");
@@ -315,12 +439,22 @@ sub _in_dir {
return $code->(@args);
}
+sub _generic_doit_in_dir {
+ my ($this, $dir, $sub, @args) = @_;
+ my %args;
+ if (ref($args[0])) {
+ %args = %{shift(@args)};
+ }
+ $args{chdir} = $dir;
+ return $sub->(\%args, @args);
+}
+
# Changes working directory to the source directory (if needed),
# calls print_and_doit(@_) and changes working directory back to the
# top directory.
sub doit_in_sourcedir {
my ($this, @args) = @_;
- print_and_doit({ chdir => $this->get_sourcedir }, @args);
+ $this->_generic_doit_in_dir($this->get_sourcedir, \&print_and_doit, @args);
return 1;
}
@@ -329,7 +463,7 @@ sub doit_in_sourcedir {
# top directory. Errors are ignored.
sub doit_in_sourcedir_noerror {
my ($this, @args) = @_;
- return print_and_doit_noerror({ chdir => $this->get_sourcedir }, @args);
+ return $this->_generic_doit_in_dir($this->get_sourcedir, \&print_and_doit_noerror, @args);
}
# Changes working directory to the build directory (if needed),
@@ -337,7 +471,7 @@ sub doit_in_sourcedir_noerror {
# top directory.
sub doit_in_builddir {
my ($this, @args) = @_;
- print_and_doit({ chdir => $this->get_buildpath }, @args);
+ $this->_generic_doit_in_dir($this->get_buildpath, \&print_and_doit, @args);
return 1;
}
@@ -346,15 +480,7 @@ sub doit_in_builddir {
# top directory. Errors are ignored.
sub doit_in_builddir_noerror {
my ($this, @args) = @_;
- return print_and_doit_noerror({ chdir => $this->get_buildpath }, @args);
-}
-
-# Changes working directory to the build directory (if needed),
-# calls print_and_complex_doit(@_) and changes working directory back to the
-# top directory.
-sub complex_doit_in_builddir {
- my ($this, @args) = @_;
- return $this->_in_dir($this->get_buildpath, \&print_and_complex_doit, @args);
+ return $this->_generic_doit_in_dir($this->get_buildpath, \&print_and_doit_noerror, @args);
}
# In case of out of source tree building, whole build directory
@@ -402,6 +528,9 @@ sub pre_building_step {
" does not support building out of source tree. In source building enforced.");
delete $this->{warn_insource};
}
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->pre_building_step(@_);
+ }
}
# Instance method that is called after performing any step (see below).
@@ -410,6 +539,9 @@ sub pre_building_step {
sub post_building_step {
my $this=shift;
my ($step)=@_;
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->post_building_step(@_);
+ }
}
# The instance methods below provide support for configuring,
@@ -420,26 +552,65 @@ sub post_building_step {
# implement build system specific steps needed to build the
# source. Arbitrary number of custom step arguments might be
# passed. Default implementations do nothing.
+#
+# Note: For generator build systems, the default is to
+# delegate the step to the target build system for all
+# steps except configure.
sub configure {
my $this=shift;
}
sub build {
my $this=shift;
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->build(@_);
+ }
}
sub test {
my $this=shift;
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->test(@_);
+ }
}
# destdir parameter specifies where to install files.
sub install {
my $this=shift;
- my $destdir=shift;
+ my ($destdir) = @_;
+
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->install(@_);
+ }
}
sub clean {
my $this=shift;
+
+ if ($this->IS_GENERATOR_BUILD_SYSTEM) {
+ $this->get_targetbuildsystem->clean(@_);
+ }
+}
+
+
+sub _create_buildsystem_instance {
+ my ($full_name, $required, %bsopts) = @_;
+ my @parts = split(m{[+]}, $full_name, 2);
+ my $name = $parts[0];
+ my $module = "Debian::Debhelper::Buildsystem::$name";
+ if (@parts > 1) {
+ if (exists($bsopts{'targetbuildsystem'})) {
+ error("Conflicting target buildsystem for ${name} (load as ${full_name}, but target configured in bsopts)");
+ }
+ $bsopts{'targetbuildsystem'} = $parts[1];
+ }
+
+ eval "use $module";
+ if ($@) {
+ return if not $required;
+ error("unable to load build system class '$name': $@");
+ }
+ return $module->new(%bsopts);
}
1