Skip Menu |

This queue is for tickets about the Module-Build CPAN distribution.

Report information
The Basics
Id: 5720
Status: resolved
Priority: 0/
Queue: Module-Build

People
Owner: Nobody in particular
Requestors: trevor.schellhorn-perl [...] marketingtips.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.24
Fixed in: (no value)



Subject: Module::Build doesn't work well with version.pm
We have started to use Module::Build for building our module. Unfortunately, we have run into a problem in regards to determining the version from our modules. Our $VERSION is determined using the version module. The method that determines the $VERSION from the module creates a package. It does not load any other modules. To determine the version from our modules, the following patch was used to fix the bug/feature of Module::Build. We are using the latest version of Module::Build on perl 5.8.0 on Redhat Linux 8.0.
--- lib/Module/Build/Base.pm 2004-02-25 13:57:59.000000000 -0800 +++ lib/Module/Build/Base.pm 2004-03-18 17:19:26.000000000 -0800 @@ -477,6 +477,7 @@ my $match = qr/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/; my ($v_line, $sigil, $var) = $self->_next_code_line($fh, $match) or return undef; + eval { require version }; my $eval = qq{q# Hide from _packages_inside() #; package Module::Build::Base::_version; no strict;
From: trevor.schellhorn-perl [...] marketingtips.com
[guest - Thu Mar 18 20:28:46 2004]: Show quoted text
> We have started to use Module::Build for building our module. > Unfortunately, we have run into a problem in regards to determining > the version from our modules. Our $VERSION is determined using the > version module. The method that determines the $VERSION from the > module creates a package. It does not load any other modules. To > determine the version from our modules, the following patch was > used to fix the bug/feature of Module::Build. > > We are using the latest version of Module::Build on perl 5.8.0 on > Redhat Linux 8.0.
I have updated the patch to handle something that I didn't catch in the first round. This now gets the proper version string instead of a version object.
--- lib/Module/Build/Base.pm.orig 2004-03-18 19:38:02.000000000 -0800 +++ lib/Module/Build/Base.pm 2004-03-18 19:37:39.000000000 -0800 @@ -477,6 +477,9 @@ my $match = qr/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/; my ($v_line, $sigil, $var) = $self->_next_code_line($fh, $match) or return undef; + # Load the version module if it is installed + eval { require version }; + my $eval = qq{q# Hide from _packages_inside() #; package Module::Build::Base::_version; no strict; @@ -489,6 +492,12 @@ local $^W; my $result = eval $eval; warn "Error evaling version line '$eval' in $file: $@\n" if $@; + + # Check if the result is blessed in the version class. + if( ref( $result ) eq 'version' ) { + # Get the value out of the version object + $result = "$result"; + } return $result; }
Hi Trevor, Sorry to seem like an obstacle on this, but I think the first part of the patch, always loading version.pm if it's installed, is probably a bad idea. There are cases when authors don't expect version.pm to be loaded, and sometimes their code will break if it is (as happened when I did it for Module::Build itself). Can you think of any other way to resolve this? Maybe just try to load version.pm if the version-finding code doesn't compile the first time? -Ken
From: trevor.schellhorn-perl [...] marketingtips.com
[KWILLIAMS - Sun Sep 12 23:17:10 2004]: Show quoted text
> Hi Trevor, > > Sorry to seem like an obstacle on this, but I think the first part of > the patch, always loading > version.pm if it's installed, is probably a bad idea. There are cases > when authors don't > expect version.pm to be loaded, and sometimes their code will break if > it is (as happened > when I did it for Module::Build itself). > > Can you think of any other way to resolve this? Maybe just try to > load version.pm if the > version-finding code doesn't compile the first time? > > -Ken
Hey Ken, I have been thinking about this for a couple days now. We could remove that autoloading of the 'version' module until it fails. The problem I see with this is if the first module that it tries to check the version of uses the 'version' module, it will then be loaded. After that, any modules that are not expecting it to be loaded will have no choice. As far as I am aware, there is no way to 'unload' a module from memory. Let me know what you think of this. It might need to be put up for discussion on the mailing list for Module::Build or even for something higher up. This kind of a change will also impact the ExtUtils::MakeMaker routines too. Trevor
Hey Trevor, Your comment about "unloading a module" made me think of something. Try the following patch. I'd be willing to put it in if it works, as it's less invasive: ================================= --- lib/Module/Build/Base.pm 12 Sep 2004 03:09:44 -0000 1.331 +++ lib/Module/Build/Base.pm 15 Sep 2004 13:02:06 -0000 @@ -528,8 +528,15 @@ }; \$$var }; local $^W; + local *UNIVERSAL::VERSION = \&UNIVERSAL::VERSION; + eval {require version}; + my $result = eval $eval; warn "Error evaling version line '$eval' in $file: $@\n" if $@; + + # Unbless it if it's a version.pm object + $result = "$result" if UNIVERSAL::isa( $result, 'version' ); + return $result; } =================================
[trevor.schellhorn-perl@marketingtips.com - Wed Sep 15 13:39:27 2004]: Show quoted text
> Hi Ken, > > I applied the patch and it worked with perl 5.8.3. It doesn't work > with perl 5.8.0. In our environment, we are still using perl 5.8.0. > I am not sure where the issue arises with perl 5.8.0 as two test
cases Show quoted text
> cause a Segmentation Fault. They are t/basic.t and t/manifypods.t. > It happens just after test 6 in basic.t and just after test 14 in > manifypods.t.
Yowch! If this is purely a 5.8.0 issue, then maybe we just change the important line to local *UNIVERSAL::VERSION = \&UNIVERSAL::VERSION unless $] == 5.008; Does that eliminate the segfault? -Ken
Looks like this crashes on 5.6.1 too. I think the problem is local() - let's try the following patch instead: Index: lib/Module/Build/Base.pm ========================================================= ========== RCS file: /cvsroot/module-build/Module-Build/lib/Module/Build/Base.pm,v retrieving revision 1.331 diff -u -r1.331 Base.pm --- lib/Module/Build/Base.pm 12 Sep 2004 03:09:44 -0000 1.331 +++ lib/Module/Build/Base.pm 17 Sep 2004 04:33:38 -0000 @@ -528,8 +528,20 @@ }; \$$var }; local $^W; + + # version.pm will change the ->VERSION method, so we mitigate the + # potential effects here. Unfortunately local(*UNIVERSAL::VERSION) + # will crash perl < 5.8.1. + + my $old_version = \&UNIVERSAL::VERSION; + eval {require version}; my $result = eval $eval; + *UNIVERSAL::VERSION = $old_version; warn "Error evaling version line '$eval' in $file: $@\n" if $@; + + # Unbless it if it's a version.pm object + $result = "$result" if UNIVERSAL::isa( $result, 'version' ); + return $result; } ========================================================= ==========
From: DGOLDEN
I just ran into this myself and am coming up to speed on the issue. Is there a reason why Module::Build can't use version.pm itself internally? I've tried some quick hacks on 0.25_03 to add "use version" at the top of Base.pm and then some modifications of the version_from_file() routine to use version.pm to parse whatever it finds in the VERSION line in the file under examination. The major things that appear to break in the test scripts are the distribution directory naming scheme and the metadata generation. The former can be fixed by numifying the version object, though this somewhat defeats the purpose of using version. It would be nice if $VERSION=version->new("0.25_3") generated a distribution like "module-0.250_003.tar.gz" The latter seems to break because it uses "$build->VERSION" in the test script (after version.pm replaces VERSION), but Base.pm always uses "$Module::Build::VERSION" which isn't a version object. Having Module::Build define its version with version.pm fixes that. The major backward incompatibilities would appear to be in the numification of versions for use in naming distribution directories/tarfiles. (I.e. version->new(0.01) becomes "0.010") But then, if the version numbering direction for perl 5.10 goes forward, then this hurdle will have to be addressed sooner rather than later. Perhaps a change could be made with a flag for backwards compatible numbering of distributions. The attached patch passes the current Module::Build test suite (with one change to a single test) (at least on perl 5.8.3 on linux). This was some quick and dirty hacking, so I don't suggest taking it verbatim, but it suggests what few changes could be considered to utilize version.pm without resorting to local UNIVERSAL::VERSION adjustments. It also works for a module I'm working on that defines $VERSION=version->new("0.2.1") and it correctly converts that to 0.002001 for creating a distribution name, etc. Offered in the hope of stimulating discussion -- let me know if I can help in some way to take this forward.
Index: t/Sample/META.yml =================================================================== --- t/Sample/META.yml (revision 7) +++ t/Sample/META.yml (revision 9) @@ -13,4 +13,4 @@ version: 0.01 Sample::NoPod: file: lib/Sample/NoPod.pm -generated_by: Module::Build version 0.25_03 +generated_by: Module::Build version 0.250_030 Index: t/basic.t =================================================================== --- t/basic.t (revision 7) +++ t/basic.t (revision 9) @@ -2,6 +2,7 @@ use strict; use Test; +use version; BEGIN { plan tests => 37 } use Module::Build; ok(1); @@ -64,7 +65,7 @@ # Make sure check_installed_status() works as a class method my $info = Module::Build->check_installed_status('File::Spec', 0); ok $info->{ok}, 1; - ok $info->{have}, $File::Spec::VERSION; + ok $info->{have}, File::Spec->VERSION; # Make sure check_installed_status() works with an advanced spec $info = Module::Build->check_installed_status('File::Spec', '> 0'); Index: lib/Module/Build/Base.pm =================================================================== --- lib/Module/Build/Base.pm (revision 7) +++ lib/Module/Build/Base.pm (revision 9) @@ -11,6 +11,7 @@ use File::Compare (); use Data::Dumper (); use IO::File (); +use version (); #################### Constructors ########################### sub new { @@ -42,7 +43,7 @@ " but we are now using '$perl'.\n"); } - my $mb_version = $Module::Build::VERSION; + my $mb_version = Module::Build->VERSION; die(" * ERROR: Configuration was initially created with Module::Build version '$self->{properties}{mb_version}',\n". " but we are now using version '$mb_version'. Please re-run the Build.PL or Makefile.PL script.\n") unless $mb_version eq $self->{properties}{mb_version}; @@ -89,7 +90,7 @@ recommends => {}, build_requires => {}, conflicts => {}, - mb_version => $Module::Build::VERSION, + mb_version => Module::Build->VERSION, build_elements => [qw( PL support pm xs pod script )], installdirs => 'site', install_path => {}, @@ -463,7 +464,7 @@ my $version_from = File::Spec->catfile( split '/', $p->{dist_version_from} ); - return $p->{dist_version} = $self->version_from_file($version_from); + return $p->{dist_version} = 0 + $self->version_from_file($version_from)->numify; } sub dist_author { shift->_pod_parse('author') } @@ -517,20 +518,11 @@ my $match = qr/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/; my ($v_line, $sigil, $var) = $self->_next_code_line($fh, $match) or return undef; - - my $eval = qq{q# Hide from _packages_inside() - #; package Module::Build::Base::_version; - no strict; - - local $sigil$var; - \$$var=undef; do { - $v_line - }; \$$var - }; local $^W; - my $result = eval $eval; - warn "Error evaling version line '$eval' in $file: $@\n" if $@; - return $result; + my ($v_set) = $v_line =~ /VERSION\b.*?=(.*)/; + my $v_val = eval $v_set; + warn "Error getting version from '$v_val' in $file: $@\n" if $@; + return version->new( "$v_val" ); } sub _persistent_hash_write { @@ -733,16 +725,9 @@ # Check the current perl interpreter # It's much more convenient to use $] here than $^V, but 'man # perlvar' says I'm not supposed to. Bloody tyrant. - return $^V ? $self->perl_version_to_float(sprintf "%vd", $^V) : $]; + return version->new( "$]" ); } -sub perl_version_to_float { - my ($self, $version) = @_; - $version =~ s/\./../; - $version =~ s/\.(\d+)/sprintf '%03d', $1/eg; - return $version; -} - sub _parse_conditions { my ($self, $spec) = @_; @@ -760,7 +745,7 @@ if ($modname eq 'perl') { $status{have} = $self->perl_version; - } elsif (eval { no strict; $status{have} = ${"${modname}::VERSION"} }) { + } elsif (eval { no strict; $status{have} = $modname->VERSION }) { # Don't try to load if it's already loaded } else { @@ -783,7 +768,7 @@ my ($op, $version) = /^\s* (<=?|>=?|==|!=) \s* ([\w.]+) \s*$/x or die "Invalid prerequisite condition '$_' for $modname"; - $version = $self->perl_version_to_float($version) + $version = version->new("$version") if $modname eq 'perl'; next if $op eq '>=' and !$version; # Module doesn't have to actually define a $VERSION @@ -801,11 +786,7 @@ sub compare_versions { my $self = shift; my ($v1, $op, $v2) = @_; - - # for alpha versions - this doesn't cover all cases, but should work for most: - $v1 =~ s/_(\d+)\z/$1/; - $v2 =~ s/_(\d+)\z/$1/; - + $_ = version->new($_) for ($v1, $v2); my $eval_str = "\$v1 $op \$v2"; my $result = eval $eval_str; warn "error comparing versions: '$eval_str' $@" if $@; @@ -2044,7 +2025,7 @@ @{[ join "\n", map " - $_", @{$self->dist_author} ]} abstract: @{[ $self->dist_abstract ]} license: $p->{license} -generated_by: Module::Build version $Module::Build::VERSION, without YAML.pm +generated_by: Module::Build version $p->{mb_version}, without YAML.pm END_OF_META $fh->close(); @@ -2098,10 +2079,10 @@ $node->{dynamic_config} = $p->{dynamic_config} if exists $p->{dynamic_config}; $node->{provides} = $self->find_dist_packages; - $node->{generated_by} = "Module::Build version $Module::Build::VERSION"; + $node->{generated_by} = "Module::Build version $p->{mb_version}"; # YAML API changed after version 0.30 - my $yaml_sub = $YAML::VERSION le '0.30' ? \&YAML::StoreFile : \&YAML::DumpFile; + my $yaml_sub = YAML->VERSION le '0.30' ? \&YAML::StoreFile : \&YAML::DumpFile; return $self->{wrote_metadata} = $yaml_sub->($self->{metafile}, $node ); } @@ -2140,7 +2121,7 @@ foreach my $package ($self->_packages_inside($localfile)) { $out{$package}{file} = $dist_files{$file}; - $out{$package}{version} = $version if defined $version; + $out{$package}{version} = 0+$version->numify if defined $version; } } return \%out; Index: lib/Module/Build.pm =================================================================== --- lib/Module/Build.pm (revision 7) +++ lib/Module/Build.pm (revision 9) @@ -10,12 +10,12 @@ use File::Spec (); use File::Path (); use File::Basename (); - +use version; use Module::Build::Base; use vars qw($VERSION @ISA); @ISA = qw(Module::Build::Base); -$VERSION = '0.25_03'; +$VERSION = version->new('0.25_03'); # Okay, this is the brute-force method of finding out what kind of # platform we're on. I don't know of a systematic way. These values
Hi David, I think that at least for this release, we don't want to convert the Module::Build version- handling code to version.pm, though it's possible we'll want to do so later. The main problem with doing so is that it may/will change people's $VERSION variables (or rather, the reporting of them) in ways they don't anticipate. For now, I'm comfortable with the final patch I referenced in this thread. Thanks for your patch, it may be helpful later as we revisit this. -Ken