Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm using the ifdef pragma, but am having problems with using it in modules. For example:

foo.pl: use Bar; die "outer death"; Bar.pm: package Bar; =begin DEBUGGING die "inner death"; =cut

Running 'perl -Mifdef=DEBUGGING foo.pl' just dies with 'outer death' but I was expecting 'inner death'. Does the ifdef pragma not affect used modules? This thread suggests it should affect all modules. Thanks

Replies are listed 'Best First'.
Re: ifdef in modules
by ikegami (Patriarch) on Jun 14, 2005 at 16:03 UTC

    The limitation is not ifdef's, but -M's. use is block/file scoped. -M is the same thing as use at the top of the input file, therefore -M won't affect the module.

    bla.pl ------ BEGIN { $|=1 } use bla (); $planet = "World\n"; print($planet); bla.pm ------ $greet = "Hello\n"; print($greet); >perl -Mstrict bla.pl Hello Global symbol "$planet" requires explicit package name at bla.pl line +3. Global symbol "$planet" requires explicit package name at bla.pl line +4. Execution of bla.pl aborted due to compilation errors.

    As you can see, strict did not affect the module.

      The way ifdef seems to be implemented1, it does its thing before the compilation stage, so it's not quite the same as 'use strict'2.

      1 I say _seems_ to be implemented because I don't fully understand how it works. If I did, I'd know why it's not working :)

      2I'm not really sure how 'use strict' works either, so take that for what it's worth ;)

        According to the ifdef docs:

        This version is completely written in Perl. It uses a source filter to provide its magic to the script being run and an @INC handler for all of the modules that are loaded otherwise.
        which says to me that we use an @INC handler to load modules. And the lib says it puts stuff at the front of the @INC. So it sounds to me like the two are not compatable with each other.

        A quick test shows that if you "use ifdef;" at the top of your module, whatever you put on the commandline will propogate... you may want to try more significant tests before relying on it, though.

Re: ifdef in modules
by tlm (Prior) on Jun 14, 2005 at 15:21 UTC

    It works fine for me:

    # Bar.pm: use strict; use warnings; package Bar; =begin DEBUGGING die 'Bar dies'; =cut 1; __END__ # foo.pl use strict; use warnings; use Bar; die 'foo.pl dies'; __END__ % perl foo.pl foo.pl dies at foo.pl line 6. % perl -Mifdef=DEBUGGING foo.pl Bar dies at /loader/0x8128de4/Bar.pm line 7. Compilation failed in require at foo.pl line 4. BEGIN failed--compilation aborted at foo.pl line 4.

    the lowliest monk

      You're right...it does work! It looks like mine didn't work due to this (which I failed to put in my sample code...sorry):

      use lib './perl5lib';

      That's where I put Bar.pm. Here's the full not-working-as-expected code:

      # ./foo.pl: use lib './perl5lib'; use Bar; die "outer death"; __END__ # ./perl5lib/Bar.pm: package Bar; =begin DEBUGGING die "inner death"; =cut 1; __END__

      That said, I'm still not sure why this doesn't work. I'm guessing it has something to do with 'use lib' being loaded after 'ifdef', and 'ifdef' isn't able to work its magic on anything that wasn't in @INC when it was loaded.

      Given the restriction that the module in question must be put in './perl5lib', can anyone offer any suggestions for workarounds?

      Thanks!

        I think that by the time lib modifies @INC, ifdef has already done its thing. One possible workaround would go something like:

        $ PERL5LIB=perl5lib:$PERL5LIB perl -Mifdef=DEBUGGING foo.pl

        the lowliest monk

        Try this:

        % perl -Mlib=perl5lib -Mifdef=DEBUGGING foo.pl

        the lowliest monk

Re: ifdef in modules
by clee (Novice) on Jun 15, 2005 at 21:47 UTC

    In case anyone's interested, this is what I ended up doing in my development environment. The purpose of this is to enable debugging code in CGI applications that are only active during development. Note that this is running on a Win32 platform, though I expect it should work on other platforms. Just make sure to substitute the correct paths.

    1. Set environment variables in Apache:
      SetEnv PERL5LIB C:/Perl/site/lib SetEnv PERL5OPT -Mifdef=DEBUGGING
      This will force C:/Perl/site/lib to the front of @INC and enable the 'ifdef' pragma, activating pod sections tagged with 'DEBUGGING'.

    2. Create a new version of 'lib.pm' in 'C:/Perl/site/lib'. This new 'lib.pm' will ensure that the @INC handler installed by 'ifdef' gets pushed to the front of @INC even when 'use lib' is called in the code. This new 'lib.pm' looks like:
      package lib; sub import { # call the built-in lib first require 'C:/Perl/lib/lib.pm'; import(@_); # re-order @INC with CODE refs at front my (@coderefs, @rest); foreach (@INC) { if (ref $_ && ref $_ eq 'CODE') { push @coderefs, $_; } else { push @rest, $_; } } @INC = (@coderefs, @rest); } 1;

    Basically, step 1 enables 'ifdef' and makes sure our new 'lib.pm' from step 2 will be called in place of the standard 'lib.pm'. Step 2 forces the @INC handler installed by 'ifdef' to the front of @INC (credit for most of the code belongs to Tanktalus).