我之前已经问过这个问题或者搜过其他人问过 - 为什么我会收到警告“子程序mySub重新定义在../lib/Common.pm第x行”?并且你总是得到答案你在相同的代码中声明了两次。我创建了这个测试包:
整个文件---------------
package MyCommonPkg;
use strict;
sub thisSubroutineIsNotDefinedAnywhereElse{
}
1;
整个文件---------------
我从perl脚本使用这个包,它使用其他包也使用这个包,我收到警告:
子程序ThisSubroutineIsNotDefinedAnywhereElse在../lib/MyCommonPkg.pm第19行重新定义。
我保证我没有在其他任何地方声明这个子。这是由循环引用引起的吗?如何跟踪和修复此警告的原因?
答案 0 :(得分:34)
你有依赖循环吗?如果Perl开始编译脚本并遇到如下所示的行:
use PackageA;
Perl暂停编写脚本;找到PackageA.pm并开始编译它。如果它遇到这样的一行:
use PackageB;
Perl暂停编译PackageA;找到PackageB.pm并开始编译它。通常情况下,这将成功完成,Perl将返回完成编译PackageA,当成功完成时,它将返回编译脚本,当成功完成时,它将开始执行已编译的操作码。
然而,如果PackageB.pm包含以下行:
use PackageA;
你可能会认为它不会做任何事情,因为Perl已经处理过PackageA.pm但问题是它还没有完成。所以Perl将暂停PackageB的编译并从头开始再次开始编译PackageA.pm。这可能会触发您重新定义PackageA中子例程的消息。
作为一般规则,两个包不应相互依赖。但有时循环更难定位,因为它是由第三个包引起的。
答案 1 :(得分:24)
如果在不同的包中有两个具有相同名称的子例程,则应该看到此警告(启用警告时)为“Subroutine new redefined ....”。 一个简单的原因(非常接近Grant McLean所说的,但仍然不完全正确)是你必须让你的包跳过编译阶段然后再需要。这样,Perl命名空间管理器在编译时将找不到任何具有相同名称的冲突符号,如果模块没有任何错误,那么它们之后也会正常工作。
请确保您实施
需要模块;
声明而不是
使用模块;
你不应该再看到这个警告。
答案 2 :(得分:7)
如果您使用的是具有不区分大小写的文件系统(Windows,通常是OSX)的系统,并且您在一个文件中执行use Common
而在另一个文件中执行use common
,则可能会导致类似问题此
答案 3 :(得分:4)
这听起来像是由循环依赖引起的问题。以下是如何追踪它。如果你的问题类看起来像这样:
package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;
然后将您的示例更改为:
package AlienPlanet;
sub has_dinosaurs {...} # <-- swap
use Dinosaurs; # <-- swap
1;
现在使用Carp::Always编译代码,如下所示:
⚡ perl -MCarp::Always -c lib/AlienPlanet.pm
Subroutine has_dinosaurs redefined at lib/AlienPlanet.pm line 4.
require AlienPlanet.pm called at lib/Dinosaurs.pm line 4
Dinosaurs::BEGIN() called at lib/AlienPlanet.pm line 4
eval {...} called at lib/AlienPlanet.pm line 4
require Dinosaurs.pm called at lib/AlienPlanet.pm line 5
AlienPlanet::BEGIN() called at lib/AlienPlanet.pm line 4
eval {...} called at lib/AlienPlanet.pm line 4
lib/AlienPlanet.pm syntax OK
现在你有了一个堆栈跟踪,你可以看到循环的位置。快速而肮脏的解决方案是在Dinosaurs.pm。
中使用Class::Load有关更详细的说明,请尝试我的blog post。
答案 4 :(得分:2)
您是否有机会在网络服务器上运行此cgi脚本?
我发现我需要重新启动网络服务器以解决此警告。
答案 5 :(得分:1)
查看计划package MyCommonPkg.pm
并查看其内容。它有这样的东西吗?
package MyCommonPkg;
use Exporter qw(import); # Might be "require" and not "use"
our @EXPORT = qw(thisSubroutineIsNotDefinedAnywhereElse);
语法可能略有不同。您应该看到的主要内容是package
语句,它使用Exporter
并且@EXPORT
数组中包含您的子例程的名称。
发生了什么是命名空间冲突。您的包正在定义您正在定义的相同子例程。
为了防止这种情况发生,Perl使用名称空间。默认情况下,您的命名空间为main
。但是,假设包使用package
命令定义它们各自的名称。
子例程或变量的完整命名空间是命名空间,后跟双冒号,后跟子例程或变量名。例如,在您查看File::Find时,您会看到对变量$File::Find::name
和$File::Find::dir
的引用。这些是$name
命名空间下$dir
包内的变量File/Find.pm
和File::Find
。
为了使您的工作更轻松,软件包可以将导出它们的主命名空间。例如,如果我使用File::Copy,O可以这样做:
...
use File::Copy
...
copy ($file, $to_dir);
而不是:
...
use File::Copy
...
File::Copy::copy ($file, $to_dir);
如果查看File/Copy.pm
,您会看到以下内容:
package File::Copy;
...
our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
...
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(copy move);
package File::Copy;
定义命名空间。 require Exporter;
和@ISA = qw(Exporter)
允许包将子例程和变量导出到 main 命名空间。 @EXPORT
会自动将copy
和move
子程序导入主名称空间 ,无论您是否需要它,不!的
最后一点非常重要。现在,使用@EXPORT
认为不礼仪。相反,您应该使用@EXPORT_OK
,它要求您列出要使用的子例程。像Scalar::Util这样的更现代的软件包可以做到这一点。
所以有几件事。首先,您的MyCommonPkg
是否有package MyCommonPkg;
声明。如果没有,它应该。这使包子程序和变量不会以令人讨厌的方式影响您的程序。然后,您可以使用@EXPORT
或@EXPORT_OK
。
如果MyCommonPkg
确实有package
声明,是否使用@EXPORT
?如果是这样,您有几种方法可以避免此问题:
您可以在重新定义子例程时关闭警告:
use MyCommonPkg;
no warnings qw(redefine);
sub thisSubroutineIsNotDefinedAnywhereElse {
...
}
use warnings qw(redefine);
require MyCommonPkg;
代替use MyCommonPkg;
。这将阻止将任何子例程或变量导入您的命名空间,包括您想要使用的子例程或变量。假设MyCommonPkg
定义了四个子例程:thisSubroutineIsNotDefinedAnywhereElse
,foo
,bar
和barfoo
。要使用这些子程序中的任何一个。你需要这样做:
my $answer = MyCommonPkg::foo( $input );
不好玩。
为子例程使用其他名称。应记录此子例程在MyCommonPkg
中定义,如果要使用MyCommonPkg
,则不应使用导出的子例程名称。
最后,如果MyCommonPkg
相当新,并且未在数十个程序中使用,请使用@EXPORT_OK
代替@EXPORT
,并确保所有使用的程序修改MyCommonPkg
以导出他们想要的子例程:
像这样:
use MyCommonPkg qw(foo bar);
在这种情况下,仅导出子例程foo
和bar
。子例程thisSubroutineIsNotDefinedAnywhereElse
和barfoo
不会导出到您的环境中。
答案 6 :(得分:0)
我尝试使用“package Common.pm”作为包名。编译器给了我错误。非常好吗?您使用的是什么版本的Perl?我在5.10.0和5.12.1上尝试过它。
即使您可以编译,最好删除.pm文件。例如;
文件:some_package.pm;
package some_package;
use strict;
sub yadayadayada { ... }
1;
答案 7 :(得分:0)
确保您在模块末尾没有忘记这一行:
1;
我知道它已包含在这里的一些例子中,但我提到它是因为它很容易被忽视,而在我的情况下,它被证明是导致错误的唯一原因!
答案 8 :(得分:0)
我有同样的问题;这是因为程序使用了一个模块,子程序既存在于程序中,也存在于perl模块中;