[Chicago-talk] [WindyCity-pm] Module::Build and company in a $work environment

Elliot Shank chicago.pm at galumph.com
Thu Apr 17 18:01:53 PDT 2008

Shawn Carroll wrote:
> Has any one used Module::Build or similar modules in a workplace
> environment?  I'm embarking on cleaning up some messy perl code and
> hooking into the local build and release system.  The system is
> designed for compiled languages, but I figure if I can present them
> with a make file-esqe setup, I won't cause to much of a problem.

I do.  I LOVE M::B.  Easy to subclass, extend, override defaults, etc.

We've got a hierarchy like this:

M::B => X::M::B => X::M::B::Base => X::M::B::(?:Legacy|Standard)

X::M::B is where we put our extra functionality.

X::M::B::Base has stuff that we want every distribution to use.

X::M::B::Standard has stuff for new code and completely reformed legacy code.

X::M::B::Legacy, well, you can guess that.

One thing we use this for is centralizing version dependencies.

Here's an edited down version of one of our Build.PL files:


use strict;
use warnings;

use X::Module::Build::Legacy 16230;


# Unless there are extraordinary circumstances, please do not specify a module
# version in the dependencies here.  Simply specify a dependency upon a
# version 0 here, then go modify
# $X::Module::Build::Base::MINIMUM_MODULE_VERSIONS to include your real
# minimum version.  This way we only need to update versions in one location.

my $builder = X::Module::Build::Legacy->new(
    module_name          => 'Y::B',
    requires_merge       => {
        'A::Z'              => 0,
        Cwd                 => 0,
        DBI                 => 0,
        Exporter            => 0,
        Fcntl               => 0,
        'File::Basename'    => 0,
        'File::Copy'        => 0,
        'File::Spec'        => 0,
        'File::stat'        => 0,
        'File::Temp'        => 0,
        'G::C::C'           => 0,
        'G::U'              => 0,
        'G::U::S'           => 0,
        'Getopt::Long'      => 0,
        'IO::Handle'        => 0,
        'IO::Wrap'          => 0,
        'List::MoreUtils'   => 0,
        POSIX               => 0,
        Readonly            => 0,
        'S::S'              => 0,
        'Sys::Hostname'     => 0,
        Template            => 0,
        'Term::ANSIColor'   => 0,
        'Time::HiRes'       => 0,
        'Time::Local'       => 0,
        'U::M'              => 0,
        'U::S'              => 0,
        'U::S'              => 0,
        vars                => 0,

        # There is no direct dependency upon this, but a very definite
        # indirect one.  Nothing will work without this.
        'DBD::Sybase'       => 0,
    build_requires_merge => {
        'Data::Dumper'          => 0,
        'File::Basename'        => 0,
        'File::Spec::Functions' => 0,
        'File::Temp'            => 0,
        FindBin                 => 0,
        'IO::File'              => 0,
        lib                     => 0,
        'Scalar::Util'          => 0,
        'Scope::Guard'          => 0,
        'Test::Deep'            => 0,
        'Test::Differences'     => 0,
        'Test::File'            => 0,
        'Test::File::Diff'      => 0,

# Have to clean up additional test-generated files.
$builder->add_to_cleanup( qw< t/a/O> );



Yes, we list dependencies upon core modules.  It helps if a core module is/is made to be a dual-lifed module and we want to force an upgrade.

You'll note that M::B doesn't have "requires_merge" and "build_requires_merge" configuration keys.  The handling of those lives in X::M::B.  I named those after "meta_merge"; see the doc on that for the idea of how these work.  The ::Base, ::Standard, and ::Legacy modules put modules we want to commonly have our distros depend upon into "requires" and "build_requires".  For example, ::Standard puts in a "build_requires" for Test::Perl::Critic and ::Legacy puts one in for Test::Perl::Critic::Progressive.

We've got a CruiseControl server set up.  When somebody makes a change to a distribution, it gets built, and assuming that the tests pass, a tarball is published to an internal CPAN repository.  (Truly an instance of the dark-PAN.)  We have a Task:: like distribution that depends upon all the other distributions that we want put into production (it also runs some sanity tests).  CruiseControl builds this distribution 4 times a day.  It uses normal CPAN.pm to build all of our third-party dependencies and plus ours.  (Woohoo! Free dependency resolution!)  Out of that comes a tarball that can be handed to QA and eventually put into production.

There's a bunch of other stuff in there that adds custom build targets (ACTION_* methods) and custom file-type handling.  We make the dist target depend upon the build, manifest, and distmeta ones.  We've got some workarounds for NFS timing issues. (Just lovely, that.)  Etc.

More information about the Chicago-talk mailing list