diff options
Diffstat (limited to 't/buildsystems')
-rwxr-xr-x | t/buildsystems/01-build-system-basic-api.t | 43 | ||||
-rwxr-xr-x | t/buildsystems/02-make-jobserver-makeflags.t | 57 | ||||
-rwxr-xr-x | t/buildsystems/03-bs-auto-buildable.t | 218 | ||||
-rwxr-xr-x | t/buildsystems/04-dh_auto_do_autoconf.t | 88 | ||||
-rwxr-xr-x | t/buildsystems/05-load-build-system.t | 55 | ||||
-rwxr-xr-x | t/buildsystems/06-buildsystem-mkdir-rmdir.t | 51 | ||||
-rwxr-xr-x | t/buildsystems/autoconf/configure | 84 | ||||
-rwxr-xr-x | t/buildsystems/buildsystem_tests.t | 293 | ||||
-rw-r--r-- | t/buildsystems/debian/changelog | 5 | ||||
-rw-r--r-- | t/buildsystems/debian/control | 12 | ||||
-rwxr-xr-x | t/buildsystems/load-bs.pl | 16 | ||||
-rw-r--r-- | t/buildsystems/parallel.mk | 21 |
12 files changed, 943 insertions, 0 deletions
diff --git a/t/buildsystems/01-build-system-basic-api.t b/t/buildsystems/01-build-system-basic-api.t new file mode 100755 index 0000000..dfb26d2 --- /dev/null +++ b/t/buildsystems/01-build-system-basic-api.t @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 12; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Buildsystem; + +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; + + +build_system_path_apis(); + +# Bulk tests +sub build_system_path_apis { + ### Test Buildsystem class API methods + is( $BS_CLASS->canonpath("path/to/the/./nowhere/../../somewhere"), + "path/to/somewhere", "canonpath no1" ); + is( $BS_CLASS->canonpath("path/to/../forward/../../somewhere"), + "somewhere","canonpath no2" ); + is( $BS_CLASS->canonpath("path/to/../../../somewhere"), + "../somewhere","canonpath no3" ); + is( $BS_CLASS->canonpath("./"), ".", "canonpath no4" ); + is( $BS_CLASS->canonpath("/absolute/path/./somewhere/../to/nowhere"), + "/absolute/path/to/nowhere", "canonpath no5" ); + is( $BS_CLASS->_rel2rel("path/my/file", "path/my", "/tmp"), + "file", "_rel2rel no1" ); + is( $BS_CLASS->_rel2rel("path/dir/file", "path/my", "/tmp"), + "../dir/file", "_rel2rel no2" ); + is( $BS_CLASS->_rel2rel("file", "/root/path/my", "/root"), + "/root/file", "_rel2rel abs no3" ); + is( $BS_CLASS->_rel2rel(".", ".", "/tmp"), ".", "_rel2rel no4" ); + is( $BS_CLASS->_rel2rel("path", "path/", "/tmp"), ".", "_rel2rel no5" ); + is( $BS_CLASS->_rel2rel("/absolute/path", "anybase", "/tmp"), + "/absolute/path", "_rel2rel abs no6"); + is( $BS_CLASS->_rel2rel("relative/path", "/absolute/base", "/tmp"), + "/tmp/relative/path", "_rel2rel abs no7"); +} + diff --git a/t/buildsystems/02-make-jobserver-makeflags.t b/t/buildsystems/02-make-jobserver-makeflags.t new file mode 100755 index 0000000..9469759 --- /dev/null +++ b/t/buildsystems/02-make-jobserver-makeflags.t @@ -0,0 +1,57 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 9; + +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); + +# Test clean_jobserver_makeflags. + +test_clean_jobserver_makeflags('--jobserver-fds=103,104 -j', + undef, + 'unset makeflags'); + +test_clean_jobserver_makeflags('-a --jobserver-fds=103,104 -j -b', + '-a -b', + 'clean makeflags'); + +test_clean_jobserver_makeflags(' --jobserver-fds=1,2 -j ', + undef, + 'unset makeflags'); + +test_clean_jobserver_makeflags('-a -j -b', + '-a -j -b', + 'clean makeflags does not remove -j'); + +test_clean_jobserver_makeflags('-a --jobs -b', + '-a --jobs -b', + 'clean makeflags does not remove --jobs'); + +test_clean_jobserver_makeflags('-j6', + '-j6', + 'clean makeflags does not remove -j6'); + +test_clean_jobserver_makeflags('-a -j6 --jobs=7', + '-a -j6 --jobs=7', + 'clean makeflags does not remove -j or --jobs'); + +test_clean_jobserver_makeflags('-j6 --jobserver-fds=103,104 --jobs=8', + '-j6 --jobs=8', + 'jobserver options removed'); + +test_clean_jobserver_makeflags('-j6 --jobserver-auth=103,104 --jobs=8', + '-j6 --jobs=8', + 'jobserver options removed'); + +sub test_clean_jobserver_makeflags { + my ($orig, $expected, $test) = @_; + + local $ENV{MAKEFLAGS} = $orig; + clean_jobserver_makeflags(); + is($ENV{MAKEFLAGS}, $expected, $test); +} + diff --git a/t/buildsystems/03-bs-auto-buildable.t b/t/buildsystems/03-bs-auto-buildable.t new file mode 100755 index 0000000..6516622 --- /dev/null +++ b/t/buildsystems/03-bs-auto-buildable.t @@ -0,0 +1,218 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 192; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Dh_Buildsystems; + +my @STEPS = qw(configure build test install clean); + +### Test check_auto_buildable() of each buildsystem +sub test_check_auto_buildable { + my ($bs, $config, $expected) = @_; + + if (! ref $expected) { + my %all_steps; + $all_steps{$_} = $expected foreach (@STEPS); + $expected = \%all_steps; + } + for my $step (@STEPS) { + my $e = 0; + if (exists $expected->{$step}) { + $e = $expected->{$step}; + } elsif (exists $expected->{default}) { + $e = $expected->{default}; + } + is( $bs->check_auto_buildable($step), $e, + $bs->NAME() . "($config): check_auto_buildable($step) == $e" ); + } +} + +sub test_autoselection { + my ($testname, $expected, %args) = @_; + for my $step (@STEPS) { + my $bs = load_buildsystem({'enable-thirdparty' => 0}, $step, @_); + my $e = $expected; + $e = $expected->{$step} if ref $expected; + if (defined $bs) { + is( $bs->NAME(), $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') ); + } + else { + is ( undef, $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') ); + } + &{$args{"code_$step"}}() if exists $args{"code_$step"}; + } +} + +my $TEMP_DIR = tempdir('tmp.XXXXXXX', CLEANUP => 1); +my $sourcedir = "${TEMP_DIR}/source"; +my $builddir = "${TEMP_DIR}/build"; +my %options = ( + 'builddir' => $builddir, + 'sourcedir' => $sourcedir, +); +make_path($sourcedir, $builddir); +use Config; +my $libpath = $ENV{AUTOPKGTEST_TMP} ? $Config{vendorlib} : "$Test::DH::ROOT_DIR/lib"; +my @bs = load_all_buildsystems([ $libpath ], %options); +my %bs; +my @names = map { $_->NAME() } @bs; + +ok(@Debian::Debhelper::Dh_Buildsystems::BUILDSYSTEMS >= 1, "some build systems are built in" ); +is_deeply( \@names, \@Debian::Debhelper::Dh_Buildsystems::BUILDSYSTEMS, "load_all_buildsystems() loads all built-in buildsystems" ); + +# check_auto_buildable() fails with numeric 0 +for my $bs (@bs) { + test_check_auto_buildable($bs, "fails with numeric 0", 0); + $bs{$bs->NAME()} = $bs; +} + +run_auto_buildable_tests(); + +remove_tree($sourcedir, $builddir); +make_path($sourcedir, $builddir); + +run_autoselection_tests(); + + +#### Bulk of test code #### + +sub run_auto_buildable_tests { + create_empty_file("${sourcedir}/configure", 0755); + test_check_auto_buildable($bs{autoconf}, "configure", { configure => 1, clean => 1 }); + rm_files("${sourcedir}/configure"); + + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_check_auto_buildable($bs{'cmake+makefile'}, "CMakeLists.txt", { configure => 1, clean => 1 }); + rm_files("${sourcedir}/CMakeLists.txt"); + + create_empty_file("${sourcedir}/Makefile.PL"); + test_check_auto_buildable($bs{perl_makemaker}, "Makefile.PL", { configure => 1 }); + rm_files("${sourcedir}/Makefile.PL"); + + create_empty_file("${sourcedir}/meson.build"); + test_check_auto_buildable($bs{'meson+ninja'}, "meson.build", { configure => 1, clean => 1 }); + # Leave meson.build + + create_empty_file("${builddir}/build.ninja"); + test_check_auto_buildable($bs{ninja}, "build.ninja", { configure => 1, build => 1, clean => 1, install => 1, test => 1 }); + # Leave ninja.build + + # Meson + ninja + test_check_auto_buildable($bs{'meson+ninja'}, "meson.build+build.ninja", { configure => 1, build => 1, clean => 1, install => 1, test => 1 }); + rm_files("${sourcedir}/meson.build", "${builddir}/build.ninja"); + + # With Makefile + create_empty_file("$builddir/Makefile"); + test_check_auto_buildable($bs{makefile}, "Makefile", 1); + + # ... +autoconf + create_empty_file("${sourcedir}/configure", 0755); + test_check_auto_buildable($bs{autoconf}, "configure+Makefile", { configure => 1, test => 1, build => 1, install => 1, clean => 1 }); + rm_files("${sourcedir}/configure"); + + # ... +cmake + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_check_auto_buildable($bs{'cmake+makefile'}, "CMakeLists.txt+Makefile", 1); + create_empty_file("$builddir/CMakeCache.txt"); # strong evidence that cmake was run + test_check_auto_buildable($bs{'cmake+makefile'}, "CMakeCache.txt+Makefile", 2); + rm_files("${builddir}/Makefile", "${sourcedir}/CMakeLists.txt"); + + # Makefile.PL forces in-source + #(see note in check_auto_buildable() why always 1 here) + create_empty_file("${sourcedir}/Makefile.PL"); + create_empty_file("${sourcedir}/Makefile"); + test_check_auto_buildable($bs{perl_makemaker}, "Makefile.PL+Makefile", 1); + rm_files("${sourcedir}/Makefile.PL", "${sourcedir}/Makefile"); + + # Perl Build.PL - handles always + test_check_auto_buildable($bs{perl_build}, "no Build.PL", 0); + create_empty_file("${sourcedir}/Build.PL"); + test_check_auto_buildable($bs{perl_build}, "Build.PL", { configure => 1 }); + create_empty_file("${sourcedir}/Build"); # forced in source + test_check_auto_buildable($bs{perl_build}, "Build.PL+Build", 1); + rm_files("${sourcedir}/Build.PL", "${sourcedir}/Build"); + + # Python Distutils + test_check_auto_buildable($bs{python_distutils}, "no setup.py", 0); + create_empty_file("${sourcedir}/setup.py"); + test_check_auto_buildable($bs{python_distutils}, "setup.py", 1); + rm_files("${sourcedir}/setup.py"); +} + +sub run_autoselection_tests { + # Auto-select nothing when no supported build system can be found + # (see #557006). + test_autoselection("auto-selects nothing", undef, %options); + + # Autoconf + create_empty_file("${sourcedir}/configure", 0755); + create_empty_file("${builddir}/Makefile"); + test_autoselection("autoconf", + { configure => "autoconf", build => "autoconf", + test => "autoconf", install => "autoconf", + clean => "autoconf" + }, %options); + rm_files("${sourcedir}/configure", "${builddir}/Makefile"); + + + # Perl Makemaker (build, test, clean fail with builddir set [not supported]) + create_empty_file("${sourcedir}/Makefile.PL"); + create_empty_file("${sourcedir}/Makefile"); + test_autoselection("perl_makemaker", "perl_makemaker", %options); + rm_files("${sourcedir}/Makefile.PL", "${sourcedir}/Makefile"); + + + # Makefile + create_empty_file("$builddir/Makefile"); + test_autoselection("makefile", "makefile", %options); + rm_files("$builddir/Makefile"); + + # Python Distutils + create_empty_file("${sourcedir}/setup.py"); + test_autoselection("python_distutils", "python_distutils", %options); + rm_files("${sourcedir}/setup.py"); + + # Perl Build + create_empty_file("${sourcedir}/Build.PL"); + create_empty_file("${sourcedir}/Build"); + test_autoselection("perl_build", "perl_build", %options); + rm_files("${sourcedir}/Build.PL", "${sourcedir}/Build"); + + # CMake + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_autoselection("cmake without CMakeCache.txt", + { configure => "cmake+makefile", build => "makefile", + test => "makefile", install => "makefile", + clean => "makefile" + }, + %options, + code_configure => sub { + create_empty_file("$builddir/Makefile"); + }); + rm_files("${sourcedir}/CMakeLists.txt", "$builddir/Makefile"); + + create_empty_file("${sourcedir}/CMakeLists.txt"); + test_autoselection("cmake with CMakeCache.txt", + "cmake+makefile", + %options, + code_configure => sub { + create_empty_file("$builddir/Makefile"); + create_empty_file("$builddir/CMakeCache.txt"); + }); + rm_files("${sourcedir}/CMakeLists.txt", "$builddir/Makefile", "$builddir/CMakeCache.txt"); + + create_empty_file("${sourcedir}/CMakeLists.txt"); + create_empty_file("$builddir/Makefile"); + test_autoselection("cmake and existing Makefile", "makefile", %options); + rm_files("${sourcedir}/CMakeLists.txt", "$builddir/Makefile"); + +}; + diff --git a/t/buildsystems/04-dh_auto_do_autoconf.t b/t/buildsystems/04-dh_auto_do_autoconf.t new file mode 100755 index 0000000..a1346e4 --- /dev/null +++ b/t/buildsystems/04-dh_auto_do_autoconf.t @@ -0,0 +1,88 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More tests => 31; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Dh_Buildsystems; + +# Let the tests to be run from anywhere but currect directory +# is expected to be the one where this test lives in. +chdir File::Basename::dirname($0) or die "Unable to chdir to ".File::Basename::dirname($0); + +$Test::DH::TEST_DH_COMPAT = 10; + +# Build the autoconf test package +sub dh_auto_do_autoconf { + my ($sourcedir, $builddir, %args) = @_; + + my (@lines, @extra_args); + my $buildpath = $sourcedir; + my @dh_auto_args = ("-D", $sourcedir); + my $dh_auto_str = "-D $sourcedir"; + if ($builddir) { + push @dh_auto_args, "-B", $builddir; + $dh_auto_str .= " -B $builddir"; + $buildpath = $builddir; + } + + my $do_dh_auto = sub { + my ($step) = @_; + my @extra_args; + my $extra_str = ""; + if (exists $args{"${step}_args"}) { + push @extra_args, @{$args{"${step}_args"}}; + $extra_str .= " $_" foreach (@extra_args); + } + ok(run_dh_tool({ 'quiet' => 1 }, "dh_auto_${step}", @dh_auto_args, '--', @extra_args), + "dh_auto_$step $dh_auto_str$extra_str"); + return @extra_args; + }; + + @extra_args = &$do_dh_auto('configure'); + ok ( -f "$buildpath/Makefile", "$buildpath/Makefile exists" ); + @lines=(); + if ( ok(open(FILE, '<', "$buildpath/stamp_configure"), "$buildpath/stamp_configure exists") ) { + @lines = @{readlines(\*FILE)}; + close(FILE); + } + is_deeply( \@lines, \@extra_args, "$buildpath/stamp_configure contains extra args" ); + + &$do_dh_auto('build'); + ok ( -f "$buildpath/stamp_build", "$buildpath/stamp_build exists" ); + &$do_dh_auto('test'); + @lines=(); + if ( ok(open(FILE, '<', "$buildpath/stamp_test"), "$buildpath/stamp_test exists") ) { + @lines = @{readlines(\*FILE)}; + close(FILE); + } + is_deeply( \@lines, [ "VERBOSE=1" ], + "$buildpath/stamp_test contains VERBOSE=1" ); + &$do_dh_auto('install'); + @lines=(); + if ( ok(open(FILE, '<', "$buildpath/stamp_install"), "$buildpath/stamp_install exists") ) { + @lines = @{readlines(\*FILE)}; + close(FILE); + } + is_deeply( \@lines, [ "DESTDIR=".Cwd::getcwd()."/debian/testpackage" ], + "$buildpath/stamp_install contains DESTDIR" ); + &$do_dh_auto('clean'); + if ($builddir) { + ok ( ! -e "$buildpath", "builddir $buildpath was removed" ); + } + else { + ok ( ! -e "$buildpath/Makefile" && ! -e "$buildpath/stamp_configure", "Makefile and stamps gone" ); + } + ok ( -x "$sourcedir/configure", "configure script renamins after clean" ); +} + +dh_auto_do_autoconf('autoconf'); +dh_auto_do_autoconf('autoconf', 'bld/dir', configure_args => [ "--extra-autoconf-configure-arg" ]); +ok ( ! -e 'bld', "bld got deleted too" ); + diff --git a/t/buildsystems/05-load-build-system.t b/t/buildsystems/05-load-build-system.t new file mode 100755 index 0000000..23aed9f --- /dev/null +++ b/t/buildsystems/05-load-build-system.t @@ -0,0 +1,55 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Cwd; +use Test::More tests => 3; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use Test::DH; +use File::Path qw(remove_tree make_path); +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Buildsystem; + +my $DIR = dirname($0); +my $SCRIPT = './load-bs.pl'; # relative to $DIR +my $BS_CWD = Cwd::realpath($DIR) or error("cannot resolve ${DIR}: $!"); +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; +my $bs = $BS_CLASS->new(); +my $default_builddir = $bs->DEFAULT_BUILD_DIRECTORY(); +delete($ENV{'TEST_DH_SYSTEM'}); +delete($ENV{'TEST_DH_STEP'}); + +# NOTE: disabling parallel building explicitly (it might get automatically +# enabled if run under dpkg-buildpackage -jX) to make output deterministic. +is_deeply( try_load_bs(undef, 'configure', '--builddirectory=autoconf/bld dir', '--sourcedirectory', + 'autoconf', '--max-parallel=1'), + [ 'NAME=autoconf', 'builddir=autoconf/bld dir', "cwd=$BS_CWD", 'makecmd=make', 'parallel=1', 'sourcedir=autoconf' ], + "autoconf autoselection and sourcedir/builddir" ); + +is_deeply( try_load_bs('autoconf', 'build', '-Sautoconf', '-D', 'autoconf', '--max-parallel=1'), + [ 'NAME=autoconf', 'builddir=undef', "cwd=$BS_CWD", 'makecmd=make', 'parallel=1', 'sourcedir=autoconf' ], + "forced autoconf and sourcedir" ); + +is_deeply( try_load_bs('autoconf', 'build', '-B', '-Sautoconf', '--max-parallel=1'), + [ 'NAME=autoconf', "builddir=$default_builddir", "cwd=$BS_CWD", 'makecmd=make', 'parallel=1', 'sourcedir=.' ], + "forced autoconf and default build directory" ); + +sub try_load_bs { + my ($system, $step, @params) = @_; + my @lines; + my $pid = open(my $fd, '-|') // die("fork: $!"); + + if (not $pid) { + chdir($DIR) or die("chdir($DIR): $!"); + $ENV{'TEST_DH_SYSTEM'} = $system if defined($system); + $ENV{'TEST_DH_STEP'} = $step if defined($step); + exec($^X, $SCRIPT, @params); + } + @lines = map { chomp; $_ } <$fd>; + close($fd); # Ignore error + return \@lines; +} + diff --git a/t/buildsystems/06-buildsystem-mkdir-rmdir.t b/t/buildsystems/06-buildsystem-mkdir-rmdir.t new file mode 100755 index 0000000..c13b253 --- /dev/null +++ b/t/buildsystems/06-buildsystem-mkdir-rmdir.t @@ -0,0 +1,51 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Cwd; +use Test::More tests => 6; + +use File::Temp qw(tempdir); +use File::Basename qw(dirname); +use lib dirname(dirname(__FILE__)); +use File::Path qw(make_path); +use Test::DH; +use Debian::Debhelper::Dh_Lib qw(!dirname); +use Debian::Debhelper::Buildsystem; + +chdir(dirname($0)) or die("chdir: $!"); +my $TEMP_DIR = tempdir('tmp.XXXXXXX', CLEANUP => 1); +my $sourcedir = $TEMP_DIR; +my $builddir = "${TEMP_DIR}/build"; +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; + +# Tests + +do_rmdir_builddir($sourcedir, $builddir); +ok ( ! -e $builddir, "testing rmdir_builddir() 1: builddir parent '$builddir' deleted" ); +ok ( -d $sourcedir, "testing rmdir_builddir() 1: sourcedir '$sourcedir' remains" ); + +$builddir = "$sourcedir/bld"; +do_rmdir_builddir($sourcedir, "$builddir/dir"); +ok ( ! -e $builddir, "testing rmdir_builddir() 2: builddir parent '$builddir' deleted" ); +ok ( -d $sourcedir, "testing rmdir_builddir() 2: sourcedir '$sourcedir' remains" ); + +$builddir = "$sourcedir/bld"; + +make_path($builddir, "$builddir/dir"); +create_empty_file("$builddir/afile"); +create_empty_file("$builddir/dir/afile2"); +do_rmdir_builddir($sourcedir, "$builddir/dir"); +ok ( ! -e "$builddir/dir", "testing rmdir_builddir() 3: builddir '$builddir/dir' not empty, but deleted" ); +ok ( -d $builddir, "testing rmdir_builddir() 3: builddir parent '$builddir' not empty, remains" ); + + +### Test Buildsystem::rmdir_builddir() +sub do_rmdir_builddir { + my ($sourcedir, $builddir) = @_; + my $system; + $system = $BS_CLASS->new(builddir => $builddir, sourcedir => $sourcedir); + $system->mkdir_builddir(); + $system->rmdir_builddir(); +} + diff --git a/t/buildsystems/autoconf/configure b/t/buildsystems/autoconf/configure new file mode 100755 index 0000000..5039783 --- /dev/null +++ b/t/buildsystems/autoconf/configure @@ -0,0 +1,84 @@ +#!/usr/bin/perl + +# Emulate autoconf behaviour and do some checks + +use strict; +use warnings; + +my @OPTIONS=qw( + ^--build=.*$ + ^--prefix=/usr$ + ^--includedir=\$\{prefix\}/include$ + ^--mandir=\$\{prefix\}/share/man$ + ^--infodir=\$\{prefix\}/share/info$ + ^--sysconfdir=/etc$ + ^--localstatedir=/var$ + ^--libdir=\$\{prefix\}/lib/.*$ + ^--disable-option-checking$ + ^--disable-silent-rules$ + ^--disable-maintainer-mode$ + ^--disable-dependency-tracking$ +); + +# Not always passed (e.g. --libexecdir is skipped in compat 12) +my @OPTIONAL_ARGUMENTS = qw( + ^--libexecdir=\$\{prefix\}/lib/.*$ +); + +# Verify if all command line arguments were passed +my @options = map { { regex => qr/$_/, + str => $_, + found => 0 } } @OPTIONS; +push(@options, map { { regex => qr/$_/, + str => $_, + found => 1 } } @OPTIONAL_ARGUMENTS); +my @extra_args; +ARGV_LOOP: foreach my $arg (@ARGV) { + foreach my $opt (@options) { + if ($arg =~ $opt->{regex}) { + $opt->{found} = 1; + next ARGV_LOOP; + } + } + # Extra / unrecognized argument + push @extra_args, $arg; +} + +my @notfound = grep { ! $_->{found} and $_ } @options; +if (@notfound) { + print STDERR "Error: the following default options were NOT passed\n"; + print STDERR " ", $_->{str}, "\n" foreach (@notfound); + exit 1; +} + +# Create a simple Makefile +open(MAKEFILE, ">", "Makefile"); +print MAKEFILE <<EOF; +CONFIGURE := $0 +all: stamp_configure \$(CONFIGURE) + \@echo Package built > stamp_build + +# Tests if dh_auto_test executes 'check' target if 'test' does not exist +check: \$(CONFIGURE) stamp_build + \@echo VERBOSE=\$(VERBOSE) > stamp_test + +install: stamp_build + \@echo DESTDIR=\$(DESTDIR) > stamp_install + +# Tests whether dh_auto_clean executes distclean but does not touch +# this target +clean: + echo "This should not have been executed" >&2 && exit 1 + +distclean: + \@rm -f stamp_* Makefile + +.PHONY: all check install clean distclean +EOF +close MAKEFILE; + +open(STAMP, ">", "stamp_configure"); +print STAMP $_, "\n" foreach (@extra_args); +close STAMP; + +exit 0; diff --git a/t/buildsystems/buildsystem_tests.t b/t/buildsystems/buildsystem_tests.t new file mode 100755 index 0000000..eaa2380 --- /dev/null +++ b/t/buildsystems/buildsystem_tests.t @@ -0,0 +1,293 @@ +#!/usr/bin/perl + +use Test::More tests => 85; + +use strict; +use warnings; +use IPC::Open2; +use Cwd (); +use File::Temp qw(tempfile); +use File::Basename (); + +# Let the tests to be run from anywhere but currect directory +# is expected to be the one where this test lives in. +chdir File::Basename::dirname($0) or die "Unable to chdir to ".File::Basename::dirname($0); + +use_ok( 'Debian::Debhelper::Dh_Lib' ); +use_ok( 'Debian::Debhelper::Buildsystem' ); +use_ok( 'Debian::Debhelper::Dh_Buildsystems' ); + +my $TOPDIR = $ENV{AUTOPKGTEST_TMP} ? '/usr/bin' : '../..'; +my @STEPS = qw(configure build test install clean); +my $BS_CLASS = 'Debian::Debhelper::Buildsystem'; + +my ($bs); +my ($tmp, @tmp, %tmp); +my ($default_builddir); + +### Common subs #### +sub readlines { + my $h=shift; + my @lines = <$h>; + close $h; + chop @lines; + return \@lines; +} + +sub process_stdout { + my ($cmdline, $stdin) = @_; + my ($reader, $writer); + + my $pid = open2($reader, $writer, $cmdline) or die "Unable to exec $cmdline"; + print $writer $stdin if $stdin; + close $writer; + waitpid($pid, 0); + $? = $? >> 8; # exit status + return readlines($reader); +} + +sub write_debian_rules { + my $contents=shift; + my $backup; + + if (-f "debian/rules") { + (undef, $backup) = tempfile(DIR => ".", OPEN => 0); + rename "debian/rules", $backup; + } + # Write debian/rules if requested + if ($contents) { + open(my $f, ">", "debian/rules"); + print $f $contents;; + close($f); + chmod 0755, "debian/rules"; + } + return $backup; +} + +### Test Buildsystem class path API methods under different configurations +sub test_buildsystem_paths_api { + my ($bs, $config, $expected)=@_; + + my $api_is = sub { + my ($got, $name)=@_; + is( $got, $expected->{$name}, "paths API ($config): $name") + }; + + &$api_is( $bs->get_sourcedir(), 'get_sourcedir()' ); + &$api_is( $bs->get_sourcepath("a/b"), 'get_sourcepath(a/b)' ); + &$api_is( $bs->get_builddir(), 'get_builddir()' ); + &$api_is( $bs->get_buildpath(), 'get_buildpath()' ); + &$api_is( $bs->get_buildpath("a/b"), 'get_buildpath(a/b)' ); + &$api_is( $bs->get_source_rel2builddir(), 'get_source_rel2builddir()' ); + &$api_is( $bs->get_source_rel2builddir("a/b"), 'get_source_rel2builddir(a/b)' ); + &$api_is( $bs->get_build_rel2sourcedir(), 'get_build_rel2sourcedir()' ); + &$api_is( $bs->get_build_rel2sourcedir("a/b"), 'get_build_rel2sourcedir(a/b)' ); +} + +# Defaults +$bs = $BS_CLASS->new(); +$default_builddir = $bs->DEFAULT_BUILD_DIRECTORY(); +%tmp = ( + "get_sourcedir()" => ".", + "get_sourcepath(a/b)" => "./a/b", + "get_builddir()" => undef, + "get_buildpath()" => ".", + "get_buildpath(a/b)" => "./a/b", + "get_source_rel2builddir()" => ".", + "get_source_rel2builddir(a/b)" => "./a/b", + "get_build_rel2sourcedir()" => ".", + "get_build_rel2sourcedir(a/b)" => "./a/b", +); +test_buildsystem_paths_api($bs, "no builddir, no sourcedir", \%tmp); + +# builddir=bld/dir +$bs = $BS_CLASS->new(builddir => "bld/dir"); +%tmp = ( + "get_sourcedir()" => ".", + "get_sourcepath(a/b)" => "./a/b", + "get_builddir()" => "bld/dir", + "get_buildpath()" => "bld/dir", + "get_buildpath(a/b)" => "bld/dir/a/b", + "get_source_rel2builddir()" => "../..", + "get_source_rel2builddir(a/b)" => "../../a/b", + "get_build_rel2sourcedir()" => "bld/dir", + "get_build_rel2sourcedir(a/b)" => "bld/dir/a/b", +); +test_buildsystem_paths_api($bs, "builddir=bld/dir, no sourcedir", \%tmp); + +# Default builddir, sourcedir=autoconf +$bs = $BS_CLASS->new(builddir => undef, sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => "$default_builddir", + "get_buildpath()" => "$default_builddir", + "get_buildpath(a/b)" => "$default_builddir/a/b", + "get_source_rel2builddir()" => "../autoconf", + "get_source_rel2builddir(a/b)" => "../autoconf/a/b", + "get_build_rel2sourcedir()" => "../$default_builddir", + "get_build_rel2sourcedir(a/b)" => "../$default_builddir/a/b", +); +test_buildsystem_paths_api($bs, "default builddir, sourcedir=autoconf", \%tmp); + +# sourcedir=autoconf (builddir should be dropped) +$bs = $BS_CLASS->new(builddir => "autoconf", sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => undef, + "get_buildpath()" => "autoconf", + "get_buildpath(a/b)" => "autoconf/a/b", + "get_source_rel2builddir()" => ".", + "get_source_rel2builddir(a/b)" => "./a/b", + "get_build_rel2sourcedir()" => ".", + "get_build_rel2sourcedir(a/b)" => "./a/b", +); +test_buildsystem_paths_api($bs, "no builddir, sourcedir=autoconf", \%tmp); + +# Prefer out of source tree building when +# sourcedir=builddir=autoconf hence builddir should be dropped. +$bs->prefer_out_of_source_building(builddir => "autoconf"); +test_buildsystem_paths_api($bs, "out of source preferred, sourcedir=builddir", \%tmp); + +# builddir=bld/dir, sourcedir=autoconf. Should be the same as sourcedir=autoconf. +$bs = $BS_CLASS->new(builddir => "bld/dir", sourcedir => "autoconf"); +$bs->enforce_in_source_building(); +test_buildsystem_paths_api($bs, "in source enforced, sourcedir=autoconf", \%tmp); + +# builddir=../bld/dir (relative to the curdir) +$bs = $BS_CLASS->new(builddir => "bld/dir/", sourcedir => "autoconf"); +%tmp = ( + "get_sourcedir()" => "autoconf", + "get_sourcepath(a/b)" => "autoconf/a/b", + "get_builddir()" => "bld/dir", + "get_buildpath()" => "bld/dir", + "get_buildpath(a/b)" => "bld/dir/a/b", + "get_source_rel2builddir()" => "../../autoconf", + "get_source_rel2builddir(a/b)" => "../../autoconf/a/b", + "get_build_rel2sourcedir()" => "../bld/dir", + "get_build_rel2sourcedir(a/b)" => "../bld/dir/a/b", +); +test_buildsystem_paths_api($bs, "builddir=../bld/dir, sourcedir=autoconf", \%tmp); + +#### Test parallel building and related options / routines +@tmp = ( $ENV{MAKEFLAGS}, $ENV{DEB_BUILD_OPTIONS} ); + + +# Test parallel building with makefile build system. +$ENV{MAKEFLAGS} = ""; +$ENV{DEB_BUILD_OPTIONS} = ""; + +sub do_parallel_mk { + my $dh_opts=shift || ""; + my $make_opts=shift || ""; + return process_stdout( + "LANG=C LC_ALL=C LC_MESSAGES=C $TOPDIR/dh_auto_build -Smakefile $dh_opts " . + "-- -s -f parallel.mk $make_opts 2>&1 >/dev/null", ""); +} + +sub test_isnt_parallel { + my ($got, $desc) = @_; + my @makemsgs = grep /^make[\d\[\]]*:/, @$got; + if (@makemsgs) { + like( $makemsgs[0], qr/Error 10/, $desc ); + } + else { + ok( scalar(@makemsgs) > 0, $desc ); + } +} + +sub test_is_parallel { + my ($got, $desc) = @_; + is_deeply( $got, [] , $desc ); + is( $?, 0, "(exit status=0) $desc"); +} + + +test_isnt_parallel( do_parallel_mk(), + "No parallel by default" ); +test_isnt_parallel( do_parallel_mk("parallel"), + "No parallel by default with --parallel" ); +test_isnt_parallel( do_parallel_mk("--max-parallel=5"), + "No parallel by default with --max-parallel=5" ); + +$ENV{DEB_BUILD_OPTIONS}="parallel=5"; +{ + local $ENV{DH_COMPAT} = 9; + # compat 9 is not parallel by default + test_isnt_parallel( do_parallel_mk(), + "DEB_BUILD_OPTIONS=parallel=5 without parallel options [c9]" ); +} + +# compat 10+ are parallel by default +test_is_parallel( do_parallel_mk(), + "DEB_BUILD_OPTIONS=parallel=5 without parallel options [current compat]" ); +test_is_parallel( do_parallel_mk("--parallel"), + "DEB_BUILD_OPTIONS=parallel=5 with --parallel" ); +test_is_parallel( do_parallel_mk("--max-parallel=2"), + "DEB_BUILD_OPTIONS=parallel=5 with --max-parallel=2" ); +test_isnt_parallel( do_parallel_mk("--max-parallel=1"), + "DEB_BUILD_OPTIONS=parallel=5 with --max-parallel=1" ); +test_isnt_parallel( do_parallel_mk("--no-parallel"), + "DEB_BUILD_OPTIONS=parallel=5 with --no-parallel" ); + +$ENV{MAKEFLAGS} = "--jobserver-fds=105,106 -j"; +$ENV{DEB_BUILD_OPTIONS}=""; +test_isnt_parallel( do_parallel_mk(), + "makefile.pm (no parallel): no make warnings about unavailable jobserver" ); +$ENV{DEB_BUILD_OPTIONS}="parallel=5"; +test_is_parallel( do_parallel_mk("--parallel"), + "DEB_BUILD_OPTIONS=parallel=5: no make warnings about unavail parent jobserver" ); + +$ENV{MAKEFLAGS} = "-j2"; +$ENV{DEB_BUILD_OPTIONS}=""; +test_isnt_parallel( do_parallel_mk(), + "MAKEFLAGS=-j2: dh_auto_build ignores MAKEFLAGS" ); +test_isnt_parallel( do_parallel_mk("--max-parallel=1"), + "MAKEFLAGS=-j2 with --max-parallel=1: dh_auto_build enforces -j1" ); + +# Test dh dpkg-buildpackage -jX detection +sub do_rules_for_parallel { + my $cmdline=shift || ""; + my $stdin=shift || ""; + return process_stdout("LANG=C LC_ALL=C LC_MESSAGES=C PATH=$TOPDIR:\$PATH " . + "make -f - $cmdline 2>&1 >/dev/null", $stdin); +} + +doit("ln", "-sf", "parallel.mk", "Makefile"); + +# Test if dh+override+$(MAKE) legacy punctuation hack work as before +$ENV{MAKEFLAGS} = "-j5"; +$ENV{DEB_BUILD_OPTIONS} = "parallel=5"; + +$tmp = write_debian_rules(<<'EOF'); +#!/usr/bin/make -f +export DEB_RULES_REQUIRES_ROOT:=no +override_dh_auto_build: + $(MAKE) +%: + @dh_clean > /dev/null 2>&1 + @+dh $@ --buildsystem=makefile --without autoreconf 2>/dev/null + @dh_clean > /dev/null 2>&1 +EOF +test_is_parallel( do_rules_for_parallel("build", "include debian/rules"), + "legacy punctuation hacks: +dh, override with \$(MAKE)" ); +unlink "debian/rules"; + +if (defined $tmp) { + rename($tmp, "debian/rules"); +} +else { + unlink("debian/rules"); +} + +# Clean up after parallel testing +END { + system("rm", "-f", "Makefile"); +} +$ENV{MAKEFLAGS} = $tmp[0] if defined $tmp[0]; +$ENV{DEB_BUILD_OPTIONS} = $tmp[1] if defined $tmp[1]; + +END { + system("$TOPDIR/dh_clean"); +} diff --git a/t/buildsystems/debian/changelog b/t/buildsystems/debian/changelog new file mode 100644 index 0000000..f902d89 --- /dev/null +++ b/t/buildsystems/debian/changelog @@ -0,0 +1,5 @@ +testpackage (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Test <testing@nowhere> Tue, 09 Jun 2009 15:35:32 +0300 diff --git a/t/buildsystems/debian/control b/t/buildsystems/debian/control new file mode 100644 index 0000000..9c3134b --- /dev/null +++ b/t/buildsystems/debian/control @@ -0,0 +1,12 @@ +Source: testsrcpackage +Section: devel +Priority: optional +Maintainer: Test <testing@nowhere> +Standards-Version: 3.8.1 +Build-Depends: debhelper-compat (= 12) +Rules-Requires-Root: no + +Package: testpackage +Architecture: all +Description: short description + Long description diff --git a/t/buildsystems/load-bs.pl b/t/buildsystems/load-bs.pl new file mode 100755 index 0000000..aeb5ea8 --- /dev/null +++ b/t/buildsystems/load-bs.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Debian::Debhelper::Dh_Buildsystems; + +buildsystems_init(); +my $system = $ENV{'TEST_DH_SYSTEM'}; +my $step = $ENV{'TEST_DH_STEP'}; +my $bs = load_buildsystem($system, $step); +if (defined $bs) { + print 'NAME=', $bs->NAME(), "\n"; + print $_, "=", (defined $bs->{$_}) ? $bs->{$_} : 'undef', "\n" + foreach (sort keys %$bs); +} + diff --git a/t/buildsystems/parallel.mk b/t/buildsystems/parallel.mk new file mode 100644 index 0000000..3e0d201 --- /dev/null +++ b/t/buildsystems/parallel.mk @@ -0,0 +1,21 @@ +all: FIRST SECOND + +TMPFILE ?= $(CURDIR)/parallel.mk.lock + +rmtmpfile: + @rm -f "$(TMPFILE)" + +FIRST: rmtmpfile + @c=0; \ + while [ $$c -le 5 ] && \ + ([ ! -e "$(TMPFILE)" ] || [ "`cat "$(TMPFILE)"`" != "SECOND" ]); do \ + c=$$(($$c+1)); \ + sleep 0.1; \ + done; \ + rm -f "$(TMPFILE)"; \ + if [ $$c -gt 5 ]; then exit 10; else exit 0; fi + +SECOND: rmtmpfile + @echo $@ > "$(TMPFILE)" + +.PHONY: all FIRST SECOND rmtmpfile |