views:

186

answers:

5

Hello,

I have a problem that I cannot seem to find an answer to.

With Perl I need to use a script across Windows and unix platforms. Te problem is that on Windows we use Win32-pecific modules like Win32::Process, and those modules do not exist on unix.

I need a way to include those Win32 modules only on Windows.

if($^O =~ /win/i)
{
    use win32::process qw(CREATE_NEW_CONSOLE);
}
else
{
    #unix fork
}

The problem lies in that use statement for windows. No matter what I try this does not compile on unix.

I have tried using dynamic evals, requires, BEGIN, etc.

Is there a good solution to this problem? Any help will be greatly appreciated.

Thanks in advance,

Dan


Update:

A coworker pointed out to me this is the correct way to do it.

require Win32;
require Win32::Process;

my $flag = Win32::Process::CREATE_NEW_CONSOLE();

Win32::Process::Create($process, 
    $program, 
    $cmd, 
    0, 
    $flag, ".") || die ErrorReport();

print "Child started, pid = " . getPID() . "\n";

Thank you all for your help!

Dan

+3  A: 

Are you sure win32::process can be loaded on OSX? "darwin" matches your /win/i.
You may want to use http://search.cpan.org/dist/Sys-Info-Base/ which tries to do the right thing.

That aside, can you post an example of the code that you actually are using, the failure message you're receiving, and on which unix platform (uname -a) ?

mfontani
A: 

What about a parser that modifies the file on each OS?

You could parse your perl file via a configure script that works on both operating systems to output perl with the proper Use clauses. You could even bury the parse action in the executable script to launch the code.

Originally I was thinking of precompiler directives from C would do the trick, but I don't know perl very well.

Kieveli
+7  A: 

use is executed at compile time.

Instead do:

BEGIN {
    if( $^O eq 'MSWin32' ) {
        require Win32::Process;
        # import Win32::Process qw(CREATE_NEW_CONSOLE);
        Win32::Process->import(qw/ CREATE_NEW_CONSOLE /);
    }
    else {
        #unix fork
    }
}

See the perldoc for use.

Also see perlvar on $^O.


Update:

As Sinan Unur points out, it is best to avoid indirect object syntax.

I use direct method calls in every case, except, with calls to import. Probably because import masquerades as a built-in. Since import is really a class method, it should be called as a class method.

Thanks, Sinan.

Also, on Win32 systems, you need to be very careful that you get the capitalization of your module names correct. Incorrect capitalization means that symbols won't be imported properly. It can get ugly.use win32::process may appear to work fine.

daotoad
Avoid the indirect object syntax: Win32::Process->import( qw(CREATE_NEW_CONSOLE) );
Sinan Ünür
A: 

Here's an answer to your second set of questions:

Are you using strict and warnings?

Did you define an ErrorReport() subroutine? ErrorReport() is just an example in the synopsis for Win32::Process.

CREATE_NEW_CONSOLE is probably not numeric because it didn't import properly. Check the capitalization in your call to import.

Compare these one-liners:

C:\>perl -Mwin32::process  -e "print 'CNC: '. CREATE_NEW_CONSOLE;
CNC: CREATE_NEW_CONSOLE

C:\>perl -Mwin32::process -Mstrict -e "print 'CNC: '. CREATE_NEW_CONSOLE;
Bareword "CREATE_NEW_CONSOLE" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.

C:\>perl -MWin32::Process  -e "print 'CNC: '. CREATE_NEW _CONSOLE;
CNC: 16
daotoad
A: 

You could just place your platform specific code inside of an eval{}, and check for an error.

BEGIN{
  eval{
    require Win32::Process;
    Win32::Process->import(qw'CREATE_NEW_CONSOLE');
  };
  if( $@ ){ # $@ is $EVAL_ERROR

    # Unix code here

  }
}
Brad Gilbert