]> git.donarmstrong.com Git - debhelper.git/commitdiff
Improve build system auto-selection process
authorModestas Vainius <modestas@vainius.eu>
Wed, 18 Nov 2009 19:16:41 +0000 (14:16 -0500)
committerJoey Hess <joey@gnu.kitenet.net>
Wed, 18 Nov 2009 19:16:41 +0000 (14:16 -0500)
This patch alters semantics of check_auto_buildable() a bit. Now it can
also indicate if the source has already been partitially built with the
build system and if so, such build system may be auto-selected over a less
specific its parent (in the inheritance tree) even if the latter is earlier
in the @BUILDSYSTEMS array.

However, this still leaves a requirement that a derivative build system
must not do anything that may break packages of the parent build system.
Otherwise, introduction of a new derivative build system might break
packages which already had that build system implemented via overrides...

Signed-off-by: Modestas Vainius <modestas@vainius.eu>
Debian/Debhelper/Buildsystem.pm
Debian/Debhelper/Buildsystem/ant.pm
Debian/Debhelper/Buildsystem/autoconf.pm
Debian/Debhelper/Buildsystem/cmake.pm
Debian/Debhelper/Buildsystem/makefile.pm
Debian/Debhelper/Buildsystem/perl_build.pm
Debian/Debhelper/Buildsystem/perl_makemaker.pm
Debian/Debhelper/Buildsystem/python_distutils.pm
Debian/Debhelper/Dh_Buildsystems.pm
t/buildsystems/buildsystem_tests

index 7354963d8c5a69114d2e081d12647ed34b9b9e0d..7f7465a42840171f1b73c34754da47d0a5376196 100644 (file)
@@ -109,18 +109,27 @@ sub _set_builddir {
 }
 
 # This instance method is called to check if the build system is able
-# to auto build a source package. Additional argument $step describes
-# which operation the caller is going to perform (either configure,
-# build, test, install or clean). You must override this method for the
-# build system module to be ever picked up automatically. This method is
-# used in conjuction with @Dh_Buildsystems::BUILDSYSTEMS.
+# to build a source package. It will be called during build
+# system auto-selection process inside the root directory of the debian
+# source package. Current build step will be passed as an additional
+# argument. The value returned must be 0 if the source is not buildable
+# or a positive integer otherwise.
 #
-# This method is supposed to be called inside the source root directory.
-# Use $this->get_buildpath($path) method to get full path to the files
-# in the build directory.
+# Generally, it is enough to look for invariant unique build system
+# files shipped with clean source to determine if the source might
+# be buildable or not. However, if the build system enhances (i.e.
+# derives) from the other auto-buildable build system, this method
+# may also check if the source has already been built with this build
+# system partitially by looking for temporary files or other common
+# results the build system produces during the build process. The
+# latter checks must be unique to the current build system and must
+# be very unlikely to be true for either its parent or other build
+# systems. If it is determined that the source has already built
+# partitially with this build system, the value returned must be
+# greater than the one of the SUPER call.
 sub check_auto_buildable {
        my $this=shift;
-       my ($step) = @_;
+       my ($step)=@_;
        return 0;
 }
 
index 26bee95b04cde9f30170701bc1323ca90dbc0acd..938fb446216bee8b1d2b481a2ebd091cd2a7ffd4 100644 (file)
@@ -14,7 +14,7 @@ sub DESCRIPTION {
 
 sub check_auto_buildable {
        my $this=shift;
-       return -e $this->get_sourcepath("build.xml");
+       return $this->get_sourcepath("build.xml") ? 1 : 0;
 }
 
 sub new {
index a97de9c66ab9f85a670f4c94b01a47f1312eac1b..d7b0bed251b251adcba7fafcdc229706cbb58b96 100644 (file)
@@ -18,9 +18,9 @@ sub check_auto_buildable {
        my $this=shift;
        my ($step)=@_;
 
-       # Handle configure; the rest - next class
+       # Handle configure; the rest - next class (compat with 7.0.x code path)
        if ($step eq "configure") {
-               return -x $this->get_sourcepath("configure");
+               return 1 if -x $this->get_sourcepath("configure");
        }
        return 0;
 }
index 03e6ade591017f02df80807df0f2f9737b92d076..3eddc74ff749db4182cc8dabdfdb5b06b99e06ba 100644 (file)
@@ -16,12 +16,12 @@ sub DESCRIPTION {
 sub check_auto_buildable {
        my $this=shift;
        my ($step)=@_;
-       my $ret = -e $this->get_sourcepath("CMakeLists.txt");
-       if ($step ne "configure") {
-               $ret &&= -e $this->get_buildpath("CMakeCache.txt") &&
-                        $this->SUPER::check_auto_buildable(@_);
+       if (-e $this->get_sourcepath("CMakeLists.txt")) {
+               my $ret = $this->SUPER::check_auto_buildable(@_);
+               $ret++ if ($ret && -e $this->get_buildpath("CMakeCache.txt"));
+               return $ret > 0 ? $ret : 1;
        }
-       return $ret;
+       return 0;
 }
 
 sub new {
index 704f9c952d112c25f39fc7f56f908b52b8945b8d..083abc4293cd7c39b07972e5b9bc0dfc622619a4 100644 (file)
@@ -71,15 +71,11 @@ sub check_auto_buildable {
        my $this=shift;
        my ($step) = @_;
 
-       # Handles build, test, install, clean; configure - next class
-       if (grep /^\Q$step\E$/, qw{build test install clean}) {
-               # This is always called in the source directory, but generally
-               # Makefiles are created (or live) in the the build directory.
-               return -e $this->get_buildpath("Makefile") ||
-                      -e $this->get_buildpath("makefile") ||
-                      -e $this->get_buildpath("GNUmakefile");
-       }
-       return 0;
+       # This is always called in the source directory, but generally
+       # Makefiles are created (or live) in the the build directory.
+       return (-e $this->get_buildpath("Makefile") ||
+               -e $this->get_buildpath("makefile") ||
+               -e $this->get_buildpath("GNUmakefile")) ? 1 : 0;
 }
 
 sub build {
index 8974be2e3495beb3a3859f686a6e9a285385ad73..2afa5e59ff75888dcaa741380d81eb4343998a5c 100644 (file)
@@ -21,7 +21,7 @@ sub check_auto_buildable {
        if ($step ne "configure") {
                $ret &&= -e $this->get_sourcepath("Build");
        }
-       return $ret;
+       return $ret ? 1 : 0;
 }
 
 sub do_perl {
index e109be5711e4aa96669ddef40bfd5e78a5afacbf..473a3a7e8bf7e2c3747236b10bf91823f7f34bda 100644 (file)
@@ -19,7 +19,7 @@ sub check_auto_buildable {
 
        # Handles everything if Makefile.PL exists. Otherwise - next class.
        if (-e $this->get_sourcepath("Makefile.PL")) {
-               if ($step eq "install" || $step eq "configure") {
+               if ($step eq "configure") {
                        return 1;
                }
                else {
index 219c6f9bd633a1592575e1a95770e420e7516c17..70307b0fa2023395af5466d0661a8bb65ef3af62 100644 (file)
@@ -31,7 +31,7 @@ sub new {
 
 sub check_auto_buildable {
        my $this=shift;
-       return -e $this->get_sourcepath("setup.py");
+       return -e $this->get_sourcepath("setup.py") ? 1 : 0;
 }
 
 sub not_our_cfg {
@@ -117,10 +117,10 @@ sub setup_py {
        # Then, run setup.py with each available python, to build
        # extensions for each.
 
-        my $python_default = `pyversions -d`;
-        $python_default =~ s/^\s+//;
-        $python_default =~ s/\s+$//;
-        my @python_requested = split ' ', `pyversions -r 2>/dev/null`;
+       my $python_default = `pyversions -d`;
+       $python_default =~ s/^\s+//;
+       $python_default =~ s/\s+$//;
+       my @python_requested = split ' ', `pyversions -r 2>/dev/null`;
        if (grep /^\Q$python_default\E/, @python_requested) {
                @python_requested = (
                        grep(!/^\Q$python_default\E/, @python_requested),
@@ -129,7 +129,7 @@ sub setup_py {
        }
 
        my @python_dbg;
-        my @dbg_build_needed = $this->dbg_build_needed();
+       my @dbg_build_needed = $this->dbg_build_needed();
        foreach my $python (map { $_."-dbg" } @python_requested) {
                if (grep /^(python-all-dbg|\Q$python\E)/, @dbg_build_needed) {
                        push @python_dbg, $python;
index a9a13a29d98e287b93732116c74728220073a1f1..2893c1a4c626dea352708e3c38cbb47f615cf6dd 100644 (file)
@@ -14,6 +14,8 @@ use File::Spec;
 use base 'Exporter';
 our @EXPORT=qw(&buildsystems_init &buildsystems_do &load_buildsystem &load_all_buildsystems);
 
+use constant BUILD_STEPS => qw(configure build test install clean);
+
 # Historical order must be kept for backwards compatibility. New
 # build systems MUST be added to the END of the list.
 our @BUILDSYSTEMS = (
@@ -66,14 +68,26 @@ sub load_buildsystem {
        }
        else {
                # Try to determine build system automatically
+               my $selected;
+               my $selected_level = 0;
                for $system (@BUILDSYSTEMS) {
                        my $inst = create_buildsystem_instance($system, @_);
-                       if ($inst->check_auto_buildable($step)) {
-                               return $inst;
+
+                       # Only derived (i.e. more specific) build system can be
+                       # considered beyond the currently selected one.
+                       next if defined $selected && !$inst->isa(ref $selected);
+
+                       # If the build system says it is auto-buildable at the current
+                       # step and it can provide more specific information about its
+                       # status than its parent (if any), auto-select it.
+                       my $level = $inst->check_auto_buildable($step);
+                       if ($level > $selected_level) {
+                               $selected = $inst;
+                               $selected_level = $level;
                        }
                }
+               return $selected;
        }
-       return;
 }
 
 sub load_all_buildsystems {
@@ -189,7 +203,7 @@ sub buildsystems_do {
                $step =~ s/^dh_auto_//;
        }
 
-       if (grep(/^\Q$step\E$/, qw{configure build test install clean}) == 0) {
+       if (grep(/^\Q$step\E$/, BUILD_STEPS) == 0) {
                error("unrecognized build step: " . $step);
        }
 
index 0465a93b4cac9680ff8880863dff995a4c164fc8..487fd2bef6d2163c7db4418ced71533fd1c94ae7 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 
-use Test::More tests => 277;
+use Test::More tests => 292;
 
 use strict;
 use warnings;
@@ -229,14 +229,8 @@ sub test_check_auto_buildable {
                } elsif (exists $expected->{default}) {
                        $e = $expected->{default};
                }
-               if ($e) {
-                       ok( $bs->check_auto_buildable($step),
-                           $bs->NAME() . "($config): check_auto_buildable($step)" );
-               }
-               else {
-                       ok( ! $bs->check_auto_buildable($step),
-                           $bs->NAME() . "($config): ! check_auto_buildable($step)" );
-               }
+               is( $bs->check_auto_buildable($step), $e,
+                       $bs->NAME() . "($config): check_auto_buildable($step) == $e" );
        }
 }
 
@@ -262,17 +256,18 @@ touch "$tmpdir/configure", 0755;
 test_check_auto_buildable($bs{autoconf}, "configure", { configure => 1 });
 
 touch "$tmpdir/CMakeLists.txt";
-test_check_auto_buildable($bs{cmake}, "CMakeLists.txt", { configure => 1 });
+test_check_auto_buildable($bs{cmake}, "CMakeLists.txt", 1);
 
 touch "$tmpdir/Makefile.PL";
-test_check_auto_buildable($bs{perl_mm}, "Makefile.PL",
-    { configure => 1, install => 1 });
+test_check_auto_buildable($bs{perl_mm}, "Makefile.PL", { configure => 1 });
 
 # With Makefile
 touch "$builddir/Makefile";
-test_check_auto_buildable($bs, "Makefile", { configure => 0, default => 1 });
+test_check_auto_buildable($bs, "Makefile", 1);
 test_check_auto_buildable($bs{autoconf}, "configure+Makefile", { configure => 1 });
 test_check_auto_buildable($bs{cmake}, "CMakeLists.txt+Makefile", 1);
+touch "$builddir/CMakeCache.txt"; # strong evidence that cmake was run
+test_check_auto_buildable($bs{cmake}, "CMakeCache.txt+Makefile", 2);
 
 # Makefile.PL forces in-source
 #(see note in check_auto_buildable() why always 1 here)
@@ -298,18 +293,20 @@ cleandir($tmpdir);
 
 ### Now test if it can autoselect a proper buildsystem for a typical package
 sub test_autoselection {
-       my $system=shift;
+       my $testname=shift;
        my $expected=shift;
+       my %args=@_;
        for my $step (@STEPS) {
                my $bs = load_buildsystem(undef, $step, @_);
                my $e = $expected;
                $e = $expected->{$step} if ref $expected;
                if (defined $bs) {
-                       is( $bs->NAME(), $e, "autoselection($system): $step=".((defined $e)?$e:'undef') );
+                       is( $bs->NAME(), $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') );
                }
                else {
-                       is ( undef, $e, "autoselection($system): $step=".((defined $e)?$e:'undef') );
+                       is ( undef, $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') );
                }
+               &{$args{"code_$step"}}() if exists $args{"code_$step"};
        }
 }
 
@@ -329,8 +326,7 @@ cleandir $tmpdir;
 
 # Makefile
 touch "$builddir/Makefile";
-test_autoselection("makefile", { build => "makefile", test => "makefile",
-               install => "makefile", clean => "makefile" }, %tmp);
+test_autoselection("makefile", "makefile", %tmp);
 cleandir $tmpdir;
 
 # Python Distutils
@@ -345,11 +341,28 @@ test_autoselection("perl_build", "perl_build", %tmp);
 cleandir $tmpdir;
 
 # CMake
+touch "$tmpdir/CMakeLists.txt";
+$tmp = sub {
+       touch "$builddir/Makefile";
+};
+test_autoselection("cmake without CMakeCache.txt",
+       { configure => "cmake", build => "makefile",
+         test => "makefile", install => "makefile", clean => "makefile" }, %tmp,
+       code_configure => $tmp);
+cleandir $tmpdir;
+
+touch "$tmpdir/CMakeLists.txt";
+$tmp = sub {
+       touch "$builddir/Makefile";
+       touch "$builddir/CMakeCache.txt";
+};
+test_autoselection("cmake with CMakeCache.txt",
+       "cmake", %tmp, code_configure => $tmp);
+cleandir $tmpdir;
+
 touch "$tmpdir/CMakeLists.txt";
 touch "$builddir/Makefile";
-test_autoselection("cmake",
-    { configure => "cmake", build => "makefile",
-      test => "makefile", install => "makefile", clean => "makefile" }, %tmp);
+test_autoselection("cmake and existing Makefile", "makefile", %tmp);
 cleandir $tmpdir;
 
 ### Test Buildsystem::rmdir_builddir()