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

I have a script that needs to run on both mac and win32 but I really don't like keeping two copies of the script so instead I would like to load only the required modules for win32 and vice versa. Here is my example:
if ( $os =~ /win32/i ) { use Win32::TieRegistry ( Delimiter=>"/", ArrayValues=>0 );} }
It seems that this block of code is evaluated despite the fact that $os isn't win32 and errors out requiring the Win32::TieRegistry even though I'm running it on a mac.

Any thoughts?

Replies are listed 'Best First'.
Re: require different modules per OS?
by almut (Canon) on Nov 18, 2009 at 14:58 UTC
    use if $^O =~ /win32/i, 'Win32::TieRegistry', Delimiter=>"/", ArrayVal +ues=>0;

    (see if)  Or

    if ( $^O =~ /win32/i ) { require Win32::TieRegistry; Win32::TieRegistry->import(Delimiter=>"/", ArrayValues=>0); }
      "use if" - wow, learn something new everyday. ++!
        adding an eval it is still looking for IO::Interface::Simple on Win32...
        eval { # check and load module at runtime and not compile time if ( $os !~ /darwin/i ) { use Win32::TieRegistry ( Delimiter=>"/", ArrayValues=>0 ); use Win32::Process; use Net::Address::Ethernet qw( get_address ); use Wx::ActiveX::IE qw(:iexplorer); } else { use IO::Interface::Simple; } };
        Am I missing something?
Re: require different modules per OS?
by gwadej (Chaplain) on Nov 18, 2009 at 14:57 UTC

    To expand on keszler's comment, use happens at compile time and the if happens at run time.

    By moving the use into a string eval, you put off its execution until run time.

    G. Wade

      I downvoted for the string eval. Don't use string eval unless necessary.

      If you want to do something which is not easy enough to write with the if module, you can still use require in a begin-block:

      BEGIN { if ($^O =~ /win32/) { require Win32::TieRegistry; import Win32 +::TieRegistry Delimiter=>"/", ArrayValues=>0; } }

        I was wondering how eval EXPR compares. We have the following without eval EXPR:

        BEGIN { if ($^O =~ /win32/) { require Win32::TieRegistry; import Win32::TieRegistry Delimiter=>"/", ArrayValues=>0; } }

        The following would be the equivalent using eval EXPR and a minimal expression:

        BEGIN { if ($^O =~ /win32/) { my @import = ( Delimiter=>"/", ArrayValues=>0 ); eval "use Win32::TieRegistry \@import; 1" or die $@; } }

        Or if you extended the expression beyond the necessary:

        BEGIN { if ($^O =~ /win32/) { eval 'use Win32::TieRegistry Delimiter=>"/", ArrayValues=>0; 1 +' or die $@; } }

        So it looks like there's no gain from using eval EXPR.

Re: require different modules per OS?
by keszler (Priest) on Nov 18, 2009 at 14:52 UTC
    my $winfail = eval 'use Win32::TieRegistry ( Delimiter=>"/", ArrayValu +es=>0 );'; if ($winfail and $os =~ /win32/i) { die "Running on Windows and couldn't load TieRegistry\n"; }
Re: require different modules per OS?
by ww (Archbishop) on Nov 18, 2009 at 14:54 UTC
    Where does $os come from?

    More code needed because psi isn't working today.

Re: require different modules per OS?
by Anonymous Monk on Nov 18, 2009 at 15:55 UTC
    the string eval works great but now I'm seeing this issue:
    Bareword "DETACHED_PROCESS" not allowed while "strict subs" in use at +test_script.pl line 740.
    this bareword is part of a win32 process but I see this error on mac because the module is never loaded. I have an os check for this method call but it still returns an error. The easy fix is to turn off strict but I don't like doing that. Any alternatives?
      Don't omit the parens around the argument list. You can only do that when the function has previously been declared.
      DETACHED_PROCESS()
      I have an os check for this method call

      You'd have to avoid that the code is even being compiled (as opposed to not being run only), for example by (again) making use of string-eval:

      use strict; eval 'printf "%d\n", DETACHED_PROCESS;' if $^O =~ /win32/i; # ok printf "%d\n", DETACHED_PROCESS if $^O =~ /win32/i; # not o +k: Bareword "DETACHED_PROCESS" not allowed...
Re: require different modules per OS?
by DrHyde (Prior) on Nov 19, 2009 at 10:42 UTC

    Do you really mean /win32/, or do you mean Windows? /win32/ doesn't include Cygwin.

    This is (partly) why I wrote Devel::CheckOS - it lets you easily check for things like 'MicrosoftWindows' or 'Unix' without having to know (or look up) what all the values of $^O are. It's also less likely that a highly specialised module will go out of date when new platforms are supported (such as MirBSD or Dragonfly or Haiku) than that a scrap of code buried somewhere in several of your scripts will!