Perl modules baked into perl

I use nixops and am looking to deploy perl to a bunch of boxes, but I would like perl modules to “just work”. The developers on these boxes don’t want to know anything about nix, they just want to be able to fire up perl and start using perl modules they have asked me to install on the system. These users might also want to be able to use cpan to install perl modules themselves and not have to worry about configuring anything. These are developers who are used to Debian and want as little change as possible if I move them to NixOS. Ideally they wouldn’t even know.

Using Nix Cookbook - NixOS Wiki as a guide I have came up with the following solution:

{ lib, runCommand, symlinkJoin, makeWrapper, perl, perl5Lib }:
let
  perl5LibRef = symlinkJoin {
    name = "perl5Lib";
    paths = lib.misc.closePropagation perl5Lib;
  };
in
  runCommand "perl-with-perl5Lib" {
    buildInputs = [ makeWrapper ];
  } ''
    mkdir $out
 
    # Link every top-level folder from perl to our new target
    ln -s ${perl}/* $out
 
    # Except the bin folder
    rm $out/bin
    mkdir $out/bin
 
    # We create the bin folder ourselves and link every binary in it
    ln -s ${perl}/bin/* $out/bin
 
    # Except the perl binary
    rm $out/bin/perl
 
    # Because we create this ourself, by creating a wrapper
    makeWrapper ${perl}/bin/perl $out/bin/perl --set PERL5LIB "/etc/perl:${perl5LibRef}/lib/perl5/site_perl/5.28.1"
  ''

I think add this to the machine configurations:

let
  perlWithModules = pkgs.callPackage ../pkgs/perl.nix {
    perl5Lib = with pkgs.perlPackages [ CGI DataDumper DBI URI ... etc... ];
  };
environment.systemPackages = [ perlWithModules ];

Note the reference to “/etc/perl:” is an arbitrary spot I chose where developers on these boxes could install cpan (or their own) perl modules. With some preliminary this seems to work reasonably well. There are a huge number of collisions, though. Are there any problems I haven’t anticipated with this? Is there any way I could do this better?

Would love some feedback.

Thanks

python has withModules function, so you can write

pythonWithModules = python3.withModules(p: [p.lxml])

It should be ported to perl

2 Likes