SPUG: she-bang lines: "/usr/bin/perl" vs "/usr/bin/env perl"

Joshua ben Jore twists at gmail.com
Sun Apr 15 13:52:55 PDT 2007


On 4/15/07, Michael R. Wolf <MichaelRWolf at att.net> wrote:
>
> > I go so far as never installing or upgrading any modules under
> > /usr/bin/perl.
>
> Could you elaborate on your multi-perl stragegy?
>   1.  How many Perl's do you keep?  Where?
>       OS-Perl:       /usr/bin/perl
>       current-Perl:  /usr/local/bin/perl
>       Others...?

The OS' perl. This is in the path, of course. I can write code against
this perl but I have to be aware that choice of modules and extensions
is sometimes restricted by what my packager has in its universe. I
also have to be aware that if I ever modify this, the OS can modify it
back when it upgrades or really... does anything. If the OS controls
it, I don't.

/usr/bin/perl

A stable private copy. On other people's systems this might be located
in /usr/local/bin/perl. Some OSes like FreeBSD that come without perl
might stomp over this location.

/home/josh/bin/perl/5.8.8/bin/perl  -> /usr/local/bin/perl

A whole pile used for testing. I left the /bin/perl part off because
it would just be too distracting.

/opt/perl-5.6.2
/opt/perl-5.6.2-dbg
/opt/perl-5.6.2-threaded
/opt/perl-5.6.2-threaded-dbg
/opt/perl-5.8.1
/opt/perl-5.8.1-dbg
/opt/perl-5.8.2-dbg
/opt/perl-5.8.1-threaded-dbg
/opt/perl-5.8.2
/opt/perl-5.8.1-threaded
/opt/perl-5.8.3-dbg
/opt/perl-5.8.2-threaded-dbg
/opt/perl-5.8.3
/opt/perl-5.8.2-threaded
/opt/perl-5.8.4-dbg
/opt/perl-5.8.3-threaded-dbg
/opt/perl-5.8.3-threaded
/opt/perl-5.8.4-threaded
/opt/perl-5.8.4
/opt/perl-5.8.4-threaded-dbg
/opt/perl-5.8.5-dbg
/opt/perl-5.8.5-threaded
/opt/perl-5.8.5
/opt/perl-5.8.5-threaded-dbg
/opt/perl-5.8.6-dbg
/opt/perl-5.8.6-threaded
/opt/perl-5.8.6
/opt/perl-5.8.6-threaded-dbg
/opt/perl-5.8.7-dbg
/opt/perl-5.8.7-threaded
/opt/perl-5.8.7
/opt/perl-5.8.7-threaded-dbg
/opt/perl-5.8.8
/opt/perl-5.8.8-dbg
/opt/perl-5.8.8-threaded-dbg
/opt/perl-5.8.8-threaded
/opt/perl-5.9.5-dbg
/opt/perl-5.9.5-threaded-dbg
/opt/perl-5.9.5-threaded
/opt/perl-5.9.5
/opt/perl-special

>   2.  What's in your PATH?  In the she-bang line?  Where are scripts
> located?
>       a. How do you guarantee that OS-Perl scripts get OS-Perl?
>       b. How do you let current-Perl scripts get current-Perl?

OS perl scripts typically have /usr/bin/perl hardcoded into them. This
is fine. I have no idea what perl scripts my OS has - its not
something I care about.

My perl have typically had /home/josh/bin/perl/5.8.8/bin/perl
hardcoded into them but I'm prepared to consider that I might have
done better to use /usr/bin/env all this time. When I replace or move
my perl, now all my scripts have to be updated. It's not overly
onerous but it'd be better not to have to care.

The default $PATH from /etc/(environment|bashrc|whatever) does not
include the "private" or local perl. This lets the OS and anything it
installs get along with the ordinary perl.

Users who intend to use the local or customized perl add the new
directory to their PATH, being careful to add it before anything in
/usr. At home, this is just me so its easy. If I had more users it'd
be easy enough to find the /etc/skel/bashrc equivalent and make it a
default for new users.

The split is: anything that came with the OS has no way of knowing of
the new perl. Anything I add has to be informed somehow. Just adding
to the PATH is a cheap way to get it and convenient.

>   3.  How are updates handled?
>       a. OS-Perl and subordinate modules?

apt-get update

>       a. current-Perl and subordinate modules?

cpan's upgrade command. Recall, the current-perl cpan is in my path
before the OS's cpan. As a user, I don't have permissions to write to
/usr anyway.

> And the $64,000 question?  If your multi-perl strategy is a fix for a
> broken Perl environment, what's broken about the Perl environment that
> prevents you from having a mono-perl (pun not intended) environemnt?

All of this prevents my upgrading a CPAN module from ever breaking my
OS or my OS upgrading or *downgrading* a module from breaking my code.
The core of perl could be ok to share but its easier to just have
multiple installations.

When I say `apt-get upgrade' and it modifies a module, its only going
to do it to the limits of my OS' package repository. This *may* mean
an upgrade or it may also mean a downgrade. Its sure to mean clutter
if I also installed the same module using CPAN and outside the package
manager. By stepping outside of the package manager, I've just ensured
I never have to care about that whole raft of issues.

In fact, let me bring up FreeBSD again. A few years ago they removed
perl from the default OS. This means users can now install perl and be
assured that if they alter anything they won't be breaking their OS.
Before, your OS came with a particular perl version and it really
wasn't safely upgradeable. You'd be stuck with whatever perl version
your OS installed. FreeBSD's /usr/bin/perl was 5.005_03 for ages and
you could install something newer into /usr/local/bin/perl.

This is all about managing how many people are writing to a particular
namespace. If it is /usr/bin/perl then anyone from the management of
the OS can write there through updates or whatever. If its some path
only known locally, then I know I'm protected against anything my OS
does.

> Is the fix too academic/theoretical to be practical?  (For instance,
> if every Perl script and module had some sort of "use only", all
> inter-module dependencies could be checked by the computer, but it may
> be too onerous a solution for the humans in the loop, or the
> intricacies of maintaining multiple module versions.)

If you refer to the `use only' pragma, that's far too much work under
normal circumstances. Its a useful tool to have but I'd rather not
have to use it.

> If it's academic/theoretical and practical, is it being investigated
> for Perl6?  I had heard, for example, that many ISP's wouldn't install
> non-core modules.  One solution to that was to have Perl ship with
> *NO* modules, thus requiring a just-in-time install of *all* modules.
> Such an architecture would not allow any modules to be "second class",
> and would therefore require that any module could be installed with
> the same mechanisms that allowed a micro-perl to bootstrap the
> modules-formerly-known-as-core.

This is easily solveable with no special magic. Perl has a simple
facility to indicate at runtime that some additional libraries should
be checked. At work, I use this to get access to useful CPAN modules
that don't come with the machine but without installing it globally.

I have all my user modules at work installed under ~/.perl/lib. If I
want to use them on an adhoc basis I have to add to PERL5LIB. If I've
installed scripts that use those modules, I modify them with a `use
lib' pragma. This means nothing I'm working on uses my local
installations unless I go to a little bit of effort to make it so.
That's the right thing for me - perhaps not for you.

  PERL5LIB=~/.perl/lib perl -MCrazy::Mojo -pe ...

  #!...
  use lib "$ENV{HOME}/.perl/lib";

I actually have no idea what the shebang reads - its just whatever was
written for me when I installed it using the perl that was in my path.

I have a ~/.cpan/CPAN/MyConfig.pm file which tells CPAN.pm where to
install everything. It works pretty darn well. I'd like to say that it
works to have code like the following in that file but it doesn't.
CPAN.pm overwrites this file whenever it writes its configuration out.

# What I'd like to have:
my $BIN = "$ENV{HOME}/bin";
my $PERL = "$ENV{HOME}/.perl";
my $LIB = "$PERL/lib";
my $MAN1 = "$PERL/man/man1";
my $MAN3 = "$PERL/man/man3";

$CPAN::Config->{makepl_arg} =
 = join ' ',
    ( map "$_=$LIB", qw( INSTALLARCHLIB INSTALLPRIVLIB INSTALLSITEARCH
INSTALLSITELIB INSTALLVENDORARCH INSTALLVENDORLIB ) ),
    ( map "$_=$BIN", qw( INSTALLBIN INSTALLSCRIPT INSTALLSITEBIN
INSTALLVENDORBIN ) ),
    ( map "$_=$MAN1", qw( INSTALLMAN1DIR INSTALLSITEMAN1DIR
INSTALLVENDORMAN1DIR ) ),
    ( map "$_=$MAN3", qw( INSTALLMAN3DIR INSTALLSITEMAN3DIR
INSTALLVENDORMAN3DIR ) );

$CPAN::Config->{mbuildpl_arg} = join ' ',
    ( map "--installpath $_=$LIB", qw( lib arch ) ),
    ( map "--installpath $_=$BIN", qw( bin ) ),
    ( map "--installpath $_=$MAN1", qw( bindoc ) ),
    ( map "--installpath $_=$MAN3", qw( libdoc ) );

The reality is less pretty. I only had to write this once so it
doesn't really matter much.

$CPAN::Config = {
  ...,
  'makepl_arg' => q[INSTALLARCHLIB=/home/jbenjore/.perl/lib
INSTALLPRIVLIB=/home/jbenjore/.perl/lib
INSTALLSITEARCH=/home/jbenjore/.perl/lib INSTALLSITELIB=/home/jbenjo\
re/.perl/lib INSTALLVENDORARCH=/home/jbenjore/.perl/lib
INSTALLVENDORLIB=/home/jbenjore/.perl/lib
INSTALLBIN=/home/jbenjore/bin INSTALLSCRIPT=/home/jbenjore/bin
INSTALL\
SITEBIN=/home/jbenjore/bin INSTALLVENDORBIN=/home/jbenjore/bin
INSTALLMAN1DIR=/home/jbenjore/.perl/man/man1
INSTALLSITEMAN1DIR=/home/jbenjore/.perl/man/man1 INSTALLVEND\
ORMAN1DIR=/home/jbenjore/.perl/man/man1
INSTALLMAN3DIR=/home/jbenjore/.perl/man/man3
INSTALLSITEMAN3DIR=/home/jbenjore/.perl/man/man3
INSTALLVENDORMAN3DIR=/home/jbenjor\
e/.perl/man/man3],
  ...
  'mbuildpl_arg' => q[--installpath lib=/home/jbenjore/.perl/lib
--installpath arch=/home/jbenjore/.perl/lib --installpath
bin=/home/jbenjore/bin --installpath bindoc=/\
home/jbenjore/.perl/man/man1 --installpath
libdoc=/home/jbenjore/.perl/man/man3],
  ...
};

Josh

PS, my fav program to install this way is perlcritic. Tis the woot.


More information about the spug-list mailing list