Portable perl How to write code that will work everywhere
Some common fallacies • Perl is portable, my code is written in perl – Therefore my code is portable.
Some common fallacies • Perl is portable, my code is written in perl – Therefore my code is portable. • WRONG!
Some common fallacies • Perl is portable, my code is written in perl – Therefore my code is portable. • WRONG! • My code uses no XS, calls no XS, – Therefore portable.
Some common fallacies • Perl is portable, my code is written in perl – Therefore my code is portable. • WRONG! • My code uses no XS, calls no XS, – Therefore portable. • WRONG!
Who cares about portability • Portability is only an issue if you genuinely want your code to work everywhere. • Portability is not a requirement for ad-hoc scripts written for a single environment
Who cares about portability • Portability is only an issue if you genuinely want your code to work everywhere. • Portability is not a requirement for ad-hoc scripts written for a single environment • But… Think of CPAN. – You publish your module – You want it to work on as many platforms as possible
Nearly all of Perl is portable • Perl tries to bridge the gaps between different platforms • It is usually worth the mileage to make modules portable. • Module authors should be interested in making/keeping their modules portable
Operating system platforms • Unix
Operating system platforms • Unix • MS Win 32
Operating system platforms • Unix • MS Win 32 • Apple Mac
Operating system platforms • • • Unix MS Win 32 Apple Mac VMS Other (see perldoc perlport for the full list)
What are the main issues • • File names and paths Shell commands Environment variables User interaction Communications Multitasking Internationalisation
File names • Unix – /home/me/my_dir/my_file • Windows – C: My documentsmy_dirMy file. txt • VMS – MY_DEVICE: [ME. MY_DIR]MYFILE. TXT; 1
POSIX filenames • A platform independent standard /foo/bar/module. pm lib/Foo/Bar/module. pm
POSIX filenames • A platform independent standard /foo/bar/module. pm lib/Foo/Bar/module. pm • Works on Windows: C: /perl/lib/test. pm • Even works on VMS /my_device/me/my_dir/myfile. txt
Problems with POSIX filenames • No provision for a 'volume' or 'device' – (in Unix terminology, a mount point) • Variations in character set – E. g. Windows allows spaces – Is underscore allowed? Dash? Dollar? More than 1 dot? Punctuation characters? • Case sensitivity – On Unix, FOO, Foo and foo are different files – Accented letters • Problems if you mix native and POSIX syntax C: /mydirmyfile. txt OK sometimes MYDEV: [MYDIR]SUBDIR/FILE. TXTNO!!
The alternative • Use native syntax throughout • Test $^O for the operating system • Do what is necessary to construct a filename
The alternative • Use native syntax throughout • Test $^O for the operating system • Do what is necessary to construct a filename • Fortunately, this has been done for you use File: : Spec; my $file = File: : Spec->catfile( qw( mydev mydir file. txt));
File: : Spec and File: : Spec: : Functions • File: : Spec provides a class methods API • File: : Spec: : Functions provides equivalent functions for export. • The following are exported by default: – canonpath catdir catfile curdir rootdir updir no_upwards file_name_is_absolute path • There also other functions available: – devnull tmpdir splitpath splitdir catpath abs 2 rel 2 abs case_tolerant
A word of warning • File: : Spec merely manipulates strings – curdir returns ‘. ’ on Unix – canonpath merely removes /. and /foo/. . etc. • use Cwd to handle real paths – cwd gives you what curdir really is – abs_path does what you would expect canonpath to do
Other things to watch out for with files • Symbolic links – Are Unix specific – Many O/S don't even support hard links • Security and permissions – (rwx rwx) is a Unix convention – Some O/S don’t have the same concept of a user and a group – VMS ends directories with a. DIR extension
Calling the shell • Don't do it! – (if you want your code to be portable) • Thus, avoid pipe files, backticks and system – Unless providing a mechanism for your interactive user to type in commands. • If you absolutely must – Stick to commands with a common syntax – Test $^O and provide variants
Shell globbing • Not all command interpreters expand wildcards – (i. e. not all shells glob). Unix shells do glob. perl myprog. pl *. txt • Perl on MS-DOS does not glob • Perl on VMS does glob! – Though the VMS command line interpreter does not
Environment Variables • • Unix scripters are used to having standard ones: HOME TERM SHELL USER etc. These are all Unix specific. $ENV{PATH} is common to most O/S's – But not all, VMS for example. – VMS does not need PATH, as you are required to enter the command "RUN" in order to run a program, or @ for a script.
Interacting with the user Problem: • You really need to talk to the user. • stdin, stdout and stderr could be redirected • You want to prompt him for a password. • You don't want to proceed until you have received the password.
Non-portable solution open TTYIN, '/dev/tty' or die "Failed to open terminal"; open TTYOUT, '>/dev/tty' or die "Failed to open terminal"; # Autoflush on for TTYOUT select TTYOUT; $| = 1; # Echo off system "stty -echo"; print "Enter password: "; my $pass = <TTYIN>; chomp $pass; # Echo on again system "stty echo"; validate_pass($pass);
What was non-portable? • Use of "system" to control echoing • /dev/tty - the terminal will not be called this • A minor point: echoing might already be off
A better way • Refer to perlfaq 8: – How do I ask the user for a password? use Term: : Read. Key; Read. Mode('noecho'); my $password = Read. Line(0); • Unfortunately, the POD for Term: : Read. Key says: – Read. Line MODE [, Filehandle] • This call is currently not available under Windows.
Combining Term: : Read. Key and Term: : Read. Line use Term: : Read. Key; use Term: : Read. Line; my $term = Term: : Read. Line->new; Read. Mode('noecho'); my $password = $term->readline ("Enter Password: "); Read. Mode('restore');
Other nice features of Term: : Read. Line • Allows command recall from the history if the O/S supports it • Can operate inside Tk
Communications • File sharing with a different architecture • Exchanging packets over a network
Communications • File sharing with a different architecture • Exchanging packets over a network Look to standards • Each side changes the data to comply to the standard format
Line termination • How exactly is "n" stored or transmitted? – On Unix, a single ASCII 12 (line feed) – On Windows, 15 12 (carriage return, line feed) – On Mac OS, just plain 15 (carriage return)
Line termination • How exactly is "n" stored or transmitted? – On Unix, a single ASCII 12 (line feed) – On Windows, 15 12 (carriage return, line feed) – On Mac OS, just plain 15 (carriage return) • This means that "n" can stand for two characters – This is why chomp is better than chop • This is important when reading foreign files • This is also important when sending and receiving packets