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.
|