Subject: | Moo’s BEGIN/INIT codepath is not perlcc safe (“Not a CODE reference.”) |
Howdy,
[Problem]
use Moo::Based::Class; causes perlcc'd code to exit early (w/ 0 oddly enough) with “Not a CODE reference.”.
[A little more detail]
The behavior is like something (Sub::Defer related?) is happening at INIT that is depending on something having happened at BEGIN. Except with compiled code BEGIN is already done and is not executed again.
To really grok what is happening I suggest adding in 'use diagnostics;' and debuging output along the way.
I hope to narrow it down further time permitting but for now I wanted to get some other eyes on it too :)
[In Action]
The modules in the commands below are detailed under “[The files in the examples]” at the end.
Here is what can be done to [see the problem/deonstrate a work around to this limitation/test any fixes].
"a" and "b" work by forcing the entire Moo class mojo to happen after BEGIN, which isn't ideal obviously but it helps us see the problem and se something that makes it go away.
a. When use()d in main scope of a program you must require the Moo based class:
# perl -e 'use tmp::MyMoo;print Moo->VERSION. "\n";'
1.007
# perlcc -e 'use tmp::MyMoo;print Moo->VERSION. "\n";' -o tmp/moo_use_direct
/usr/local/cpanel/3rdparty/perl/514/bin/perlcc: Unexpected compiler output
Internal warning: IV !IOK Sub::Defer::DEFERRED{CODE(0x9adcbd4)}[3] sv_list[3928] 0x2
Internal warning: IV !IOK Sub::Defer::DEFERRED{CODE(0x9adc7ec)} sv_list[3930] 0x2
Internal warning: IV !IOK Sub::Quote::QUOTED{CODE(0x9adcbd4)}[4] sv_list[5002] 0x2
tmp/moo_use_direct.c:26108: warning: integer constant is too large for ‘unsigned long’ type
# tmp/moo_use_direct
1.007
Not a CODE reference.
END failed--call queue aborted.
# perl -e 'require tmp::MyMoo;print Moo->VERSION. "\n";'
1.007
# perlcc -e 'require tmp::MyMoo;print Moo->VERSION. "\n";' -o tmp/moo_require_direct
# tmp/moo_require_direct
1.007
#
b. When use()d by a module you must do so via require *and* also wrap the require in an INIT block:
# perl -e 'use tmp::XYZ tmp::MyMoo;print Moo->VERSION. "\n";'
1.007
# perlcc -e 'use tmp::XYZ tmp::MyMoo;print Moo->VERSION. "\n";' -o tmp/moo_use_indrectly_via_use
/usr/local/cpanel/3rdparty/perl/514/bin/perlcc: Unexpected compiler output
Internal warning: IV !IOK Sub::Defer::DEFERRED{CODE(0xa1ec528)} sv_list[3925] 0x2
Internal warning: IV !IOK Sub::Defer::DEFERRED{CODE(0xa1ec910)}[3] sv_list[3981] 0x2
Internal warning: IV !IOK Sub::Quote::QUOTED{CODE(0xa1ec528)}[4] sv_list[5002] 0x2
tmp/moo_use_indrectly_via_use.c:26110: warning: integer constant is too large for ‘unsigned long’ type
# tmp/moo_use_indrectly_via_use
1.007
Not a CODE reference.
END failed--call queue aborted.
# vim tmp/XYZ.pm # change use tmp::MyMoo; to require tmp::MyMoo;
# perl -e 'use tmp::XYZ tmp::MyMoo;print Moo->VERSION. "\n";'
1.007
# perlcc -e 'use tmp::XYZ tmp::MyMoo;print Moo->VERSION. "\n";' -o tmp/moo_require_indirectly_via_use
/usr/local/cpanel/3rdparty/perl/514/bin/perlcc: Unexpected compiler output
Internal warning: IV !IOK Sub::Defer::DEFERRED{CODE(0x9550c90)}[3] sv_list[4065] 0x2
Internal warning: IV !IOK Sub::Defer::DEFERRED{CODE(0x95508a8)} sv_list[4137] 0x2
Internal warning: IV !IOK Sub::Quote::QUOTED{CODE(0x9550c90)}[4] sv_list[5002] 0x2
tmp/moo_require_indirectly_via_use.c:26110: warning: integer constant is too large for ‘unsigned long’ type
# tmp/moo_require_indirectly_via_use
1.007
Not a CODE reference.
END failed--call queue aborted.
# vim tmp/XYZ.pm # change require tmp::MyMoo; to INIT {require tmp::MyMoo;}
# perl -e 'use tmp::XYZ tmp::MyMoo;print Moo->VERSION. "\n";'
1.007
# perlcc -e 'use tmp::XYZ tmp::MyMoo;print Moo->VERSION. "\n";' -o tmp/moo_require_init_indirectly_via_use
# tmp/moo_require_init_indirectly_via_use
1.007
#
[The files in the examples]
# cat tmp/XYZ.pm
package tmp::XYZ;
use strict;
use warnings;
use tmp::MyMoo;
1;
# cat tmp/MyMoo.pm
package tmp::MyMoo;
use Moo; # does strict and warnings
has foo => ("is" => "rw");
1;
#