make vs. make -j${TEST_JOBS}

Until the past year I never truly appreciated how much faster make will build an executable when you are running on some heavy iron and use the -j option. As a p5p committer I have a shell account on dromedary, a server donated by booking.com++ and maintained by Dennis Kaarsemaker and friends (more ++). On that box I set TEST_JOBS=8, which enables me to configure, build and test perl so fast that I have never bothered to time it (probably less than 5 minutes).

Today, however, was the first time that I learned that running make -j${TEST_JOBS} can obscure the results of make.

I had created a branch where, as an experiment, I moved Pod-Html from ext/ to dist/. I grepped the source code for all instances of ext/Pod-Html and changed them to dist/Pod-Html. I then ran a shell function I use all the time to test a branch:

sh ./Configure -des -Dusedevel && make -j${TEST_JOBS} && \
    TEST_JOBS=${TEST_JOBS} make -j${TEST_JOBS} test_harness

I noticed something peculiar: The make part of this command was terminating prematurely, but with no error output at the end where I would have expected it.

Processing BidiBrackets.txt
Finishing processing Unicode properties
Compiling Perl properties
Creating Perl synonyms
Writing tables
Making pod file
Making test script
Updating 'mktables.lst'

I didn't think much of this at first. I typed make and make resumed and proceeded to its normal completion, where it instructs you to run make test. And, after debugging some unrelated issues, everything in make test PASSed.

But I was puzzled about this and repeated the process one step at a time, only running make under script so that I could capture the build output for easier study. I grepped the transcript for Pod-Html and, to my surprise, found one place where there was still a mention of ext/Pod-Html. This occurred about 90% of the way through `make':

Extracting pod2html (with variable substitutions)
pod2html.PL: cannot find '../ext/Pod-Html/bin/pod2html'
make[1]: *** [pod2html] Error 2
make[1]: Leaving directory '/home/jkeenan/perl/utils'
make: *** [utilities] Error 2
make: *** Waiting for unfinished jobs....

Those "unfinished jobs" ran, but when they completed, make exited with non-zero status, which meant that make test did not automatically start. But, because of -j${TEST_JOBS}, the error output was not to be found at the end of make's output.

When, however, I re-ran make with no -j option, make failed as soon as it tried to build pod2html, so the error output appeared at the end of the transcript:

../miniperl -I../lib pod2html.PL
Extracting pod2html (with variable substitutions)
pod2html.PL: cannot find '../ext/Pod-Html/bin/pod2html'
make[1]: *** [pod2html] Error 2
make[1]: Leaving directory /home/jkeenan/perl/utils'
make: *** [utilities] Error 2

It turned out that pod2html.PL creates the string ../ext/Pod-Html/bin/pod2html in part by joining the elements of the list qw(ext Pod-Html bin) with OS-appropriate path separators. Once I changed ext to dist in this location, make -j${TEST_JOBS} ran as expected and all tests PASSed.

Moral of the story: If you customarily build an executable with make -j and make ends prematurely, you either have to search earlier in the make log for the error or you have to re-try make without a -j value.

Leave a comment

About kid51

user-pic I blog about Perl.