]> git.donarmstrong.com Git - debhelper.git/blob - t/buildsystems/buildsystem_tests
487fd2bef6d2163c7db4418ced71533fd1c94ae7
[debhelper.git] / t / buildsystems / buildsystem_tests
1 #!/usr/bin/perl
2
3 use Test::More tests => 292;
4
5 use strict;
6 use warnings;
7 use IPC::Open2;
8 use Cwd ();
9 use File::Temp qw(tempfile tempdir);
10 use File::Basename ();
11
12 # Let the tests to be run from anywhere but currect directory
13 # is expected to be the one where this test lives in.
14 chdir File::Basename::dirname($0) or die "Unable to chdir to ".File::Basename::dirname($0);
15
16 use_ok( 'Debian::Debhelper::Dh_Lib' );
17 use_ok( 'Debian::Debhelper::Buildsystem' );
18 use_ok( 'Debian::Debhelper::Dh_Buildsystems' );
19
20 my $TOPDIR = "../..";
21 my @STEPS = qw(configure build test install clean);
22 my $BS_CLASS = 'Debian::Debhelper::Buildsystem';
23
24 my ($bs, @bs, %bs);
25 my ($tmp, @tmp, %tmp);
26 my ($tmpdir, $builddir, $default_builddir);
27
28 ### Common subs ####
29 sub touch {
30         my $file=shift;
31         my $chmod=shift;
32         open FILE, ">", $file and close FILE or die "Unable to touch $file";
33         chmod $chmod, $file if defined $chmod;
34 }
35
36 sub cleandir {
37         my $dir=shift;
38         system ("find", $dir, "-type", "f", "-delete");
39 }
40 sub readlines {
41         my $h=shift;
42         my @lines = <$h>;
43         close $h;
44         chop @lines;
45         return \@lines;
46 }
47
48 sub process_stdout {
49         my ($cmdline, $stdin) = @_;
50         my ($reader, $writer);
51
52         my $pid = open2($reader, $writer, $cmdline) or die "Unable to exec $cmdline";
53         print $writer $stdin if $stdin;
54         close $writer;
55         waitpid($pid, 0);
56         $? = $? >> 8; # exit status
57         return readlines($reader);
58 }
59
60 sub write_debian_rules {
61         my $contents=shift;
62         my $backup;
63
64         if (-f "debian/rules") {
65                 (undef, $backup) = tempfile(DIR => ".", OPEN => 0);
66                 rename "debian/rules", $backup;
67         }
68         # Write debian/rules if requested
69         if ($contents) {
70                 open(my $f, ">", "debian/rules");
71                 print $f $contents;;
72                 close($f);
73                 chmod 0755, "debian/rules";
74         }
75         return $backup;
76 }
77
78 ### Test Buildsystem class API methods
79 is( $BS_CLASS->canonpath("path/to/the/./nowhere/../../somewhere"),
80     "path/to/somewhere", "canonpath no1" );
81 is( $BS_CLASS->canonpath("path/to/../forward/../../somewhere"),
82     "somewhere","canonpath no2" );
83 is( $BS_CLASS->canonpath("path/to/../../../somewhere"),
84     "../somewhere","canonpath no3" );
85 is( $BS_CLASS->canonpath("./"), ".", "canonpath no4" );
86 is( $BS_CLASS->canonpath("/absolute/path/./somewhere/../to/nowhere"),
87     "/absolute/path/to/nowhere", "canonpath no5" );
88 is( $BS_CLASS->_rel2rel("path/my/file", "path/my", "/tmp"),
89     "file", "_rel2rel no1" );
90 is( $BS_CLASS->_rel2rel("path/dir/file", "path/my", "/tmp"),
91     "../dir/file", "_rel2rel no2" );
92 is( $BS_CLASS->_rel2rel("file", "/root/path/my", "/root"),
93     "/root/file", "_rel2rel abs no3" );
94 is( $BS_CLASS->_rel2rel(".", ".", "/tmp"), ".", "_rel2rel no4" );
95 is( $BS_CLASS->_rel2rel("path", "path/", "/tmp"), ".", "_rel2rel no5" );
96 is( $BS_CLASS->_rel2rel("/absolute/path", "anybase", "/tmp"),
97     "/absolute/path", "_rel2rel abs no6");
98 is( $BS_CLASS->_rel2rel("relative/path", "/absolute/base", "/tmp"),
99     "/tmp/relative/path", "_rel2rel abs no7");
100
101 ### Test Buildsystem class path API methods under different configurations
102 sub test_buildsystem_paths_api {
103         my ($bs, $config, $expected)=@_;
104
105         my $api_is = sub {
106                 my ($got, $name)=@_;
107                 is( $got, $expected->{$name}, "paths API ($config): $name")
108         };
109
110         &$api_is( $bs->get_sourcedir(), 'get_sourcedir()' );
111         &$api_is( $bs->get_sourcepath("a/b"), 'get_sourcepath(a/b)' );
112         &$api_is( $bs->get_builddir(), 'get_builddir()' );
113         &$api_is( $bs->get_buildpath(), 'get_buildpath()' );
114         &$api_is( $bs->get_buildpath("a/b"), 'get_buildpath(a/b)' );
115         &$api_is( $bs->get_source_rel2builddir(), 'get_source_rel2builddir()' );
116         &$api_is( $bs->get_source_rel2builddir("a/b"), 'get_source_rel2builddir(a/b)' );
117         &$api_is( $bs->get_build_rel2sourcedir(), 'get_build_rel2sourcedir()' );
118         &$api_is( $bs->get_build_rel2sourcedir("a/b"), 'get_build_rel2sourcedir(a/b)' );
119 }
120
121 # Defaults
122 $bs = $BS_CLASS->new();
123 $default_builddir = $bs->DEFAULT_BUILD_DIRECTORY();
124 %tmp = (
125         "get_sourcedir()" => ".",
126         "get_sourcepath(a/b)" => "./a/b",
127         "get_builddir()" => undef,
128         "get_buildpath()" => ".",
129         "get_buildpath(a/b)" =>  "./a/b",
130         "get_source_rel2builddir()" => ".",
131         "get_source_rel2builddir(a/b)" => "./a/b",
132         "get_build_rel2sourcedir()" => ".",
133         "get_build_rel2sourcedir(a/b)" => "./a/b",
134 );
135 test_buildsystem_paths_api($bs, "no builddir, no sourcedir", \%tmp);
136
137 # builddir=bld/dir
138 $bs = $BS_CLASS->new(builddir => "bld/dir");
139 %tmp = (
140         "get_sourcedir()" => ".",
141         "get_sourcepath(a/b)" => "./a/b",
142         "get_builddir()" => "bld/dir",
143         "get_buildpath()" => "bld/dir",
144         "get_buildpath(a/b)" =>  "bld/dir/a/b",
145         "get_source_rel2builddir()" => "../..",
146         "get_source_rel2builddir(a/b)" => "../../a/b",
147         "get_build_rel2sourcedir()" => "bld/dir",
148         "get_build_rel2sourcedir(a/b)" => "bld/dir/a/b",
149 );
150 test_buildsystem_paths_api($bs, "builddir=bld/dir, no sourcedir", \%tmp);
151
152 # Default builddir, sourcedir=autoconf
153 $bs = $BS_CLASS->new(builddir => undef, sourcedir => "autoconf");
154 %tmp = (
155         "get_sourcedir()" => "autoconf",
156         "get_sourcepath(a/b)" => "autoconf/a/b",
157         "get_builddir()" => "$default_builddir",
158         "get_buildpath()" => "$default_builddir",
159         "get_buildpath(a/b)" =>  "$default_builddir/a/b",
160         "get_source_rel2builddir()" => "../autoconf",
161         "get_source_rel2builddir(a/b)" => "../autoconf/a/b",
162         "get_build_rel2sourcedir()" => "../$default_builddir",
163         "get_build_rel2sourcedir(a/b)" => "../$default_builddir/a/b",
164 );
165 test_buildsystem_paths_api($bs, "default builddir, sourcedir=autoconf", \%tmp);
166
167 # sourcedir=autoconf (builddir should be dropped)
168 $bs = $BS_CLASS->new(builddir => "autoconf", sourcedir => "autoconf");
169 %tmp = (
170         "get_sourcedir()" => "autoconf",
171         "get_sourcepath(a/b)" => "autoconf/a/b",
172         "get_builddir()" => undef,
173         "get_buildpath()" => "autoconf",
174         "get_buildpath(a/b)" =>  "autoconf/a/b",
175         "get_source_rel2builddir()" => ".",
176         "get_source_rel2builddir(a/b)" => "./a/b",
177         "get_build_rel2sourcedir()" => ".",
178         "get_build_rel2sourcedir(a/b)" => "./a/b",
179 );
180 test_buildsystem_paths_api($bs, "no builddir, sourcedir=autoconf", \%tmp);
181
182 # Prefer out of source tree building when
183 # sourcedir=builddir=autoconf hence builddir should be dropped.
184 $bs->prefer_out_of_source_building(builddir => "autoconf");
185 test_buildsystem_paths_api($bs, "out of source prefered, sourcedir=builddir", \%tmp);
186
187 # builddir=bld/dir, sourcedir=autoconf. Should be the same as sourcedir=autoconf.
188 $bs = $BS_CLASS->new(builddir => "bld/dir", sourcedir => "autoconf");
189 $bs->enforce_in_source_building();
190 test_buildsystem_paths_api($bs, "in source enforced, sourcedir=autoconf", \%tmp);
191
192 # builddir=../bld/dir (relative to the curdir)
193 $bs = $BS_CLASS->new(builddir => "bld/dir/", sourcedir => "autoconf");
194 %tmp = (
195         "get_sourcedir()" => "autoconf",
196         "get_sourcepath(a/b)" => "autoconf/a/b",
197         "get_builddir()" => "bld/dir",
198         "get_buildpath()" => "bld/dir",
199         "get_buildpath(a/b)" =>  "bld/dir/a/b",
200         "get_source_rel2builddir()" => "../../autoconf",
201         "get_source_rel2builddir(a/b)" => "../../autoconf/a/b",
202         "get_build_rel2sourcedir()" => "../bld/dir",
203         "get_build_rel2sourcedir(a/b)" => "../bld/dir/a/b",
204 );
205 test_buildsystem_paths_api($bs, "builddir=../bld/dir, sourcedir=autoconf", \%tmp);
206
207 ### Test if all buildsystems can be loaded
208 @bs = load_all_buildsystems([ $INC[0] ]);
209 @tmp = map { $_->NAME() } @bs;
210 ok(@Debian::Debhelper::Dh_Buildsystems::BUILDSYSTEMS >= 1, "some build systems are built in" );
211 is_deeply( \@tmp, \@Debian::Debhelper::Dh_Buildsystems::BUILDSYSTEMS, "load_all_buildsystems() loads all built-in buildsystems" );
212
213 ### Test check_auto_buildable() of each buildsystem
214 sub test_check_auto_buildable {
215         my $bs=shift;
216         my $config=shift;
217         my $expected=shift;
218         my @steps=@_ || @STEPS;
219
220         if (! ref $expected) {
221                 my %all_steps;
222                 $all_steps{$_} = $expected foreach (@steps);
223                 $expected = \%all_steps;
224         }
225         for my $step (@steps) {
226                 my $e = 0;
227                 if (exists $expected->{$step}) {
228                         $e = $expected->{$step};
229                 } elsif (exists $expected->{default}) {
230                         $e = $expected->{default};
231                 }
232                 is( $bs->check_auto_buildable($step), $e,
233                         $bs->NAME() . "($config): check_auto_buildable($step) == $e" );
234         }
235 }
236
237 $tmpdir = tempdir("tmp.XXXXXX");
238 $builddir = "$tmpdir/builddir";
239 mkdir $builddir;
240 %tmp = (
241         builddir => "$tmpdir/builddir",
242         sourcedir => $tmpdir
243 );
244
245 $bs{autoconf} = load_buildsystem("autoconf", undef, %tmp);
246 $bs{cmake} = load_buildsystem("cmake", undef, %tmp);
247 $bs{perl_mm} = load_buildsystem("perl_makemaker", undef, %tmp);
248 $bs = load_buildsystem("makefile", undef, %tmp);
249
250 test_check_auto_buildable($bs{autoconf}, "no configure", 0);
251 test_check_auto_buildable($bs{cmake}, "no CMakeLists.txt", 0);
252 test_check_auto_buildable($bs{perl_mm}, "no Makefile.PL", 0);
253 test_check_auto_buildable($bs, "no Makefile", 0);
254
255 touch "$tmpdir/configure", 0755;
256 test_check_auto_buildable($bs{autoconf}, "configure", { configure => 1 });
257
258 touch "$tmpdir/CMakeLists.txt";
259 test_check_auto_buildable($bs{cmake}, "CMakeLists.txt", 1);
260
261 touch "$tmpdir/Makefile.PL";
262 test_check_auto_buildable($bs{perl_mm}, "Makefile.PL", { configure => 1 });
263
264 # With Makefile
265 touch "$builddir/Makefile";
266 test_check_auto_buildable($bs, "Makefile", 1);
267 test_check_auto_buildable($bs{autoconf}, "configure+Makefile", { configure => 1 });
268 test_check_auto_buildable($bs{cmake}, "CMakeLists.txt+Makefile", 1);
269 touch "$builddir/CMakeCache.txt"; # strong evidence that cmake was run
270 test_check_auto_buildable($bs{cmake}, "CMakeCache.txt+Makefile", 2);
271
272 # Makefile.PL forces in-source
273 #(see note in check_auto_buildable() why always 1 here)
274 unlink "$builddir/Makefile";
275 touch "$tmpdir/Makefile";
276 test_check_auto_buildable($bs{perl_mm}, "Makefile.PL+Makefile", 1);
277
278 # Perl Build.PL - handles always
279 $bs = load_buildsystem("perl_build", undef, %tmp);
280 test_check_auto_buildable($bs, "no Build.PL", 0);
281 touch "$tmpdir/Build.PL";
282 test_check_auto_buildable($bs, "Build.PL", { configure => 1 });
283 touch "$tmpdir/Build"; # forced in source
284 test_check_auto_buildable($bs, "Build.PL+Build", 1);
285
286 # Python Distutils
287 $bs = load_buildsystem("python_distutils", undef, %tmp);
288 test_check_auto_buildable($bs, "no setup.py", 0);
289 touch "$tmpdir/setup.py";
290 test_check_auto_buildable($bs, "setup.py", 1);
291
292 cleandir($tmpdir);
293
294 ### Now test if it can autoselect a proper buildsystem for a typical package
295 sub test_autoselection {
296         my $testname=shift;
297         my $expected=shift;
298         my %args=@_;
299         for my $step (@STEPS) {
300                 my $bs = load_buildsystem(undef, $step, @_);
301                 my $e = $expected;
302                 $e = $expected->{$step} if ref $expected;
303                 if (defined $bs) {
304                         is( $bs->NAME(), $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') );
305                 }
306                 else {
307                         is ( undef, $e, "autoselection($testname): $step=".((defined $e)?$e:'undef') );
308                 }
309                 &{$args{"code_$step"}}() if exists $args{"code_$step"};
310         }
311 }
312
313 # Autoconf
314 touch "$tmpdir/configure", 0755;
315 touch "$builddir/Makefile";
316 test_autoselection("autoconf",
317     { configure => "autoconf", build => "makefile",
318       test => "makefile", install => "makefile", clean => "makefile" }, %tmp);
319 cleandir $tmpdir;
320
321 # Perl Makemaker (build, test, clean fail with builddir set [not supported])
322 touch "$tmpdir/Makefile.PL";
323 touch "$tmpdir/Makefile";
324 test_autoselection("perl_makemaker", "perl_makemaker", %tmp);
325 cleandir $tmpdir;
326
327 # Makefile
328 touch "$builddir/Makefile";
329 test_autoselection("makefile", "makefile", %tmp);
330 cleandir $tmpdir;
331
332 # Python Distutils
333 touch "$tmpdir/setup.py";
334 test_autoselection("python_distutils", "python_distutils", %tmp);
335 cleandir $tmpdir;
336
337 # Perl Build
338 touch "$tmpdir/Build.PL";
339 touch "$tmpdir/Build";
340 test_autoselection("perl_build", "perl_build", %tmp);
341 cleandir $tmpdir;
342
343 # CMake
344 touch "$tmpdir/CMakeLists.txt";
345 $tmp = sub {
346         touch "$builddir/Makefile";
347 };
348 test_autoselection("cmake without CMakeCache.txt",
349         { configure => "cmake", build => "makefile",
350           test => "makefile", install => "makefile", clean => "makefile" }, %tmp,
351         code_configure => $tmp);
352 cleandir $tmpdir;
353
354 touch "$tmpdir/CMakeLists.txt";
355 $tmp = sub {
356         touch "$builddir/Makefile";
357         touch "$builddir/CMakeCache.txt";
358 };
359 test_autoselection("cmake with CMakeCache.txt",
360         "cmake", %tmp, code_configure => $tmp);
361 cleandir $tmpdir;
362
363 touch "$tmpdir/CMakeLists.txt";
364 touch "$builddir/Makefile";
365 test_autoselection("cmake and existing Makefile", "makefile", %tmp);
366 cleandir $tmpdir;
367
368 ### Test Buildsystem::rmdir_builddir()
369 sub do_rmdir_builddir {
370         my $builddir=shift;
371         my $system;
372         $system = $BS_CLASS->new(builddir => $builddir, sourcedir => $tmpdir);
373         $system->mkdir_builddir();
374         $system->rmdir_builddir();
375 }
376
377 $builddir = "$tmpdir/builddir";
378 do_rmdir_builddir($builddir);
379 ok ( ! -e $builddir, "testing rmdir_builddir() 1: builddir parent '$builddir' deleted" );
380 ok ( -d $tmpdir, "testing rmdir_builddir() 1: sourcedir '$tmpdir' remains" );
381
382 $builddir = "$tmpdir/bld";
383 do_rmdir_builddir("$builddir/dir");
384 ok ( ! -e $builddir, "testing rmdir_builddir() 2: builddir parent '$builddir' deleted" );
385 ok ( -d $tmpdir, "testing rmdir_builddir() 2: sourcedir '$tmpdir' remains" );
386
387 $builddir = "$tmpdir/bld";
388 mkdir "$builddir";
389 touch "$builddir/afile";
390 mkdir "$builddir/dir";
391 touch "$builddir/dir/afile2";
392 do_rmdir_builddir("$builddir/dir");
393 ok ( ! -e "$builddir/dir", "testing rmdir_builddir() 3: builddir '$builddir/dir' not empty, but deleted" );
394 ok ( -d $builddir, "testing rmdir_builddir() 3: builddir parent '$builddir' not empty, remains" );
395
396 cleandir $tmpdir;
397
398 ### Test buildsystems_init() and commandline/env argument handling
399 sub get_load_bs_source {
400         my ($system, $step)=@_;
401         $step = (defined $step) ? "'$step'" : 'undef';
402         $system = (defined $system) ? "'$system'" : 'undef';
403
404 return <<EOF;
405 use strict;
406 use warnings;
407 use Debian::Debhelper::Dh_Buildsystems;
408
409 buildsystems_init();
410 my \$bs = load_buildsystem($system, $step);
411 if (defined \$bs) {
412         print 'NAME=', \$bs->NAME(), "\\n";
413         print \$_, "=", (defined \$bs->{\$_}) ? \$bs->{\$_} : 'undef', "\\n"
414             foreach (sort keys \%\$bs);
415 }
416 EOF
417 }
418
419 $tmp = Cwd::getcwd();
420 # NOTE: disabling parallel building explicitly (it might get automatically
421 # enabled if run under dpkg-buildpackage -jX) to make output deterministic.
422 is_deeply( process_stdout("$^X -- - --builddirectory='autoconf/bld dir' --sourcedirectory autoconf --max-parallel=1",
423                           get_load_bs_source(undef, "configure")),
424     [ 'NAME=autoconf', 'builddir=autoconf/bld dir', "cwd=$tmp",  'makecmd=make', 'parallel=1', 'sourcedir=autoconf' ],
425     "autoconf autoselection and sourcedir/builddir" );
426
427 is_deeply( process_stdout("$^X -- - -Sautoconf -D autoconf --max-parallel=1", get_load_bs_source("autoconf", "build")),
428     [ 'NAME=autoconf', 'builddir=undef', "cwd=$tmp", 'makecmd=make', 'parallel=1', 'sourcedir=autoconf' ],
429     "forced autoconf and sourcedir" );
430
431 is_deeply( process_stdout("$^X -- - -B -Sautoconf --max-parallel=1", get_load_bs_source("autoconf", "build")),
432     [ 'NAME=autoconf', "builddir=$default_builddir", "cwd=$tmp", 'makecmd=make', 'parallel=1', 'sourcedir=.' ],
433     "forced autoconf and default build directory" );
434
435 # Build the autoconf test package
436 sub dh_auto_do_autoconf {
437         my $sourcedir=shift;
438         my $builddir=shift;
439         my %args=@_;
440
441         my (@lines, @extra_args);
442         my $buildpath = $sourcedir;
443         my @dh_auto_args = ("-D", $sourcedir);
444         my $dh_auto_str = "-D $sourcedir";
445         if ($builddir) {
446                 push @dh_auto_args, "-B", $builddir;
447                 $dh_auto_str .= " -B $builddir";
448                 $buildpath = $builddir;
449         }
450
451         my $do_dh_auto = sub {
452                 my $step=shift;
453                 my @extra_args;
454                 my $extra_str = "";
455                 if (exists $args{"${step}_args"}) {
456                         push @extra_args, @{$args{"${step}_args"}};
457                         $extra_str .= " $_" foreach (@extra_args);
458                 }
459                 is ( system("$TOPDIR/dh_auto_$step", @dh_auto_args, "--", @extra_args), 0,
460                          "dh_auto_$step $dh_auto_str$extra_str" );
461                 return @extra_args;
462         };
463         
464         @extra_args = &$do_dh_auto('configure');
465         ok ( -f "$buildpath/Makefile", "$buildpath/Makefile exists" );
466         @lines=();
467         if (ok( open(FILE, "$buildpath/stamp_configure"), "$buildpath/stamp_configure exists") ) {
468                 @lines = @{readlines(\*FILE)};
469         }
470         is_deeply( \@lines, \@extra_args, "$buildpath/stamp_configure contains extra args" );
471
472         &$do_dh_auto('build');
473         ok ( -f "$buildpath/stamp_build", "$buildpath/stamp_build exists" );
474         &$do_dh_auto('test');
475         ok ( -f "$buildpath/stamp_test", "$buildpath/stamp_test exists" );
476         &$do_dh_auto('install');
477         @lines=();
478         if ( ok(open(FILE, "$buildpath/stamp_install"), "$buildpath/stamp_install exists") ) {
479                 @lines = @{readlines(\*FILE)};
480         } 
481         is_deeply( \@lines, [ "DESTDIR=".Cwd::getcwd()."/debian/testpackage" ],
482             "$buildpath/stamp_install contains DESTDIR" );
483         &$do_dh_auto('clean');
484         if ($builddir) {
485                 ok ( ! -e "$buildpath", "builddir $buildpath was removed" );
486         }
487         else {
488                 ok ( ! -e "$buildpath/Makefile" && ! -e "$buildpath/stamp_configure", "Makefile and stamps gone" );
489         }
490         ok ( -x "$sourcedir/configure", "configure script renamins after clean" );
491 }
492
493 dh_auto_do_autoconf('autoconf');
494 dh_auto_do_autoconf('autoconf', 'bld/dir', configure_args => [ "--extra-autoconf-configure-arg" ]);
495 ok ( ! -e 'bld', "bld got deleted too" );
496
497 #### Test parallel building and related options / routines
498 @tmp = ( $ENV{MAKEFLAGS}, $ENV{DEB_BUILD_OPTIONS} );
499
500 # Test is_make_jobserver_unavailable and clean_jobserver_makeflags.
501
502 $ENV{MAKEFLAGS} = "--jobserver-fds=103,104 -j";
503 ok(is_make_jobserver_unavailable(), "unavailable jobserver" );
504 clean_jobserver_makeflags();
505 ok(! exists $ENV{MAKEFLAGS}, "unset makeflags");
506
507 $ENV{MAKEFLAGS} = "-a --jobserver-fds=103,104 -j -b";
508 ok(is_make_jobserver_unavailable(), "unavailable jobserver" );
509 clean_jobserver_makeflags();
510 is($ENV{MAKEFLAGS}, "-a -b", "clean makeflags");
511
512 $ENV{MAKEFLAGS} = " --jobserver-fds=1,2 -j  ";
513 ok(! is_make_jobserver_unavailable(), "available jobserver" );
514 clean_jobserver_makeflags();
515 ok(! exists $ENV{MAKEFLAGS}, "unset makeflags");
516
517 $ENV{MAKEFLAGS} = "-a -j -b";
518 ok(! is_make_jobserver_unavailable(), "no specified jobserver");
519 clean_jobserver_makeflags();
520 is($ENV{MAKEFLAGS}, "-a -j -b", "clean makeflags does not remove -j");
521
522 $ENV{MAKEFLAGS} = "-a --jobs -b";
523 ok(! is_make_jobserver_unavailable(), "no specified jobserver");
524 clean_jobserver_makeflags();
525 is($ENV{MAKEFLAGS}, "-a --jobs -b", "clean makeflags does not remove --jobs");
526
527 $ENV{MAKEFLAGS} = "-j6";
528 ok(! is_make_jobserver_unavailable(), "no specified jobserver");
529 clean_jobserver_makeflags();
530 is($ENV{MAKEFLAGS}, "-j6", "clean makeflags does not remove -j6");
531
532 $ENV{MAKEFLAGS} = "-a -j6 --jobs=7";
533 ok(! is_make_jobserver_unavailable(), "no specified jobserver");
534 clean_jobserver_makeflags();
535 is($ENV{MAKEFLAGS}, "-a -j6 --jobs=7", "clean makeflags does not remove -j or --jobs");
536
537 $ENV{MAKEFLAGS} = "-j6 --jobserver-fds=5,6 --jobs=8";
538 ok(is_make_jobserver_unavailable(), "unavailable jobserver");
539 clean_jobserver_makeflags();
540 is($ENV{MAKEFLAGS}, "-j6 --jobs=8", "jobserver options removed");
541
542 # Test parallel building with makefile build system.
543 $ENV{MAKEFLAGS} = "";
544 $ENV{DEB_BUILD_OPTIONS} = "";
545
546 sub do_parallel_mk {
547         my $dh_opts=shift || "";
548         my $make_opts=shift || "";
549         return process_stdout(
550                 "LANG=C LC_ALL=C LC_MESSAGES=C $TOPDIR/dh_auto_build -Smakefile $dh_opts " .
551                 "-- -s -f parallel.mk $make_opts 2>&1 >/dev/null", "");
552 }
553
554 sub test_isnt_parallel {
555         my ($got, $desc) = @_;
556         my @makemsgs = grep /^make[\d\[\]]*:/, @$got;
557         if (@makemsgs) {
558                 like( $makemsgs[0], qr/Error 10/, $desc );
559         }
560         else {
561                 ok( scalar(@makemsgs) > 0, $desc );
562         }
563 }
564
565 sub test_is_parallel {
566         my ($got, $desc) = @_;
567         is_deeply( $got, [] , $desc );
568         is( $?, 0, "(exit status=0) $desc");
569 }
570
571 test_isnt_parallel( do_parallel_mk(),
572         "No parallel by default" );
573
574 $ENV{DEB_BUILD_OPTIONS}="parallel=5";
575 test_is_parallel( do_parallel_mk(),
576         "DEB_BUILD_OPTIONS=parallel=5 without --max-parallel" );
577 test_is_parallel( do_parallel_mk("--max-parallel=2"),
578         "DEB_BUILD_OPTIONS=parallel=5 with --max-parallel=2" );
579 test_isnt_parallel( do_parallel_mk("--max-parallel=1"),
580         "DEB_BUILD_OPTIONS=parallel=5 with --max-parallel=1 (off)" );
581
582 $ENV{MAKEFLAGS} = "--jobserver-fds=105,106 -j";
583 $ENV{DEB_BUILD_OPTIONS}="";
584 test_isnt_parallel( do_parallel_mk(),
585         "makefile.pm (no parallel): no make warnings about unavailable jobserver" );
586 $ENV{DEB_BUILD_OPTIONS}="parallel=5";
587 test_is_parallel( do_parallel_mk(),
588         "DEB_BUILD_OPTIONS=parallel=5: no make warnings about unavail parent jobserver" );
589
590 $ENV{MAKEFLAGS} = "-j2";
591 $ENV{DEB_BUILD_OPTIONS}="";
592 test_isnt_parallel( do_parallel_mk(),
593         "MAKEFLAGS=-j2: dh_auto_build ignores MAKEFLAGS" );
594 test_isnt_parallel( do_parallel_mk("--max-parallel=1"),
595         "MAKEFLAGS=-j2 with --max-parallel=1: dh_auto_build enforces -j1" );
596
597 # Test dh dpkg-buildpackage -jX detection
598 sub do_rules_for_parallel {
599         my $cmdline=shift || "";
600         my $stdin=shift || "";
601         return process_stdout("LANG=C LC_ALL=C LC_MESSAGES=C PATH=$TOPDIR:\$PATH " .
602                 "make -f - $cmdline 2>&1 >/dev/null", $stdin);
603 }
604
605 # Simulate dpkg-buildpackage -j5
606 doit("ln", "-s", "parallel.mk", "Makefile");
607
608 sub test_dh_parallel {
609         my $extra_dsc=shift || "";
610         my $debian_rules=shift || "";
611         my $rules;
612         my $tmpfile;
613
614         $ENV{MAKEFLAGS} = "-j5";
615         $ENV{DEB_BUILD_OPTIONS} = "parallel=5";
616
617         # Write debian/rules if requested
618         $tmpfile = write_debian_rules($debian_rules);
619
620         $rules = <<'EOF';
621 %:
622         @dh_clean > /dev/null 2>&1
623         @dh --buildsystem=makefile --after=dh_auto_configure --until=dh_auto_build $@
624         @dh_clean > /dev/null 2>&1
625 EOF
626
627         $ENV{MAKEFLAGS} = "";
628         test_is_parallel( do_rules_for_parallel("build", $rules),
629                 "DEB_BUILD_OPTIONS=parallel=5 without MAKEFLAGS=-jX via dh $extra_dsc" );
630
631         $ENV{MAKEFLAGS} = "-j5";
632         $rules = <<'EOF';
633 %:
634         @dh_clean > /dev/null 2>&1
635         @dh --max-parallel=1 --buildsystem=makefile --after=dh_auto_configure --until=dh_auto_build $@
636         @dh_clean > /dev/null 2>&1
637 EOF
638         test_isnt_parallel( do_rules_for_parallel("build", $rules),
639                 "dh --max-parallel=1 disables implicit parallel under dpkg-buildpackage -j5 $extra_dsc");
640
641         $rules = <<'EOF';
642 %:
643         @dh_clean > /dev/null 2>&1
644         @dh -j --buildsystem=makefile --after=dh_auto_configure --until=dh_auto_build $@
645         @dh_clean > /dev/null 2>&1
646 EOF
647         test_is_parallel( do_rules_for_parallel("build", $rules),
648                 "dh -j under dpkg-buildpackage -j5 is parallel $extra_dsc");
649         $ENV{MAKEFLAGS} = "";
650         test_is_parallel( do_rules_for_parallel("build", $rules),
651                 "dh -j is parallel only with DEB_BUILD_OPTIONS=parallel=5 $extra_dsc");
652
653         if (defined $tmpfile) {
654                 rename($tmpfile, "debian/rules");
655         }
656         elsif ($debian_rules) {
657                 unlink("debian/rules");
658         }
659 }
660
661 # dh should pass the same tests with and without overrides
662 test_dh_parallel();
663 test_dh_parallel("(with overrides)", <<'EOF');
664 #!/usr/bin/make -f
665 override_dh_auto_build:
666         @dh_auto_build -- -f parallel.mk
667 EOF
668
669 # Test if legacy punctuation hacks (+) work as before
670 $ENV{MAKEFLAGS} = "-j5";
671 $ENV{DEB_BUILD_OPTIONS} = "parallel=5";
672 $tmp = write_debian_rules(<<'EOF');
673 #!/usr/bin/make -f
674 %:
675         @dh_clean > /dev/null 2>&1
676         @+dh --buildsystem=makefile --after=dh_auto_configure --until=dh_auto_build $@
677         @dh_clean > /dev/null 2>&1
678 EOF
679 test_is_parallel( do_rules_for_parallel("build", "include debian/rules"),
680         "legacy punctuation hacks: +dh, no override" );
681 unlink "debian/rules";
682
683 write_debian_rules(<<'EOF');
684 #!/usr/bin/make -f
685 override_dh_auto_build:
686         dh_auto_build
687 %:
688         @dh_clean > /dev/null 2>&1
689         @+dh --buildsystem=makefile --after=dh_auto_configure --until=dh_auto_build $@
690         @dh_clean > /dev/null 2>&1
691 EOF
692 test_is_parallel( do_rules_for_parallel("build", "include debian/rules"),
693         "legacy punctuation hacks: +dh, override without +, parallel, no make warnings" );
694 unlink "debian/rules";
695
696 write_debian_rules(<<'EOF');
697 #!/usr/bin/make -f
698 override_dh_auto_build:
699         +dh_auto_build
700 %:
701         @dh_clean > /dev/null 2>&1
702         @+dh --buildsystem=makefile --after=dh_auto_configure --until=dh_auto_build $@
703         @dh_clean > /dev/null 2>&1
704 EOF
705 test_is_parallel( do_rules_for_parallel("build", "include debian/rules"),
706         "legacy punctuation hacks: +dh, override with +" );
707 unlink "debian/rules";
708
709 write_debian_rules(<<'EOF');
710 #!/usr/bin/make -f
711 override_dh_auto_build:
712         $(MAKE)
713 %:
714         @dh_clean > /dev/null 2>&1
715         @+dh --buildsystem=makefile --after=dh_auto_configure --until=dh_auto_build $@
716         @dh_clean > /dev/null 2>&1
717 EOF
718 test_is_parallel( do_rules_for_parallel("build", "include debian/rules"),
719         "legacy punctuation hacks: +dh, override with \$(MAKE)" );
720 unlink "debian/rules";
721
722 if (defined $tmp) {
723         rename($tmp, "debian/rules");
724 }
725 else {
726         unlink("debian/rules");
727 }
728
729 # Clean up after parallel testing
730 END {
731         system("rm", "-f", "Makefile");
732 }
733 $ENV{MAKEFLAGS} = $tmp[0] if defined $tmp[0];
734 $ENV{DEB_BUILD_OPTIONS} = $tmp[1] if defined $tmp[1];
735
736 END {
737         system("rm", "-rf", $tmpdir);
738         system("$TOPDIR/dh_clean");
739 }