1

Edit

I've prefixed the explanation here, for the benefit of anyone else confused by this issue. As @Ikegami explained,

  • VERSION_FROM indicates where the distribution's version comes from, if not in the top-level module;
  • PREREQ_PM indicates (optionally) the version of each required module

Often a distribution, with a version number, consists of several modules, each of which comes with its own version number, not the same as the distribution's number.

On the other end of the spectrum, a distribution consisting of a single module in a single file will not need to take advantage of VERSION_FROM.

However, for the middle case:

  • a distribution of several modules & programs which should have the same version number, and
  • there are enough files or programs where it is advantageous to put the version number into a single separate file

then, the hack described below may be of use to you.

Hope that helps somebody!

Original Question

Practically the first thing I see in ExtUtils::MakeMaker's POD is VERSION_FROM, which suggests that could, or maybe even should use it. However, even MakeMaker itself doesn't see the version of prerequisites (listed with PREREQ_PM) unless it is in the top-level module. That is, if I setup another module Bar that requires a particular version of Foo, where Foo defines its version somewhere other than Foo.pm, MakeMaker will reports the version of Foo as unknown.

Seems like such an obvious, and longstanding, bug that makes me wonder if I'm just misunderstanding or misusing it?

EDIT The question is: Why does MakeMaker encourage VERSION_FROM when it does not use it to get the version?

EDIT The following is a possibly questionable workaround, not the main question:

OTOH, the code in ExtUtils::MM_Unix that checks the version in no way looks anywhere that VERSION_FROM would have indicated. However, it does indicate an interesting workaround.

If Module Foo has in Makefile.PM:

WriteMakefile(
  NAME=>'Foo',
  VERSION_FROM => 'lib/Foo/Version.pm',
  ...

lib/Foo/Version.pm obviously has

use vars qw($VERSION);
$VERSION = '0.1';

and then in Foo.pm, you put:

$Foo::VERSION = do { use Foo::Version; $Foo::Version::VERSION; };

and everything works..... For now!

So, is it a bug in MakeMaker? and/or is my workaround tolerably sane (by Perl standards)?

thanks

  • You shows what works, but I'm not clear on what *doesn't*. – ikegami Feb 12 '14 at 17:55
  • It doesn't work unless you put that *dubious hack* in Foo.pm; and there's no hint in the MakeMaker POD, or elsewhere, that such a thing would be needed. – Bruce Miller Feb 12 '14 at 18:06
  • "It doesn't work" does not clarify anything. What "it"? And what result did you get that you deem unacceptable? – ikegami Feb 12 '14 at 18:17
  • "It doesn't work" refers to the conclusion of the 1st paragraph, namely that MakeMaker reports the version of Foo as unknown. "Works", in this context, would be that when trying to build the hypothetical package "Bar", that MakeMaker would realize that Foo has version 0.1. – Bruce Miller Feb 12 '14 at 18:32
  • You didn't tag me, so I didn't get notified of your comment. – ikegami Feb 16 '14 at 02:05

2 Answers2

1

The $VERSION variable is obviously like any other variable, so you can set it in imaginative ways like:

$Foo::VERSION = do { use Foo::Version; $Foo::Version::VERSION; };

Or:

$Foo::VERSION = grep /[aeiou]/, 'a'..'z';   # version five

However, a lot of toolchain modules (including ExtUtils::MakeMaker) do not execute your file to find the version number. Instead they'll grep through it's lines and try to look for something that looks like a number being assigned to something that looks like a variable called $VERSION, and guess that that number is the module's version. That's not ideal of course, but that's the world we live in.

To let these tools work, you need to make sure to set your version number in a really easy way, a la:

$Foo::VERSION = '1.001';

If you have a lot of modules, and are worried about updating the version numbers on all of them simultaneously, then install Perl::Version which comes bundled with a script called perl-reversion that makes it really easy to update the version numbers in a bunch of modules in one go.

tobyink
  • 13,478
  • 1
  • 23
  • 35
  • MakeMaker does not execute the *file*, but it **does** execute the line that contains $VERSION, surprisingly. But that isn't the question: see the edits above. – Bruce Miller Feb 13 '14 at 16:18
0

"Works", in this context, would be that when trying to build the hypothetical package "Bar", that MakeMaker would realize that Foo has version 0.1.

VERSION_FROM specifies where to obtain the distribution's version. It doesn't set any module's version.

PREREQ_PM defines the list of modules and (in terms of their name and version) the distribution requires.

A module's version may be different than the version of the distribution in which it resides. The module Foo has no version, which is why requiring version 0.1 of module Foo is (correctly) failing.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Aha! Indeed that is the critical, if subtle, distinction, and it is, in fact, present in the ExtUtils::MakeMaker POD, if one is perceptive enough to recognize it. Moreover, now that you bring it up, I can see that the distinction is a necessary and useful one for Perl distributions and modules. – Bruce Miller Feb 17 '14 at 17:00
  • However, I would argue that my usecase: distribution == large collection of modules ALL with the same version is also a useful one, and I know I'm not the first person to be thrown off track. Do you feel my "workaround" is a valid technique to accomplish this? Or a disaster waiting to happen? I'd like the edit the root question to clarify this to help the next person that comes along. Thanks! – Bruce Miller Feb 17 '14 at 17:03
  • Oh, didn't realize I needed to tag @ikegami – Bruce Miller Feb 17 '14 at 17:08
  • @Bruce Miller, (This is my answer you're commenting on, you didn't need to do so here. But earlier, it was your question, so you needed to then.) Oh for sure, there's absolutely nothing wrong with what you've done (though `use Foo::Version; our $VERSION = $Foo::Version::VERSION;` would be a little simpler). – ikegami Feb 17 '14 at 17:15