views:

1934

answers:

8

A recent question here on SO got me thinking.

On most Linux distributions that I tried, some Perl modules would be available through the package manager. Others, of course, not. For quite a while I would use my package manager whenever I needed to install some CPAN module to find out whether a package was available or not and to install it when it was.

The obvious advantage is that you get your modules updated whenever a new version of the package becomes available.

However, you get in trouble when the module is not available in pre-packaged form and there are dependencies for that module that are. Firing up your package manager every time the cpan shell asks whether it should follow a dependency can be quite tiring.

Often, another drawback is the version of the pre-packaged module. If you are running Debian or Ubuntu you will soon find out that you will not be able to live on the bleeding edge, like many CPAN module authors seem to do.

How do other Perl people on Linux handle that problem? Do you just ignore what your package managers have to offer? Are there any tools that make apt (for example) and cpan better team mates? Or do you simply not install anything via the cpan shell?

+10  A: 

We install everything via the CPAN shell. This does ignore what package managers have to offer, but it avoids the headaches you mention when trying to work with them (firing for dependencies, using correct versions).

In addition, it means that our packages can be built programatically (or manually via the shell) on any platform where CPAN runs. Having a dependency on a package manager would affect your ability to distribute your software to platforms that don't use/support that package manager.

Adam Bellaire
Is there an automatic way, after you've installed OS updates that change your perl version from, say, 5.6.1 to 5.6.2, to upgrade all your CPAN installed modules?
Paul Tomblin
Oh, never mind - I see from the responses to that other question that what I'm looking for is an "autobundle".
Paul Tomblin
Paul: It is expected to be compatible, any XS module compiled on 5.6.1 will work with 5.6.2. Often it is compatible even in reverse (from 5.6.2 to 5.61, for ex.).
Alexandr Ciornii
A: 

I recommend use only cpan. The modules includes in Linux distro is only to cover package dependency. When you are installing linux without internet access with only CDs, it can't use cpan, so some modules are included as packages, but to a Perl developer this is bad.

Also I used to have a cpan configured to install modules in my home, (.perl) without root login needed.

+23  A: 

For development, I install my own Perl and leave the system Perl alone. If I want to upgrade the system Perl, I use the system package manager. For my development Perl, I use the cpan tool.

Since I keep those separate, I should never mess up the Perl that the system needs for its maintenance tasks and so on, but I don't have to rely on the system's decisions for development.

It's very easy to install separate Perls. When you run Configure from the source distribution, it will ask you where you want to install everything. Give it any path that you like. I have many Perls installed in /usr/local/perls, for instance, and everything for each installation lives separately. I then make symlinks in /usr/local/bin for them (e.g. perl5.8.9, perl.5.10.0, perl5.10.0-threaded). When I want a particular version, I just use the one I want:

$ perl5.10.0 program.pl

The particular binary ensures that the program picks up the right module search path and so on (it's the same stuff in the Config.pm module for that binary).

Here's a script I use to create the symlinks. It looks in the bin directory, figures out the Perl version, and makes links like cpan5.10.1 and so on. Each program already knows the right perl to call:

#!perl

use 5.010;

use strict;
use warnings;

use File::Basename;
use File::Spec::Functions;

my $perls_directory = catfile(
    $ARGV[0] // '/usr/local/perls', 
    'perl*'
);
die "$perls_directory does not exist!\n" 
    unless -d dirname $perls_directory;

my $links_directory = $ARGV[1] // catfile( $ENV{HOME}, 'bin' ); #/
die "$links_directory does not exist!\n" unless -d $links_directory;

foreach my $directory ( glob( $perls_directory ) )
{
    say "Processing $directory...";

    unless( -e catfile( $directory, 'bin' ) )
    {
        say "\tNo bin/ directory. Skipping!";
        next;
    }

    my @perls = glob( catfile( $directory, qw( bin perl5* ) ) );    

    my( $perl_version ) = $perls[0] =~ m/(5\.\d+\.\d+)\z/;
    say "\tperl version is $perl_version";

    foreach my $bin ( glob( catfile( $directory, 'bin', '*' ) ) )
    {
        say "\tFound $bin";
        my $basename = basename( $bin );

        my $link_basename = do {
            if( $basename =~ m/5\.\d+\.\d+\z/) { $basename }
            else                               { "$basename$perl_version" }
        };

        my $link = catfile( $links_directory, $link_basename );
        next if -e $link;
        say "\t\tlinking $bin => $link";
        symlink $bin => $link or
            warn "\t\tCould not create symlink [$!]: $bin => $link!";
    }
}

Everything gets install in the right place for that particular Perl.

I've also been thinking that I should put those Perl directories under some sort of source control. If I add a module I don't like, I just back out to an earlier revision. I'm only starting to do that though and haven't played with it much.

I've written more about this sort of thing in the Effective Perler blog:

brian d foy
Too many people shoot themselves in the foot manually answering Configure questions. Please always recommend the appropriate switches instead: ./Configure -de -Dprefix=/some/path. -Dversiononly is also nice.
ysth
I think everyone should go through the questions at least once in their lives. :)
brian d foy
Do you also subdivide /usr/local/lib so as to have a separate module library for each install, or do they all share the same libraries? Surely the latter option will result in some conflicts, not to mention it is more complicated to set up in Configure.
Ether
I don't use /usr/local/lib at all. Everything is self contained in the directory for that perl, e.g. /usr/local/perls/perl-5.11.3/lib
brian d foy
+4  A: 

I do the following on all my boxes:

  • I compile my own perl: I still use 5.8.[89] mostly, the stock 5.10.0 has a performance regression that hits me a lot, waiting for 5.10.1 to try again;
  • I use (and strongly recommend) the local::lib module to keep a module directory per project. Right now, that directory is rsync'ed to all the servers where the project is installed, but I'm testing using git instead;
  • I create a Task:: module for each project, so that I can install all dependencies with a single command.
melo
+4  A: 

I am using Debian for development, and production, and rely on debian Perl packages that are provided with the distro.

For cases where I need a Perl module that is not available in debian, I usually create my own debian package of it and install it.

Ofcourse, this method is not without faults, as a a lot of debian perl modules are outdated (at least in the current debian stable version - etch), and backporting something like Catalyst which has lots of dependencies is not practical.

However, by relying on the OS package manager, I retain all the great features of it, which bring easy maintenance, especially for deployed servers, as you know exactly what packages are installed, and a simple apt-get update;apt-get upgrade (from debian, or from a local repository) upgrades all servers to the same state, including the Perl modules.

Tom Feiner
+1  A: 

I also use the cpan shell and local::lib.

You shouldn't need a Task:: for each project. Just use Module::Install (I like to use Module::Starter like this:

$ module-starter --mi --module=Module::Name --author="Me" [email protected]

and then just pop your dependencies in requires 'module::dependency'; in the Makefile.PL. Finally when it's install time, you just perl Makefile.PL (answer yes) then make installdeps

singingfish
local::lib seconded, it's a godsend if you want to install packages locally. It's not a dramatically clever algorithm, it's just all the magic to get package installers to consistently drop their stuff in a nominated directory, with a bonus function to set the environment when you try and run against it. And you don't even need to install it on the system, there's a bootstrap mechanism too.
ijw
A: 

For production:

In development, choose a version of the perl module which seems right for the requirements; if possible choose the target OS's shipped version (this makes most of the following superfluous), otherwise, pick another one. Create a RPM spec file for it. Use the clean build VM to build the RPM in a reproducable way (from a specfile / source checked in on the appropriate branch).

When the final build can be built (after merge), do the same build from the release branch, commit generated RPMs into deployment repository. This will be used in final validation and then released to production by being copied to the production repository.

All servers in production use the exact same binary that has been fully tested; they use the same spec file and source as the developer intended.

Perl modules are NOT upgraded by any process which does not follow this model. Nor is any other production software.

MarkR
A: 

I use FreeBSD ports and wrap up all the CPAN dependencies in a "meta port" as a sort of a local port. FreeBSD has quite a large number of CPAN modules and their build system is approachable enough that you can easily write your own port if it doesn't exist--just dont forget to submit said port so it gets included in the ports tree. If the port doesn't have the current version in stock, you can always edit the Makefile for the port so it uses the new version, again don't forget to submit the change :-).

Lastly, I use Tinderbox to build the whole mess as binary packages that I then install on the all the production and development machines.

Bottom line--Once you get over your phobia of editing Makefiles, FreeBSD's ports are a great way to maintain your perl application and its dependencies.

Cory R. King