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

Greetings perl monks. I am porting some perl from *nix to Windows. The code runs today on some 300+ servers. However, now it is going to run on Windows as well. My question is can I conditionally include a module using the "use" command only when it is running under windows? I want this piece of code to work:
if ($^O =~ "Win") { use Win32::DriveInfo ; }
Is there a way to do it?

Replies are listed 'Best First'.
Re: Conditionally including modules
by BrowserUk (Patriarch) on Apr 04, 2005 at 15:41 UTC

    Take a look at the if pragma.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco.
    Rule 1 has a caveat! -- Who broke the cabal?
Re: Conditionally including modules
by jbrugger (Parson) on Apr 04, 2005 at 15:47 UTC
    my $hostOs = $^O; if ($hostOS eq "MSWin32") { require moduleName; }
    "We all agree on the necessity of compromise. We just can't agree on when it's necessary to compromise." - Larry Wall.

      And here's why this is the best choice at the time I wrote it: require is faster than eval STR. In addition, Win32::DriveInfo (according to its documentation) doesn't export anything anyway.

      Personally, I use require over use more that most people here, it seems - but fully qualified names don't bother me as they do some.

      Alternately, you could just always load Win32::DriveInfo:

      my $hasdriveinfo = eval { require Win32::DriveInfo; 1 };
      This will fail gracefully on Unix, but load the module on Windows. The only downside is if Win32::DriveInfo isn't installed on Windows, and you absolutely must use it on Windows. Then you'll need to check:
      if ($^O eq 'MSWin32' and not $hasdriveinfo) { die "failed to load Win32::DriveInfo - is it installed? $@"; }
      At this point, jbrugger's answer is way simpler, if you do really need it.

Re: Conditionally including modules
by ysth (Canon) on Apr 04, 2005 at 16:02 UTC
    What you suggest will not work, because a "use" is performed at compile time, not run time. So before the $^O =~ /Win/ check is even made, the use happens (and presumably fails because the module isn't there).

    Your choices are:

    The if module (available in 5.6.2 and later, or from CPAN). Any variables used must be available at compile time (which is true for $^O).

    use if $^O =~ /Win/, "Win32::DriveInfo";
    Require/import instead of use. This has the drawback of not happening at compile time, which may subtly change how code that uses things that are imported gets compiled. If the module in question is purely OO, there won't be any imports, so this won't be an issue (and the import statement can be omitted).
    if ($^O =~ /Win/) { require Win32::DriveInfo; import Win32::DriveInfo; }
    Same as above, but in a BEGIN block; this has the same effect as using "if", but will work on stock 5.6.1 and older:
    BEGIN { if ($^O =~ /Win/) { require Win32::DriveInfo; import Win32::DriveInfo; } }
Re: Conditionally including modules
by jZed (Prior) on Apr 04, 2005 at 15:43 UTC
    "use" happens at compile time, "require" happens at run time, so "requrie" is what you want. If the module needs to have things imported, you will need to manually import after the require.
Re: Conditionally including modules
by Roy Johnson (Monsignor) on Apr 04, 2005 at 15:51 UTC
    You could string eval it:
    if ($^O =~ 'Win') { eval 'use Win32::DriveInfo;'; }

    Caution: Contents may have been coded under pressure.
Re: Conditionally including modules
by cog (Parson) on Apr 04, 2005 at 15:58 UTC
    This may look slightly off-topic, but I don't think it is (it simply isn't a solution to your problem, but clearly illustrates a path you can follow).

    Here's how Lingua::Identify loads all the Lingua::Identify submodules without having any information on which modules those are (it first searches them and it then loads them, but note that I take a step to prevent from loading modules that don't look like language modules (perhaps future configuration files?)):

    use Class::Factory::Util; for ( Lingua::Identify->subclasses() ) { /^[A-Z][A-Z]$/ || next; eval "require Lingua::Identify::$_ ;"; $languages{_versions}{lc $_} >= 0.01 || die "Required version of language $_ not found.\n"; }