http://qs1969.pair.com?node_id=129668

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

I'm trying to find a way of including the modules I need dependant on the OS I find my script running on. I'm trying to avoid having two scripts.

As an example, on WinNT I'm using Win32::EventLog, while on *nix I'm using Sys::Syslog, however, I'm running into problems using require, and have also tried using 'use autouse', but I guess I'm getting something wrong in my delclaration.

Here's an example -

use strict; my $eventlog; # only used by MSWin32 if ($^O eq "MSWin32") { no strict "subs"; use autouse Win32::EventLog => qw(Report new); $eventlog = Win32::EventLog->new("myscript"); } else { no strict "subs"; use autouse Sys::Syslog => qw(:DEFAULT setlogsock); Sys::Syslog::setlogsockt ('unix'); Sys::Syslog::openlog ("myscript", 'pid', "INFO"); }

When this is run on WinNT4 I get an Undefined Subroutine error for Win32::EventLog->new.

Can someone please advise me how I should be going about this :-)

Pete

Replies are listed 'Best First'.
Re: Coding for two platforms in one Script
by Kanji (Parson) on Dec 05, 2001 at 21:59 UTC

    You're being tripped up timing as use happens at compile-time, but everything else in your script (including the logic to determine the OS) happens afterwards during run-time.

    To get around this, you can change the uses to a require/import combo ...

    if ( $^O eq "MSWin32" ) { require Win32::EventLog; $eventlog = Win32::EventLog->new( "myscript" ); } else { require Sys::Syslog; import Sys::Syslog qw/ :DEFAULT setlogsock /; setlogsock( 'unix' ); openlog( 'myscript', 'pid', 'INFO' ); }

    On a side note, there's not much point in importing methods from an OO-based module like Win32::EventLog; $obj->foo should do the right thing if it's a valid method.

    Similarly, it's silly to import from non-OO modules if you're just going to call those functions explicity ( Sys::Syslog::openlog() vs openlog()).

        --k.


      Thanks for the reply Kanji.

      I've restructured my code as you advise, however, and this is why I was using the 'no strict "subs"' clause (although the context in my original post didn't make sense), I get an error on compilation.

      Here's the code snippet -

      if ($os_type eq "NT") { require Win32::EventLog; import Win32::EventLog qw / :DEFAULT /; my $eventlog_type; if ($priority ne "info") { $eventlog_type = EVENTLOG_WARNING_TYPE; } else { $eventlog_type = EVENTLOG_INFORMATION_TYPE; } $eventlog->Report({ EventType => $eventlog_type, Strings => $message, }); }

      This generates the errors -

      Bareword "EVENTLOG_WARNING_TYPE" not allowed while "strict subs" in us +e at scriptname line 2007. Bareword "EVENTLOG_INFORMATION_TYPE" not allowed while "strict subs" i +n use at scriptname line 2010.

      If I prefix the exported variables with Win32::EventLog, I get the same error. It's just struck me that this may be a problem with Win32::EventLog itself - I can see in EventLog.pm where the variables are exported, but I can't see where they're declared.... hmmmm.

      Pete

        The constants EVENTLOG_* are not grouped into an export group called ":DEFAULT". It looks like you'll have to ask for each one that you want:
        require Win32::EventLog; import Win32::EventLog qw / EVENTLOG_WARNING_TYPE EVENTLOG_INFORMATION +_TYPE /;

        buckaduck

Re: Coding for two platforms in one Script
by VSarkiss (Monsignor) on Dec 05, 2001 at 21:59 UTC

    I've never used autouse, but I suspect you're having problems with the fact that use happens too early. You probably need to move them to a BEGIN block (which is where use "executes"). Something like this may work:

    BEGIN { if ($^O eq "MSWin32") { use Win32::EventLog qw(Report new); } else { use Sys::Syslog qw(:DEFAULT setlogsock); } } # later... if ($^O eq "MSWin32") { my $eventlog = Win32::EventLog->new("myscript"); } else { Sys::Syslog::setlogsockt ('unix'); Sys::Syslog::openlog ("myscript", 'pid', "INFO"); }
    (warning, this is untested.)

    HTH

(tye)Re: Coding for two platforms in one Script
by tye (Sage) on Dec 06, 2001 at 01:40 UTC

      Thanks tye, that page has given me some food for thought. Your point about EVENTLOG_WARNING_TYPE() has finally sunk in too ;-)

      Many thanks to all who responded on this - it's most appreciated.

      Pete

Re: Coding for two platforms in one Script
by perrin (Chancellor) on Dec 05, 2001 at 21:56 UTC
    Don't bother with autouse, just do a require(). You mentioned you had problems with require. What are they?

    Also, I don't see why you're turning off strict subs here.

      The problems with require are that for the Win32::EventLog module (at least) you get lots of 'undefined' errors (with and without -w) when the module is required (although it does continue to run, but makes examining the legitimate output of the script problematic). I also understand that I need to require in each BLOCK that uses functions from that module, well, if I don't I get more compilation errors! I get the impression that I'm incurring more overhead by doing so.

      I was unsure about the import function - do I need to use that in every BLOCK that the require appears in?

      Thanks for your (and everyone elses!) reply :-)

      Pete

        You shouldn't get any errors when the module is required unless it has bugs. Are you talking about undefined variable errors, or are you using subroutines imported from the module during a use()?

        There is no need to require the module in each block. Just require it once. If you are using imported subs, you will need to import it once in each module that uses those subs.

        It's hard to understand why you're getting these errors, so maybe you should try to post a small example of some code that gives you errors when you use require.

Re: Coding for two platforms in one Script
by giulienk (Curate) on Dec 05, 2001 at 21:58 UTC
    I don't know autouse.
    Anyway, why don't you put your use into an eval?
    Like:
    my $module = 'Win32::EventLog'; eval("use $module"); die "Are you sure you included $module in the correct place? " . $@ if $@;

    gkinueliileunikg