DEV Community

Yuki Kimoto
Yuki Kimoto

Posted on

Hacking Makefile.PL: How to Force Parallel Builds and Tests (The GNU Make Way)

If you are developing a large-scale Perl module or a native extension (XS/SPVM), build and test times can become a bottleneck. While we often manually pass -jN to make, I wanted a way to bake parallel execution directly into the Makefile.PL.

Today, I want to share a rather "aggressive" hack to achieve parallel builds and tests by injecting logic into WriteMakefile.

The Snippet

WriteMakefile(
  macro => {
    # Force parallel builds
    MAKEFLAGS => "-j$jobs",
    
    # Inject parallel test execution by overriding TEST_VERBOSE
    # Constraints for Windows shell compatibility (pwsh/cmd.exe):
    # 1. The entire command is wrapped in double quotes.
    # 2. No backslashes (\) to avoid escape hell.
    # 3. No dollar signs ($) to prevent pwsh variable expansion.
    # 4. No nested parentheses to avoid pwsh tokenization errors.
    # 5. Only '();. are used for maximum safety.
    # 6. Minimal symbols to avoid edge cases in shell parsing.
    'override TEST_VERBOSE' => "scalar (eval chr(36) . q(ENV{HARNESS_OPTIONS}='j$jobs'), 0)",
  },
);

How it works

  1. Parallel Build (MAKEFLAGS): This sets the -j flag for GNU Make. Please note that this only works with gmake.
  2. Parallel Test Hack (override TEST_VERBOSE): This is the "dirty" part. I’m hijacking the TEST_VERBOSE macro, which is usually intended for toggling verbose output. By using eval and chr(36) (to avoid the $ symbol which causes pain in PowerShell), I’m forcing the HARNESS_OPTIONS environment variable to be set to j$jobs just as the test suite starts.

The constraints in the comments ensure that this string remains "shell-safe" even on Windows (cmd.exe or PowerShell), avoiding backslashes and nested parentheses that usually break the build.

Is there a better way?

I’ll be honest: this works, but I’m not sure if it’s the "best" or "right" way to do it. It feels like a brilliant hack, but hacking TEST_VERBOSE to set environment variables is definitely not what the ExtUtils::MakeMaker authors intended.

I’d love to hear your thoughts:

  • Is there a built-in WriteMakefile option that handles parallel tests natively?
  • Have you found a cleaner way to pass HARNESS_OPTIONS through the generated Makefile without shell-escaping hell?

If you have a more "canonical" approach, please let me know in the comments!

Top comments (0)