Ken Williams came chasing after me to get more information about a Module::Build/YAML bug I reported that was creating problem getting Bundle::CPAN compatible with Vanilla Perl (but more on Vanilla Perl in a week or so)
It turned into a sort of 3 way brainstorming between Ken, Matt Trout and myself on how Module::Build worked now, and might be improved.
So at least now I finally got the chance to bitch about Module::Build in person to Ken rather than just lobbing grenades at evangelists in mailing lists. :)
And as seems to be the case for most situations like this, a conversation with the main author of a system was far more productive than talking to users of the system that evangelise it.
It helped to confirm for me that my main technical issue with Module::Build is valid, in that Module::Build does not provide a clean install/upgrade mechanism for end users.
In talking Ken seems quite keen to deal with this, and we talked about how it might be fixed. But for the sake for having a link to refer others to later I thought I should journal what I'd call the three main Installer Patterns.
Anyone planning on implementing a from-source installation system of any type is going to have to implement one of the following.
Installer Pattern 1 - Frozen Installer
This is generally the weakest of the three.
It involves writing an installation system, and never changing the API (even to add features).
This is kind of the current situation with ExtUtils::MakeMaker. It pretty much never changes in any significant way, and so any ExtUtils::MakeMaker Makefile.PL should work with a hell of a lot of old versions.
But this has a ton of problems. Introducing features causes damage (because the installer itself might require a newer installer-support library to be written) and so once locked in there's no room for improvement.
Which pretty much describes ExtUtils::MakeMaker.
Installer Pattern 2 - Bundled Installer
This is the approach taken by the Windows .exe installers, and to a lesser extent Module::Install (which is a hybrid Bundled/Frozen Installer, wrapping bundled code around ExtUtils::MakeMaker)
It works best when you don't really trust the target environment to be consistent. Hence the popularity on Windows and in Perl :)
It also makes it very easy to add new extensions, as the extra code only needs to be added by the author, and nothing is needed on the user's side. And as long as the code works everywhere, everything is great.
On the downside, it can bloat out your package (in the case of M:I the extra 20K is really negligable though). But more importantly, if there is a major bug in your installer you need to do an incremental release of every package created. And so you need to be relatively careful that the features available work reliably for all end-users.
But because the installer makes almost no demands on the user's intelligence (remember, popular on Windows), it works in the most environments for the most users. And if you measure the success of an installer by, well, how many places it installs, then you can see how attractive this pattern is.
The other big downside to the Bundled Installer is that you need strong control over the authors. For CPAN we actually do, there are only around 3500 of them, and we control the upload point PAUSE.
Installer Pattern 3 - Upgrading Installer
When you don't control the authors as much, and don't want to bundle, how do you have a standard installer.
The dominant way for handling this situation is to allow the installer to auto-upgrade. Indeed, to maintain your sanity and not cause maintenance prolems you have to FORCE the installer to upgrade.
So if you use Windows Update, or Redhat Network, or the Steam Installer, every now and then when it starts up it will do the "Please wait while Installer 2.0 installs Installer 2.1..."
So where to with Module::Build
Until Module::Build implements one or both of these patterns, it is going to continue to suffer. And until it implements one or more of these patterns I certainly think it doesn't belong in the core. It won't have the unique stability and adaptability requirements required from an installer.
Of course, the third option would be the best, but is also going to require the co-operation of both CPAN.pm and CPANPLUS to somehow support version checking and auto-upgrading of the core installer components.
And Ken also wants elements of bundling involved, for some of the same reasons we use them in Module::Install, to do things like bundle small testing modules and reduce the number of dependency installer iterations.
Now, I doubt any of this will be available in 0.28, but my hope is that some time after 0.28, we see some capability for bundling, following by some level of integration with CPAN.pm and CPANPLUS to allow auto-upgrading of the core components.
Now flame away :)
I think this taxonomy is lacking because it confuses several different tasks:
The problem is that there tends to be tight coupling between many of these, but we have decentralized and largely uncoordinated tools and different toolchain combinations are needed to handle these tasks. Roughly in order of number of components:
CPAN, Module::Build
(2)CPAN, ExtUtils::MakeMaker, make
(3)CPAN, Module::Install, Module::Build
(3)CPANPLUS, CPANPLUS::Dist::Build, Module::Build
(3)CPAN, Module::Install, ExtUtils::MakeMaker, make
(4)CPANPLUS, CPANPLUS::Dist::MM, ExtUtils::MakeMaker, make
(4)CPANPLUS, CPANPLUS::Dist::Build, Module::Install, Module::Build
(4)CPANPLUS, CPANPLUS::Dist::MM, Module::Install, ExtUtils::MakeMaker, make
(5)Have I missed any? (I'm not even addressing Module::Build
being used to generate a Makefile.PL, as that's Module::Build
being used as an Authoring Tool to support #2 and #5 above. I'm also ignoring the complications that XS create.)
I may also have missed some Module::Install
variations, as I'm not entirely sure where it ends and the other components begin from a task perspective.
I broke out the CPANPLUS::Dist::*
ones separately, as *::Build
is now a separate distribution -- in part to allow faster upgrades to the coupling between components.
So there's anywhere from 2 to 5 different components, each of which are maintained separately and have separate release cycles. Is there any wonder this breaks?
I like the Module::Install
approach of bundling itself with the distribution because it helps a distribution to try to be good to users who have old versions of the other components. But it still sits on top of the rest of a cruddy toolchain, so it doesn't really address the core problem.
Things I think might help the situation:
I think refactoring the whole process around the individual tasks would help. I think CPANPLUS
had the good idea of breaking up front-end administration from back-end distribution-specific plugins. CPAN
should do the same.
CPAN
and CPANPLUS
should aggressively try to auto-upgrade themselves if they can, and they need to be seamless doing so (no lengthy configuration steps).
I'd like to see a CPAN.PL
file that tells CPAN
what installation plug-in to use. CPAN
should then aggressively try to upgrade that plug-in or use one bundled with the distribution.
Potentially, distributions would use the Module::Install
technique to bundle CPAN
and appropriate plugins to upgrade CPAN
if that was out of date. Yes that's even more bloat, but space is cheap these days and CPAN 1.87 is only 242K. I'd rather see bigger but more robust distributions over smaller ones that break under older versions of the toolchain.
That's my ramble for a Sunday morning. I think there's a lot more thinking that could be done about refactoring the whole process, but the big challenge will be getting the entire toolchain upgraded across current/legacy Perl's with and without network access. There, the Module::Install
approach of bundling seems to have some interesting potential -- if anything, perhaps it doesn't go far enough!