[ Back | warped.org ]

Perl - Using / Porting / Compiling Local (non-root installed) XS modules in a multi-platform or multi-architecture enviornment

Brief

Let's say you do not have a C-based XS module that you want to use locally and not install into the system perl directory. This may be so you can do local development, or because you do not have root access. Or both.

Just running the normal Makefile.PL process and installing into a locally directory does not work. Files from the different architectures will collide. Things get even uglier when you use different Perl versions, because the MakeMaker behavior isn't consistent. Makemaker will try to stick things in the same auto directory for instance.

This code is used to compile versions of the module into architecture specific directories that will not collide. By default if you install into a local directory (perl Makefile.PL PREFIX=...) and you try to do that on multiple architectures in the same directory tree, things will collide.

Solution

Run Makefile.PL specifying lots of things. This requires you to add some more complex code when trying to add the library path with use lib.

Resulting Directory Structure

 Module_Name/
        liblocal/
            $Perl_Version/
                $Architecture/
            site_perl/
                $Perl_Version/
                    auto/

Code added to use the module

After running the recompile_xs_module script to recompile for the current architecture, add this code to use the module in your Perl app:
    $ModDir = 'Module-0.05';
    # Add a bunch of local library paths so that we can have 
    #   multiple architectures using a local version of an
    #   XS-based module.
    use FindBin;
    use Config;
    $Perl = $Config{version};
    $Arch = $Config{myarchname};
    @Lib  = ("$FindBin::Bin/$ModDir/liblocal/$Perl/$Arch",
             "$FindBin::Bin/$ModDir/liblocal/site_perl/$Perl",
             "$FindBin::Bin/$ModDir/liblocal/site_perl/$Perl/auto",
             "$FindBin::Bin/$ModDir/liblocal");
    foreach my $l (@Lib) { warn "Can't find lib dir : $l" unless -d $l; }
    unshift(@INC,@Lib);

    # Make sure that the module loads.
    eval "use Module;"
    die << "end_die" if ($@);
        $@
        Can't find Module for this architecture.  
        Please run ./recompile_xs_module $ModDir.
end_die

recompile_xs_module shell script

This script (download here) will call Makefile.PL with proper arguments to install the XS-based module into architecture-specific directories.
#!/usr/bin/perl -w
# recompile_xs_module
# Max Baker
# see bottom for usage.

$|=1;
use Cwd 'chdir';
use FindBin;
use Config;

$arch         = $Config{myarchname};
$perl_version = $Config{version};
$lib          = 'liblocal';
#$lib  = 'lib'; # this causes weird recursive behavior
                # since makemaker looks for this dir.

$dest = shift || '';
die &usage unless -d $dest;

# append . if not full path
$dest    = "$FindBin::Bin/$dest" unless $dest =~ /^\//;
$arch    = "$dest/$lib/$perl_version/$arch";
$perlexe = $^X;
$sitelib = "$dest/$lib/site_perl/$perl_version";

$cmd = "$perlexe Makefile.PL";
$cmd .= " PREFIX=$dest";
$cmd .= " INSTALLBIN=$dest/bin     INSTALLSCRIPT=$dest/bin";
$cmd .= " INSTALLMAN1DIR=$dest/man INSTALLMAN3DIR=$dest/man";
$cmd .= " INSTALLARCHLIB=$arch";
$cmd .= " INSTALLSITELIB=$sitelib";

# these don't work right in 5.6.0
#$cmd .= " LIB=$dest/lib";

chdir($dest);
#system("make clean") if -r 'Makefile';
print "$cmd\n\n";
system("$cmd");
system("make install");

sub usage{ ... download the script, don't copy and paste this. } 
----------------8<--------------------8<------------------------
 
maxb 3/2/5
    
end_usage
}

Results

As with Perl there are always 10e6 ways of doing things, so if I'm reinventing the wheel or if you know a better way to use an XS module locally across multiple platforms, please do let me know.

If this information helped you, consider exiting through your right. ©2000-2013 Max Baker
Sun Apr 27 22:32:33 2008 PST