ExtUtils::MakeMaker make release

I often wonder why people praise Dist::Zilla for ease of use. Recently I heard this argument: 'It was never easier to make a release. You cannot do that with EUMM'.

So I here is my little make release snippet from one of my Makefile.PL.

There is more in it. make README, make gcov and make gprof for XS extensions.

sub depend {
  "
README : \$(VERSION_FROM)
    pod2text \$(VERSION_FROM) > README

release : dist
    git commit -a -m\"release \$(VERSION)\"
    git tag \$(VERSION)
    cpan-upload \$(DISTVNAME).tar\$(SUFFIX)
    git push
    git push --tags

gcov : \$(BASEEXT).c.gcov \$(BASEEXT).gcov cover_db/\$(BASEEXT)-xs.html

\$(BASEEXT).c.gcov \$(BASEEXT).xs.gcov : \$(BASEEXT).xs
    \$(MAKE) CCFLAGS=\"\$(CCFLAGS) -fprofile-arcs -ftest-coverage\" \
      LDDLFLAGS=\"\$(LDDLFLAGS) -fprofile-arcs -ftest-coverage\"
    gcov \$(BASEEXT).c \$(BASEEXT).xs

cover_db/\$(BASEEXT)-xs.html : \$(BASEEXT).xs.gcov
    PERL5OPT=-MDevel::Cover make test
    -$^X -S gcov2perl \$(BASEEXT).c.gcov \$(BASEEXT).xs.gcov
    $^X -S cover

gprof :
    \$(MAKE) CCFLAGS=\"\$(CCFLAGS) -pg\" LDDLFLAGS=\"\$(LDDLFLAGS) \
      -pg\"
"
}

29 Comments

Making a release also means updating the requires lists and all the versions and copright markers in all the files.

With the quote as you said it taken at face value, you're right; however i'm pretty sure that whoever said that was thinking about those things as well.

Dist::Zilla is classic massive overkill. If you're releasing a significant module, you'll spend way more time writing useful code than you do tweaking version numbers and copyrights, or uploading stuff through PAUSE. If your ratio of time spent doing these things to time spent writing actual code is large enough to be an issue, then you may want to reconsider uploading your module in the first place.

I still click through the irritating PAUSE web interface when I update a module, because it's just not worth my time to automate away the 30 seconds it takes to push an update.

> another sed line

Which of course requires sed to be present, which can however not be assumed to be a given. This is one of the reasons why i personally prefer Dist::Zilla greatly over Makefile shenanigans, i am not bound to any given system architecture.

> That's a job for your editor.

I'm honestly not sure what you mean by that.

> All this and updating req lists should be done before a release, not in a release.

I disagree on the copyright markers and versions, because they only become significant *with* the release.

On the reqs:Sure, they should, and they can. I have my Dzil set up so it automatically updates a META.json file with the current deps when i run dzil build (or, more often: dzil test). It's faster than when i'd do it manually, and also more accurate.

> you'll spend way more time writing useful code than you do tweaking version numbers and copyrights, or uploading stuff through PAUSE.

Of course, but frankly, the time for release preparation is still substantial. Next time you release something, do start a timer from when you're done writing code, to when you've completed the upload. I don't think it'll come even close to the five seconds that Dzil takes. (Excluding time for tests.)

And really, dzil might only save you a minute, but humans are strange creatures. As Google found out, even site loading delays of less than a second will have a significant impact on whether people will give the site the time to load. Similarly, people will weigh up their desire to make a new release of a dist against the effort and time it'll take to do so. Dzil reduces this effort from an admittedly small value, to a near-zero value and as such increases the amounts of releases cut.

If you’re releasing a significant module, you’ll spend way more time writing useful code than you do tweaking version numbers and copyrights, or uploading stuff through PAUSE.

Congratulations for missing the point entirely. No one cares about how long it takes. It’s tedious, finicky work in which it’s easy to make stupid mistakes, or even to skip entire steps in absence of a checklist. If you enjoy carefully executing a fixed set of instructions, feel free; personally I don’t care for having to impersonate a slow, buggy version of the machine that sits under my desk.

Congratulations for missing the point entirely
Thanks! I try really hard! I personally don't mind editing one version number and (once a year) two copyright years, then typing "make dist", even though that probably makes me an inferior person in your book. I weigh doing that against the time needed to install dzil and configure it to do what I want, and believe I'll still be coming out ahead for quite a few more releases.

Everyone has their inclinations on how they prefer their life to be difficult, why would yours make you inferior? I have my own.

You only have to edit the version in a single place? Either you have no change log nor advertise the version in the POD and README, or else you’ve automated the propagation of the version to them in some way – in which case you’ve reinvented part of dzil. I tried a number of approaches for that before dzil came along myself, none satisfying. In so doing I found both EUMM and MB to be horrible as far as tweaking the author workflow goes. I’d rather futz with dzil any day of the week.

You're right -- I have the version in two places if you count the ChangeLog. However, I use the GNU ChangeLog format (though I'm constantly tempted to switch to just exporting the GIT commit log, a lower-level resource), so adding the version there is pretty trivial compared to writing the rest of the entries. Even with the Perl Changes format, with one entry per version, the author should be taking time to summarize important changes since the previous release, so typing in the version's no big deal.

I also settled into a comfortable Perl workflow with EUMM, h2xs (eventually replaced by a simple script that prints out only the useful parts) and CVS (more recently Git) a decade ago. I don't maintain anything super-complex, or put more than a handful of things on CPAN, but I haven't felt the need for a more complicated module authoring and management tool. Maybe if I managed 100+ modules it would be worth my time.

A question here: How many packages do your modules normally contain?

Err, distributions.

Usually not that many -- 5 or fewer -- but in any case, I avoid having more than one $VERSION in a single distribution. That way lies confusion and madness.

Sadly, not having versions in each package can mean needless confusion for the user when things mess up, or distributions get split. I'm talking from experience here. :)

I won't say that everyone MUST have versions in all packages, but it's a very nice thing to do for your user.

Similarly for short descriptions on every package, as well as proper author/support notes on all of them: You don't need to have it and it's a nice thing to do for your users as it makes their lifes a bit easier.

Sadly, as you say, doing it manually leads to chaos; and that is exactly where Dist::Zilla steps in. Again, not saying that you should do these things too, just that i hope this shows you a completely legit use case. :)

IMHO every package should have its own version, otherwise specifying specific version dependencies is going to be hellish. If I use Foo::Bar::Baz in my codebase, I don't want to have to worry about whether it is part of the Foo::Bar distribution or is packaged separately. I should be able to depend on just the specific version of Baz that I need, either in my code, META.yml or dist.ini, and ignore details about external package distribution.

The only way I can see confusion and madness arising is if each module in a dist has its own version, either intentionally or by neglecting to bump a version in one particular file. But if you have your dist builder keep track of versions, this won't happen. Just set the version once, in dist.ini, and the rest happens automatically.

You aren't feeling any love for this but I appreciate it at least.

If nothing else the sub depend{} is neater than the way I've done this in the past. It is probably worth noting that this has to go into package MY; in Makefile.PL.

Also worth noting is the cpan-upload program in your release target.

I've tried Dist::Zilla but it doesn't really work for me. I'm probably not the target audience. I made 30-40 CPAN releases in the last year but they were all mainly for the same module. Using a method similar to yours none of them took me more than a couple of minutes (mainly of watching automated output). I can see situations where I might use Dist::Zilla but I'm not there.

The Pod weaving part of Dist::Zilla also jars with me a little even though I know it is optional. Documentation is one of the few things that I don't think should be automated. Anyone who has had to suffer through the turgid prose generated by Javadoc will have an idea of what I have in mind.


Dist::Zilla is admittedly not perfect. Startup time is superslow (up to ten seconds or more, especially on slow notebooks) and its internals are not documented enough, so you need extra time to understand stuffs. And I hope someday someone creates a worthy alternative. But it gets the job done and you can always Use The Source.

I think dzil (or something like it) has a valid use case and can be really beneficial if you release lots of modules/distributions (say, over 10-20 modules and 50-100 releases a year). Another benefit is, as Mithaldu hinted, since you lower the barrier of releasing modules, people will release more often. I often do a new release after fixing just a bug or two, and wouldn't dream of doing so if I have to do it manually.

Can we perhaps see your CPAN releases?

I don't think the goal of Pod::Weaver is to automate documentation. Its job is to munge POD, like sorting/adding/removing sections. It's like Pod::Parser's weird sibling, with plugins. I'm not very crazy about it too, but again it gets the job done.

But don't you essentially have to keep all submodules' versions in lockstep, or at least bump the main module's version with every submodule change? I guess you could make PAUSE happy by having *yet another* version for the package (e.g. my-package-20120214.tgz contains My::Package 1.01 and My::Package::Subpackage 1.23), but that seems pretty awful.

I'm not entirely sure what you're asking, but: Whenever i do a release, all packages in my dist get their version bumped by dzil to the version set by the auto version generator plugin i chose to use.

I no longer remember the arguments on this particular issue in detail, but the essence was that while there are some undesirable effects of having the same version in all modules (primarily: dependency resolution may then force upgrades that weren’t strictly necessary), the alternative of having a separate version in each module is a lot of effort for little gain and causes headaches in some edge cases (primarily in making it much more difficult to reconstruct what has gone into a perl install over time).

Bottom line: for the toolchain to work reliably, have a single version in each distribution and declare it in every module.

I definitely agree that a distribution should not have more than one version. I think I see the reason for declaring the version in every module -- CPAN will follow dependencies on sub-modules, which you can later spin off into separate distros -- but declaring sub-module dependencies seems awfully error-prone. To guard against future distribution-splitting, you would have to declare dependencies on every sub-module of the current distribution that you used. For example, if you use X::Y::Z and X::Y::W out of X-Y, you need to declare them both, and not just X::Y.

I prefer the much simpler model of naming the distribution X-Y after a single main module X::Y, which contains the sole $VERSION. If you want to spawn off X::Y::Z, you can make X-Y depend upon X::Y::Z (in X-Y-Z), and give X::Y::Z its own $VERSION going forward. With this system, there are no redundant versions, and the relation between PREREQ_PM and packages to be installed is always clear.

Simply put:

If you depend on X::Y::Z and X::Y::W, but declare a dependency on X::Y, then your code is lying.

Also keep in mind that X::Y will not always depend on X::Y::Z, but simply be a thing to collect a number of X::Y::* modules in, some of which may prove to be so big to need a different dist.

Look at Web-Simple for an example of a dist that contains disparate modules that might be spun out, but for now need proper versions in each to be sanely usable.

That's as may be, but I'm guessing that very little of CPAN follows those rules. For example, even Catalyst, a likely example of a "best practices" module, uses Moose::Role while only declaring its dependency on Moose. (FWIW, Moose itself seems to include a $VERSION in every submodule.)

You just demonstrated a perfect example of the http://en.wikipedia.org/wiki/Broken_windows_theory

Catalyst could easily could break without warning, and if you decide to follow their example, your software itself would only exhibit the same trait.

My point was that even the most norm-following distributions on CPAN don't seem to do things right in your view. I suppose you could think of it as a "broken windows" example, but that theory basically states that stopping small crimes prevents a cascade toward more serious ones. Here, it seems like most people's windows are broken, but no one has started looting yet as a result.

I dunno -- if I start running into dependency problems with module-splitting, I may start doing things your way.

To guard against future distribution-splitting, you would have to declare dependencies on every sub-module of the current distribution that you used.

And that is exactly what I do, for precisely that reason. :-)

There have been quite a few splits of large distributions on CPAN, and not of obscure but popular ones, like LWP and BioPerl, as well as (a lot fewer) mergers.

It is not error-prone at all. Simply list every single used module as a dependency and the toolchain will then faithfully do its job. In the case of LWP, many distributions did break, but there were also quite a few that didn’t, because they were done the right way.

> Simply list every single used module as a dependency

The nice bit is that you don't even need to do it manually. Just `use` all your modules in the appropiate places, maybe with versions, and AutoPrereqs builds the dependency list appropiately.

@foo:

There's no reason to loot anymore. It's already in the worst state. Only very few do it, because it's a drag to do it manually, even though it's objectively the correct way to do it. And thus leads to people thinking it's ok not to do it.

Aha! At last it becomes clear to me why some CPAN modules have do-nothing lines like

strict => 0,
warnings => 0,

in their PREREQ_PM. I thought it was just some weird coding style I hadn't heard of, but now I see it's an automated tool. I find the heuristic plug-in mechanism a bit disconcerting, but I can see the appeal.

@steven: I don't think the goal of Pod::Weaver is to automate documentation. Its job is to munge POD, like sorting/adding/removing sections.


You are right. I shouldn't have conflated Pod::Weaver with Javadoc. It isn't doing the same thing at all.

Leave a comment

About Reini Urban

user-pic Working at cPanel on B::C (the perl-compiler), p2, types, parrot, B::Generate, cygwin perl and more guts (LLVM, jit, optimizations).