Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Easing cross-platform scripting

by White Raven (Initiate)
on Nov 27, 2018 at 04:55 UTC ( [id://1226402]=perlquestion: print w/replies, xml ) Need Help??

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

As a way of easing cross-platform scripting (prototyping system level software) is there a mechanism for implementing a Perl script that checks on what platform it is been executed and loads some certain modules that are that platform specific or execute some certain code for that platform(probably thought the use of a series of if like in c/c++:)
#if defined __Linux__ ...do something... #elif defined __win32__ ...do something.... )
I come from a C/C++ background and looking under the hood to learn Perl.

Replies are listed 'Best First'.
Re: Easing cross-platform scripting -- portable scripts - OS agnostic tools
by Discipulus (Canon) on Nov 27, 2018 at 08:28 UTC
    Hello White Raven and welcome to the monastery and to the wonderful world of perl!

    You already got a good clue: $^O is the perl special variable containing the OS, from the perl point of view. But with perl you have many many options to finely leverage the platform/architecture checking.

    1) $^O being your first option: you can use it in if construct: if ($^O eq 'MSWin32 ) { ...' or in a dispatch thable:

    my %clear_command = ( MSWin32 => 'cls', Linux => 'clear' ... ); system (1, $clear_command{ $^O } );

    As said in perlvar concerning $^O on windows it always returns MSWin32 but using Win32 module you have something better:

    print Win32::GetOSName(),Win32::GetOSVersion(); # output: Win10Business (64-bit)100179362002561

    2) Config is a core module that holds ~900 values concerning the current perl installation: for example the architecture:

    print $Config{archname}; # MSWin32-x64-multi-thread or if current perl is configured to use threads: $Config{usethreads} The module populates for you a readonly hash named %Config

    3) the if module (not the normal if ) is useful to import the rigth module depending on situation: if you need to work with the OS name (given the above) you may need Win32 module to get the right name:  use if $^O eq 'MSWin32', 'MSWin32'; # note that it wants module in a string!

    4) in perlvar look also at $] and $^V useful to inspect the current perl version (versions are a bit.. confusing in perl: recent history shows.. ;)

    5) last but not least consider that many modules do their best in being agnostinc in respect of the operating system: come to mind Term::ReadLine that works fine on different platforms. Under the hood the module will load the appropriate module dependin on platforms: Term::ReadLine::Linux for example if run on Linux.

    The very same does the best module for portable program: the core module File::Spec that abstracts many important file and path related operations being very OS agnostic

    6) a look at perlport is recomended

    good luck!

    L*

    PS (the title was: Perl Newbie question) next times try to choose more meaning titles for your questions: it wil be useful for future searcher!

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Thanks. This was really helpful. Also note taken on the choice of title for future posts.
        ... choice of title for future posts.

        Why not make it easier on future Seekers of Perl Wisdom concerning this topic and change the title of this post? Please see How do I change/delete my post? for guidance.


        Give a man a fish:  <%-{-{-{-<

Re: Easing cross-platform scripting
by haukex (Archbishop) on Nov 27, 2018 at 11:48 UTC

    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.

      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 = ...
      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.
      Also see Browser::Open (and check out the source code for these modules to see how it's done).
Re: Easing cross-platform scripting
by kcott (Archbishop) on Nov 27, 2018 at 07:51 UTC

    G'day White Raven,

    Welcome to the Monastery.

    What you're looking for sounds very similar to what File::Spec does.

    That's a core module, so you should already have the source code on your system. Alternatively, you can find it all online: File::Spec (CPAN) has links to the source code as well as all the various File::Spec::<os> modules.

    — Ken

Re: Easing cross-platform scripting
by Anonymous Monk on Nov 27, 2018 at 05:35 UTC
    perldoc -v '$^O'

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1226402]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2024-04-24 16:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found