in reply to Easing cross-platform scripting

Just to add a couple of points to the already excellent answers by Discipulus and kcott: In general, much of core Perl is already written to be fairly platform-independent, with differing implementations inside the interpreter itself (for example, see the win32 directory in the Perl source). For anything else in a cross-platform application, I would very strongly recommend to hide any platform-specific stuff behind an abstraction layer. For example, for filesystem stuff, there's File::Spec (mentioned by kcott), or with an IMO nicer API, Path::Class. You'll also find a lot of modules on CPAN with "Any" in their name, for example, ShellQuote::Any, which automatically uses either Win32::ShellQuote or String::ShellQuote under the hood. Sometimes, you may have to load the modules yourself, for example, I'm not aware of an ::Any module that loads either Win32::SerialPort or Device::SerialPort, although they both provide a very similar API.

So you see there are already quite a few abstraction layers available, and if you're planning on writing your own platform-dependent code with an abstraction layer, it would probably be best if you say what functionality it is you want to abstract, perhaps we can give some more specific suggestions on how to do that.

Replies are listed 'Best First'.
Re^2: Easing cross-platform scripting
by kschwab (Vicar) on Nov 27, 2018 at 21:12 UTC
    module that loads either Win32::SerialPort or Device::SerialPort, although they both provide a very similar API
    I've done something like that...not an "Any" module, but conditionally loading one or the other. You do need to wrap it in a BEGIN block and eval, due to the way "use" works:
    # # Use Win32::Serial port on Windows otherwise, use Device::SerialPort #; BEGIN { my $IS_WINDOWS = ($^O eq "MSWin32" or $^O eq "cygwin") ? 1 : 0; # if ($IS_WINDOWS) { eval "use Win32::SerialPort"; die "$@\n" if ($@); } else { eval "use Device::SerialPort"; die "$@\n" if ($@); } }
    Then something like this when using it:
    my $IS_WINDOWS = ($^O eq "MSWin32" or $^O eq "cygwin") ? 1 : 0; if ($IS_WINDOWS) { $serial = new Win32::SerialPort ($port, 1); } else { $serial = new Device::SerialPort ($port, 1); }
    Somewhat ugly, but handy for anyone using my module. There's likely some more elegant way to do it.

      One arguably more elegant way would be with the if pragma. The documentation even uses this specific case (yes/no MSWin32) as the first example.

      Another could be Module::Load which can be used for run-time decisions (as opposed to compile-time) and might therefore be better suited to more general cases.

      Thanks for the example - just to pick a couple nits:

      • eval "..."; die $@ if $@; has issues, eval "...; 1" or die $@; is better
      • Indirect Object Syntax is discouraged, Win32::SerialPort->new($port, 1) is better
      • Instead of evaling a use, in this case a require is enough.
      • You don't need the duplicate $IS_WINDOWS, it's easier to do my $IS_WINDOWS; BEGIN { $IS_WINDOWS = ...
Re^2: Easing cross-platform scripting
by White Raven (Initiate) on Nov 27, 2018 at 13:51 UTC
    Thanks. But no hard targets at the moment. Am still relatively a fresher fingering the dynamics of the Perl programming language in the context of systems programming.
Re^2: Easing cross-platform scripting
by Anonymous Monk on Nov 27, 2018 at 21:25 UTC
    Also see Browser::Open (and check out the source code for these modules to see how it's done).