Perl: Difference between revisions

From NixOS Wiki
imported>Artturin
No edit summary
m ryantm link -> canonical Nixpkgs manual
 
(10 intermediate revisions by 4 users not shown)
Line 1: Line 1:
==Running a Perl script==
== Running a Perl script ==


Common problems and solutions:
=== Replacing #! with nix-shell ===


<code>Can't locate DB_File.pm in @INC (you may need to install the DB_File module)</code>: run it with <code>nix-shell -p perl -p perlPackages.DBFile --run ./myscript.pl</code>
Perl scripts normally start something like this:


<code>./myscript.pl: bad interpreter: /usr/bin/perl: no such file or directory</code>: change the first line of the script to <code>#!/usr/bin/env -S perl</code> or start it with <code>perl ./myscript.pl</code>
<syntaxHighlight lang=shell>
  #!/usr/bin/env perl
</syntaxHighlight>
 
In Nix, we often make isolated environments using [https://nixos.org/manual/nix/unstable/command-ref/nix-shell.html nix-shell]. You can do this in the <code>#!</code> (shabang) section directly in the script too. Here is an example from the manual &mdash; a Perl script that specifies that it requires Perl and the HTML::TokeParser::Simple and LWP packages:
 
<syntaxHighlight lang=perl>
#! /usr/bin/env nix-shell
#! nix-shell -i perl -p perl perlPackages.HTMLTokeParserSimple perlPackages.LWP
 
use HTML::TokeParser::Simple;
 
# Fetch nixos.org and print all hrefs.
my $p = HTML::TokeParser::Simple->new(url => 'http://nixos.org/');
 
while (my $token = $p->get_tag("a")) {
    my $href = $token->get_attr("href");
    print "$href\n" if $href;
}
</syntaxHighlight>
 
=== Invoking nix-shell on command-line ===
 
If you run a perl script and encounter a dependency error like this:
 
<syntaxHighlight lang=shell>
Can't locate DB_File.pm in @INC (you may need to install the DB_File module)
</syntaxHighlight >
 
... use <code>nix-shell</code> to create a shell environment which includes the dependency. Here we searched NixOS packages and found an existing perl package which suits, [https://search.nixos.org/packages?channel=unstable&from=0&size=30&sort=relevance&type=packages&query=dbfile like so].
 
<syntaxHighlight lang=shell>
nix-shell -p perl perl534Packages.DBFile --run ./myscript.pl
</syntaxHighlight >
 
=== There is no /usr/bin/perl ===
By design, there is no <code>/usr/bin/perl</code> in Nix. So you may encounter messages like:
 
<syntaxHighlight lang=shell>
./myscript.pl: bad interpreter: /usr/bin/perl: no such file or directory
</syntaxHighlight>
Change the first line of the script to
<syntaxHighlight lang=shell>
#!/usr/bin/env -S perl
</syntaxHighlight>
 
or start it with <code>perl ./myscript.pl</code>


==Adding something from CPAN to nixpkgs==
==Adding something from CPAN to nixpkgs==


* Use the <tt>nix-generate-from-cpan.pl</tt> script (see <tt>nixpkgs/maintainers/scripts/</tt>) to generate something appropriate.<br/>Example usage: <tt>nix-generate-from-cpan.pl Devel::REPL</tt>
# Enter a <tt>nix-shell</tt> that provides the necessary dependencies: <syntaxHighlight lang=shell>nix-shell -p perl perlPackages.CPANPLUS perlPackages.GetoptLongDescriptive perlPackages.LogLog4perl perlPackages.Readonly</syntaxHighlight>.
* After reviewing the result from the previous step and making appropriate modifications, add it to <code>pkgs/top-level/perl-packages.nix</code>.  Note that some things use <code>buildPerlPackage</code> while some use <code>buildPerlModule</code>.  Also note the mostly-followed naming convention as well as the mostly-followed alphabetical ordering. There are plenty of examples in <tt>perl-packages.nix</tt> &mdash; use the source, Luke!
# Use the <tt>nix-generate-from-cpan.pl</tt> script (see <tt>nixpkgs/maintainers/scripts/</tt>) to generate something appropriate.<br/>Example usage: <syntaxHighlight lang=shell>nix-generate-from-cpan.pl Devel::REPL</syntaxHighlight>
* Build and test.
# After reviewing the result from the previous step and making appropriate modifications, add it to <code>pkgs/top-level/perl-packages.nix</code>.  Note that some things use <code>buildPerlPackage</code> while some use <code>buildPerlModule</code>.  Also note the mostly-followed naming convention as well as the mostly-followed alphabetical ordering. There are plenty of examples in <tt>perl-packages.nix</tt> &mdash; use the source, Luke!
# Build and test.


==Wrappers for installed programs==
==Wrappers for installed programs==


To make perl modules available to a program in your derivation:
To make perl modules available to a program in your derivation:
* add <code>makeWrapper</code> to <code>nativeBuildInputs</code>
# Add <code>makeWrapper</code> to <code>nativeBuildInputs</code>
* add <syntaxhighlight lang="nix">
# Add <syntaxhighlight lang="nix">
postFixup = ''
postFixup = ''
   wrapProgram $out/bin/something \
   wrapProgram $out/bin/something \
Line 23: Line 70:
'';
'';
</syntaxhighlight>
</syntaxhighlight>
 
Also keep in mind that <code>makePerlPath</code> would not resolve transitive dependencies of Perl packages. Hence if you want to just reference top-level packages, then use <code>makeFullPerlPath</code> which would recursively resolve dependency graph for you.
== See also ==
* [https://nixos.org/manual/nixpkgs/stable/#sec-language-perl Nixpkgs Manual - Perl section]
* [https://blog.stigok.com/2020/04/16/building-a-custom-perl-package-for-nixos.html Overriding an existing Perl package in NixOS]
[[Category:Languages]]
[[Category:Languages]]

Latest revision as of 06:47, 21 June 2024

Running a Perl script

Replacing #! with nix-shell

Perl scripts normally start something like this:

  #!/usr/bin/env perl

In Nix, we often make isolated environments using nix-shell. You can do this in the #! (shabang) section directly in the script too. Here is an example from the manual — a Perl script that specifies that it requires Perl and the HTML::TokeParser::Simple and LWP packages:

#! /usr/bin/env nix-shell
#! nix-shell -i perl -p perl perlPackages.HTMLTokeParserSimple perlPackages.LWP

use HTML::TokeParser::Simple;

# Fetch nixos.org and print all hrefs.
my $p = HTML::TokeParser::Simple->new(url => 'http://nixos.org/');

while (my $token = $p->get_tag("a")) {
    my $href = $token->get_attr("href");
    print "$href\n" if $href;
}

Invoking nix-shell on command-line

If you run a perl script and encounter a dependency error like this:

Can't locate DB_File.pm in @INC (you may need to install the DB_File module)

... use nix-shell to create a shell environment which includes the dependency. Here we searched NixOS packages and found an existing perl package which suits, like so.

nix-shell -p perl perl534Packages.DBFile --run ./myscript.pl

There is no /usr/bin/perl

By design, there is no /usr/bin/perl in Nix. So you may encounter messages like:

./myscript.pl: bad interpreter: /usr/bin/perl: no such file or directory

Change the first line of the script to

#!/usr/bin/env -S perl

or start it with perl ./myscript.pl

Adding something from CPAN to nixpkgs

  1. Enter a nix-shell that provides the necessary dependencies:
    nix-shell -p perl perlPackages.CPANPLUS perlPackages.GetoptLongDescriptive perlPackages.LogLog4perl perlPackages.Readonly
    
    .
  2. Use the nix-generate-from-cpan.pl script (see nixpkgs/maintainers/scripts/) to generate something appropriate.
    Example usage:
    nix-generate-from-cpan.pl Devel::REPL
    
  3. After reviewing the result from the previous step and making appropriate modifications, add it to pkgs/top-level/perl-packages.nix. Note that some things use buildPerlPackage while some use buildPerlModule. Also note the mostly-followed naming convention as well as the mostly-followed alphabetical ordering. There are plenty of examples in perl-packages.nix — use the source, Luke!
  4. Build and test.

Wrappers for installed programs

To make perl modules available to a program in your derivation:

  1. Add makeWrapper to nativeBuildInputs
  2. Add
    postFixup = ''
      wrapProgram $out/bin/something \
        --prefix PERL5LIB : "${with perlPackages; makePerlPath [ something ]}"
    '';
    

Also keep in mind that makePerlPath would not resolve transitive dependencies of Perl packages. Hence if you want to just reference top-level packages, then use makeFullPerlPath which would recursively resolve dependency graph for you.

See also