[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [MacPerl] Mac CGI-to-Unix answer



At 7:55 pm 4/4/96, Tim Broderick wrote:

        [ ... joys of UNIX ports snipped ... ]

>That's what I know. Now what I don't know. I'm not sure I understand what
>this line does:
>unshift (@INC, "/usr/www/cgi-bin/requires");
>
>Can someone explain what it's doing.?

'@INC' is the array that holds the list of directories to be searched for
files included by 'use', 'do' or 'require'. The 'unshift' command adds the
directory '/usr/www/cgi-bin/requires' to that list, so that when MacPerl
hits your:

        require ("/usr/www/cgi-bin/requires/parse_form.pl");

instruction, it knows to include '/usr/www/cgi-bin/requires/' in its search
for the 'parse_form.pl' file.

It's always struck me as slightly strange that you need to add the include
directory *and* specify the full path as part of the 'require' statement.
However, I've seen it go wrong if it's not done just like that, so I tend
to treat it as a piece of black magic and do it blindly.

Trying to theorise a little, I'd actually say that the important thing is
to make sure that '@INC' is appropriately set up. I'm currently
successfully using (with Perl 5 at least) code in which I set up '@INC' and
then refer to the required files simply by filename, rather than specifying
the full path. My guess is that:

        # Snippet 1

        unshift(@INC, "/usr/www/cgi-bin/requires");
        require "parse_form.pl";

and

        # Snippet 2

        unshift(@INC, "/usr/www/cgi-bin/requires");
        require "/usr/www/cgi-bin/requires/parse_form.pl";

would both work, but:

        # Snippet 3

        require "/usr/www/cgi-bin/requires/parse_form.pl";

would not. It seems as if Perl refuses to look at any directory not listed
in '@INC', even if you give the full path to the file. But that may vary
from system to system.

Incidentally, '@INC' is a general Perl feature, and is relevant in MacPerl
as well as UNIX Perl. MacPerl initially sets up '@INC' from the list of
paths given in the 'Libraries' preference, but you can also use the
'unshift' trick to add other paths to the search list.

Also incidentally, let me share a trick I use which helps in the process of
porting from MacPerl to UNIX. When you execute a script, the directory that
that script lives in should also be part of '@INC'. So if you're executing
a script called 'foo.pl' and there's another script called 'bar.pl' in the
same directory, then:

        require 'bar.pl';

in 'foo.pl' should - if 'bar.pl' is unique in all the directories searched
- find that.

How is this useful? Well, you can use it to set up '@INC' appropriately for
a particular OS, or set up any other OS-specific information. Then, instead
of hacking the code of your script(s) each time you move them from one
platform to another, you simply change the file that contains the
OS-specific setup. Because you can refer to a file in the local directory
without using any platform-specific pathname delimiters at all, the actual
'require' statement is fully portable.

For example, here's a script:

        # File: my_script.pl

        require 'EnvironmentSetup.pl'
        require 'some_library.pl';

        &do_my_thang();

On the Mac, 'EnvironmentSetup.pl' - which lives in the same directory as
the script - might look like:

        # File: EnvironmentSetup.pl

        unshift(@INC,"Code:Perl:Library");
        unshift(@INC,"Code:Perl:Contributed");

When you move it to UNIX, you don't change 'my_script.pl' at all. You just
change the 'EnvironmentSetup.pl' file to include the appropriate pathnames
for UNIX.

        # File: EnvironmentSetup.pl

        unshift(@INC,"/usr/www/cgi-bin/requires");
        unshift(@INC,"/usr/local/bin/perl/contributed");

This really pays off when you have a cluster of related scripts - instead
of having to edit in platform-specific pathnames across half a dozen
scripts every time you move them from platform to platform, you just edit
the one file that contains the directory specifications.

OK, this is scarcely rocket science - and I apologise to the grizzled
Perl-hackers on the list who've been using this trick or variations on it
for the last eight decades - but it's a timesaver.

The other things to remember when UNIX CGI programming are (a) wrap your
code in an 'eval' as soon as you possibly can in your script, so that when
it blows up you can at least trap it and print a useful error message
rather than simply getting a 'Server Error 500 - Please contact the server
administrator', and (b) check permissions on all your files, and all
directories, including the directories in '@INC'. And (c) check the line at
the start of the script that gives the name of the interpreter to use (e.g.
'#!/usr/bin/perl') really does point to the Perl you're using. I'd estimate
that about 80% of the really head-thumping inexplicable errors when you're
first starting up come down to bad permissions or the wrong interpreter.

Ramble mode off.

                        A