Subject: | Failure when a package VERSION references a package with XSLoader::load() |
When trying to add Sereal 3.005 to a Pinto repository I get an error from Module::Metadata:
in [..]/Sereal-Decoder-3.005/lib/Sereal/Decoder/Constants.pm: Attempt to reload Sereal/Decoder.pm aborted.
It took me hours to dig into the code, but here's the problem:
- Dist::Metadata::Dist::packages_from_directory (line 213)
calls Module::Metadata->package_versions_from_directory(@pvfd);
where @pvfd = (
'/tmp/Sereal-Decoder-3.005',
[
'/tmp/Sereal-Decoder-3.005/lib/Sereal/Decoder.pm',
'/tmp/Sereal-Decoder-3.005/lib/Sereal/Decoder/Constants.pm',
'/tmp/Sereal-Decoder-3.005/lib/Sereal/Performance.pm'
]
);
- Sereal::Decoder is parsed correctly:
our $VERSION = '3.005'
- Sereal::Decoder::Constants fails:
use Sereal::Decoder; our $VERSION= $Sereal::Decoder::VERSION;
This happens in the following lines in M::Md::evaluate_version_line():
my $vsub = __clean_eval($eval); # line 660
# "Can't locate loadable object for module Sereal::Decoder in @INC"
# --> but this is catched by eval
# next this is done:
local @INC = ('lib',@INC); # line 664
$vsub = __clean_eval($eval); # line 665
# "Error evaling version line ... Attempt to reload Sereal/Decoder.pm aborted."
# --> dies in 667
From what I understood the problem is XSLoader::load() in Sereal::Decoder that always fails.
I guess it's not wanted/possible to compile XS code just to extract the version numbers.
Without having detailed knowledge about Module::Metadata, I see two possible solutions
(please take my apologies in advance if this was complete rubbish):
1. In _evaluate_version_line (line 663): insert a new if-block matching
/Can't locate loadable object/ where we extract the name of the wanted package from
the "$VERSION= $Sereal::Decoder::VERSION" line.
Now check if we already know the version number for package.
To achieve this, we could store intermediate results of already extracted version
numbers in a gobal variable. It can't be class attribute because the loop iterating
over all files is in package_versions_from_directory() - before object instantiation.
So this might get ugly.
2. Insert new if-block like above, but only mark unsatisfied dependency to be
resolved later.
Something like:
'Sereal::Decoder::Constants' => { 'version_from' => 'Sereal::Decoder' }
Later on, we could try to resolve the version references.
Option 2 is my preferred one. It could even be a standard way to resolve
VERSION dependencies without use'ing referenced packages multiple times within
a distribution/directory.