Obscure baffling "module not exported" error: can someone help me find the cause?



I have a bizarre problem with packages and I'm hoping that someone can help me find out what I'm doing wrong because I'm utterly stumped.

The error is "not exported" for something that quite clearly is exported (details follow). The error disappears when one of several particular lines is deleted or commented out, one of which refers to a different Perl module altogether, not used anywhere in any of the code except for the "use" statement. And yet that completely unused module is specific to the error: simply replacing it with another, equally unused, module causes the error to disappear. Again, more details below.

It's the most perplexing thing I've seen in all my years of debugging hardware and software systems and I'm forced to the conclusion that there's some corruption in the Perl installation itself, especially since the code compiles clean on another machine at ostensibly the same level (though the offending machine is newly-built). If someone can even point me in the direction of something to look at or try I'd be grateful.

Now for the description of the code itself, which is a bit involved, despite my having condensed it down to its bare essentials. If you're prepared to help me make sense of this then http://www.lawshouse.org/perl/Problem.jpg shows the thing diagrammatically, with arrows drawn on. You can just about read the code in the image too.

There are three modules: NFBT::ServerLib, NFBT::Utilities::Common and NFBT::Utilities::Server. There is some requirement in them for subroutines out of one or more of the others.

A small test program "trynfbt.pl" includes "shadow_conv" from NFBT::Utilities::Server. The shadow_conv subroutine in Utilities::Server imports a subroutine from ServerLib, which in turn imports ":all: from Utilities::Common as well as the same shadow_conv sub from Utilities::Server. (I hope you're following this). The last piece of the jigsaw is that Utilities::Common imports XML::Twig::XPath.

Running the test program trynfbt.pl gives (These line numbers may not be right because I knocked out blank lines and CR's to make the code smaller to post)

"shadow_conv" is not exported by the NFBT::Utilities::Server module
Can't continue after import errors at /usr/lib/perl5/site_perl/5.8.6/NFBT/ServerLib.pm line 28
BEGIN failed--compilation aborted at /usr/lib/perl5/site_perl/5.8.6/NFBT/ServerLib.pm line 28.
Compilation failed in require at /usr/lib/perl5/site_perl/5.8.6/NFBT/Utilities/Server.pm line 22.
... and three other lines that tell us no more.

But shadow_conv *is* exported, unless my brain is addled.
And removing any of the following lines makes the code run:

The import of Utilities::Common(':all')
The import of XML::Twig::XPath
.. and, of course, the other "use" statements.

Replacing XML::Twig::XPath with something else - I tried XML::Simple and even File::Basename - also makes the code run clean; it has to be that XML module despite the fact that it's never used. Eh?

Lastly here is the actual code from the three modules and the test program. You might find the graphic easier ...

Test Program
============
#!/usr/bin/perl

use strict;
use warnings;

use NFBT::Utilities::Server qw ( shadow_conv );

print "This is the test routine $0\n";


The three modules
=================
------------------------------------------------------
package NFBT::ServerLib;

use 5.008;
use strict;
use warnings;

require Exporter;
our @ISA = qw(Exporter);

our %EXPORT_TAGS = ( 'all' => [ qw(
write_xml_twig
) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'}}, qw(
write_xml_twig
) );

print "This is NFBT::ServerLib\n";


sub write_xml_twig {
# The original write_xml_twig required several subroutines from
# Utilities::Common and also 'shadow_conv'
# Comment either of these out, problem disappears
use NFBT::Utilities::Common ":all";
use NFBT::Utilities::Server qw(shadow_conv); # "not exported" error here
print "This is write_xml_twig in package NFBT::ServerLib\n";
}

1;

--------------------------------------------------
package NFBT::Utilities::Common;

use 5.008;
use strict;
use warnings;

require Exporter;
our @ISA = qw(Exporter);

our %EXPORT_TAGS = ( 'all' => [ qw(
find_bkfile_by_id
) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'}}, qw(
find_bkfile_by_id
) );

sub find_bkfile_by_id {
print "This is subroutine find_bkfile_by_id in package NFBT::Utilities::Common\n";
use XML::Twig::XPath; # Comment this out, problem disappears. It has to be
# XML::Twig::XPath, apparently. XML::Simple and File::Basename cause the problem to
# disappear.
}

1;

------------------------------------------------------
package NFBT::Utilities::Server;

use 5.008;
use strict;
use warnings;

require Exporter;
our @ISA = qw(Exporter);

our %EXPORT_TAGS = ( 'all' => [ qw(
shadow_conv
) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'}}, qw(
shadow_conv
) );

sub shadow_conv {
# The original shadow_conv used write_xml_twig
use NFBT::ServerLib qw(write_xml_twig); # Comment this out, problem disappears
print "This is subroutine shadow_conv in package NFBT::Utilities::Server\n";
}

1;

--

Henry Law Manchester, England
.



Relevant Pages

  • Re: A question about modules
    ... I didn't know that you were using the package name as a prefix to the subroutine name. ... It does the right connection from the DBConn package and I didn't use Exporter. ... Mail has the best spam protection around http://mail.yahoo.com. ...
    (perl.beginners)
  • Sharing functions and symbols between modules.
    ... '$config' imports '$shared::config' into the local namespace ... use $config as a package local variable and see the same data. ... use Exporter; ... sub AUTOLOAD{ ...
    (perl.beginners)
  • Re: about the vars scope
    ... use vars qw; ... package My::HTML; ... use Exporter; ...
    (perl.beginners)
  • Re: Wheres documentation for import ???
    ... and I have read the manpage for Exporter. ... Constructors and Destructors" in perlmod for BEGIN; ... This is not a Perl builtin at all. ... a sub in the package Module. ...
    (comp.lang.perl.misc)
  • Re: Possible bug in caller(0) ?
    ... Package "main", file main.pl, and line 8. ... Therefore 0 should be the current frame, and while the subroutine is ... sub new { ... my $this = shift; ...
    (comp.lang.perl.misc)