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

I have this desire to check some code into our version control system that can just run as-is. However, the version of perl that it needs to use is pre-determined by the level of perl that we're currently shipping (which is, apparently, 5.8.8, despite my pleas to move up to 5.10.1, which was current at the time I made the request). Since our test machines can vary, /usr/bin/perl, which is definitely the right level on the test boxes (tightly controlled) may not be the right level on some development boxes, such as mine (since Gentoo just upgraded from 5.8.8 to 5.12.2 over the weekend).

So I've been trying to compose in my head a way to check in a perl script, in my case it's a wrapper around App::Prove, such that you can just "do something" once, and that script will always use the correct perl, while the same file, unchanged, will use perl in potentially a different location on another machine.

I figured others may have run across the same thing, and may have alternate (better) suggestions. The best I've come up with thus far is to replace the #!/usr/bin/perl line at the top of my script with:

# -*-perl-*- eval 'exec ${DEV_PERL:-/usr/bin/perl} -S $0 "$@"' if 0;
Then, once I add the execute bit, running the tool should work. If I "export DEV_PERL=perl5.8.8" prior to running it, then my locally built (*) 5.8.8 will run it, but on boxes where /usr/bin/perl already is 5.8.8, then they'll continue just fine. Of course, to this I'd want to check that the correct perl is being loaded, so something like this:
BEGIN { if ($] != 5.008008) { die sprintf "Must use perl 5.8.8, this is %vd!\nTry setting DE +V_PERL to point to the right version.\n", $^V; } }
though it may not need to be in a BEGIN. I'm thinking of BEGIN just because I don't want all the other use's executed since they may fail anyway.

Of course, then the next fun bit is refactoring - when we upgrade the perl on the production machines, we'll want to start using the upgraded perl on the tests, too, so then I'd have to update all the scripts to check the new level. Maybe put it in a module that all scripts must use first, I suppose, so I don't have to repeat myself.

Has anyone else looked into this type of issue before? If so, how did you address it (and if you'd change that, how)? If not, how would you?

Thanks!

Replies are listed 'Best First'.
Re: Dynamic $^X
by ig (Vicar) on Oct 26, 2010 at 09:03 UTC

    If I wanted to strictly control the versions of perl and modules used by my application, I would distribute the required versions with the application, to application specific bin and library directories. All the application scripts could then use the application specific perl in their shebang lines and would be immune to any changes to /usr/bin/perl or its libraries.

      This cannot be said too many times! I lost count of the number of times using the OS Perl has bit a developer or a sysadmin over the years! But as we can see, people want to jump through white hot flaming hoops of fire over deadly sharp shards of glass to avoid doing it the right way.... :-(

      Elda Taluta; Sarks Sark; Ark Arks

Re: Dynamic $^X
by ambrus (Abbot) on Oct 26, 2010 at 13:43 UTC

    You could try to just put the version number in the shebang line, such as #!/usr/local/bin/perl5.12.2. Most systems will have perl installed with the version number in the filename too.

Re: Dynamic $^X
by tospo (Hermit) on Oct 27, 2010 at 12:13 UTC
    why not just use
    #!/usr/bin/env perl
    it is then up to your environment to set up which perl to use, which may be 5.8 on one machine and 5.10 on another.
Re: Dynamic $^X
by andal (Hermit) on Oct 27, 2010 at 07:58 UTC

    I can not understand, why are you going in such complex ways here. Maybe I'm missing something from your description.

    There's "require VERSION" and/or "use VERSION" that you can use in your modules and scripts to make sure, that they are not pulled in by wrong interpreter. In the cases, where you want to try your code with specific interpreter just use the desired binary directly

    /usr/bin/perl.5.xx my_script.pl
    

    After all, if you create a module that is not compatible with the perl that you are shipping, then this module won't be shipped, since it is useless.

    If you want to have both versions of some module (for older and newer perl) then put them in different directories and in the script have something like

    BEGIN{ unshift @INC, $ENV{MY_MODULES_DIR} if exists $ENV{MY_MODULES_DIR}; } use MyModule;

    Now you can run your script as

    MY_MODULES_DIR=experimental perl.5.xx my_script.pl
    
    Or even create a small shell wrapper like
    #!/bin/sh export MY_MODULES_DIR=experimental export OTHER_VARIABLE=value exec "$@"
    and use it as
    myenv perl5.xx my_script.pl
    

    As usually, there's more than one way to do it. Maybe you'll find above something that would help you :)