|Think about Loose Coupling|
Do Pure Perl CPAN packages really need to use ExtUtils::Command::MM?by ELISHEVA (Prior)
|on Feb 17, 2011 at 16:37 UTC||Need Help??|
ELISHEVA has asked for the
wisdom of the Perl Monks concerning the following question:
CPAN has two installers, the more "modern" Build.PL backed by Module::Build and the "traditional" Makefile.PL backed by ExtUtils::MakeMaker and ExtUtils::Command::MM. The convention for CPAN modules is to ship a package that supports both the old and the new installers.
The problem I'm running into is this: it is impossible to honor the conventions of both the older and the newer installer at once. When you have libraries that are used by the build/test process but not part of the runtime code, the newer installer (Module::Build) expects you to put them in a subdirectory of the project root, preferably named inc. The older build process expects you to put everything in the project root. This is hardcoded into the software and cannot be changed.
The newer one is more flexible and can accommodate the older conventions, so if I want to support both tools using their native build command processor, I have to go with the older conventions. I like the newer conventions. They seem cleaner and facilitate automation.
The older conventions make automating and customizing the packaging process much more complex. Instead of being able to say "everything in inc is mine", any automation software I write has to scan the root and decide what is mine, and what is generated by the build process. That means a fragile hard coded list of what other products I don't control are liable to put in root or else an easy to forget to maintain list of what I put into root. But even if it weren't fragile, any automation that has to dance around exclusion lists like that is more time consuming to write.
There is a third option suggested in the cb last night: place a use lib 'inc'; statement in any file that needs to call support files. If I did that I could do things the Module::Build way but still use ExtUtils::Command::MM. It is a tried and true method and no less than Michael Schwern uses it. (Note: he's the author of the older installer).
I'm probably sounding like Sam in Green Eggs and Ham right now, but I don't like that idea either. First, it means that I have to go into every file I want to ship and edit it to have that line.(Source filters are out - I don't trust them). Secondly, these support libraries are used in a lot of different projects - sometimes at runtime and sometimes at build/configure. If I have any concerns about the current directory of the caller, I also need to add Find::Bin which doesn't work under mod_perl. Finally, as a general rule, I don't like to manipulate @INC in .pm files. That job should be left to calling scripts and configuration files. Separation of concerns and all that. It marries assumptions about file locations with source code that could be used in any number of projects and in any possible role (runtime or support). Also any configuration that requires going into each and every file is bound to be more time consuming than a configuration that doesn't.
I suppose you could say, well, what's it to you: how many files are we talking about? Why do you even need automation? To which I'd counter, does it matter? The more time I spend hand-crafting each project, the fewer projects I can manage at one time. The answers to the questions are interdependent. Philosophically, it bothers me as well: this smells of building to the tool. My TMTOWTDI sense doesn't like it very much at all. Green eggs at least tasted good in the end. This doesn't.
This leaves me with two options: (a) bite the bullet and accept the older conventions. (b) take advantage of a feature of Module::Build that generates a traditional Makefile.PL with a twist. Its build targets simply pass commands onto Module::Build rather than the ExtUtils::Command::MM module used by the older build process.
The only downside I can see to option B is that those using very old legacy perl interpreters might not be able to install my CPAN modules (Module::Build would then become a prereq). Module::Build joined the Perl core with release 5.9 started in October 2003. It became part of stable 5.10 in Dec, 2007, over four years ago.
But is four years old, really all that old? On the timescale of new software fads and mobile phone tradeins, four years is ancient history. In the time scale of much more conservative back-end processing - the place where Perl thrives - it is not that old at all.
I don't know if the people testing my CPAN software are in any way representative, but only 3% of testers were even trying to run the older installer. 97% were using Module::Build. Is it really worth marrying my code to something I consider ugly and hard to maintain and anti-automation just to satisfy an increasingly legacy need? What do you think?
Update 1:Eliya suggested a possible resolution to the differing approaches used by ExtUtils::MakeMaker and Module::Build. Using post_initialize you can add directories to PERL5LIB and get extra paths into @INC that way. With the help of File::Spec and Config this can be done in a portable way. No conflict, no need for option B below. Yeah! - see Re^3: Do Pure Perl CPAN packages really need to use ExtUtils::Command::MM?
Update 2: An anonymous monk reminds me that the portability questions aren't all answered - see Re^7: Do Pure Perl CPAN packages really need to use ExtUtils::Command::MM?. Also moved the updates to the bottom because there still isn't a conclusive answer. At present the options are between Option B above and eliya's solution below.