diff options
Diffstat (limited to 'lib/Debian/Debhelper/Buildsystem.pm')
-rw-r--r-- | lib/Debian/Debhelper/Buildsystem.pm | 203 |
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 |