Perl Diving with Nix
This is a record of my time in the Summer of Nix holding my breath and diving into the depths of Nix to gain some Perls of wisdom.
Going through the issues assigned to my team I came across the the package for OpenFoodFacts a collaborative database that collects and provides open data on 1 million food products from around the world and counting!
Not knowing what we are eating seems like a strange thing but really how much do we know what goes into those vacuum packed bags that we open and consume daily?
“We are living in a world today where lemonade is made from artificial flavors and furniture polish is made from real lemons.” – Alfred E. Newman
OpenFoodFacts I see your quote and raise you a Newman!
Anyway enough preamble…
This project represents a deviation from the common usage of Nix to create derivations that package binaries, instead its main application Product Opener is a large app that requires many languages and dependencies which end up as a web service.
The back-end is served using Apache with the Perl Module (modules being how Apache is extended) mod_perl enabled, this embeds a Perl interpreter into the Apache server which handles the production of dynamic content.
As you can imagine there is a lot of Perl which is dynamically loaded by the Apache config file.
A word to the wise… there is a lot that goes into an Apache config file and the wonder of Nix is that it abstracts most of it away including the loading of the above-mentioned Apache modules. Unless you really know what your doing it’s best to use the extraConfig
option, which appends configuration to the Nix auto-generated one as it has many twists and turns. It is possible to override the configuration file completely with the configFile
option, but make sure you understand the auto-generated one first.
To have a look for your self run nix build nixpkgs#apacheHttpd && cd result/conf
.
A minimal ApacheHttpd configuration in Nix:
services.httpd = {
enable = true;
enablePerl = true;
adminAddr = "test@test.com";
extraConfig = builtins.readFile "${src}/apache.conf";
};
That enablePerl
option is what loads up mod_perl for us :hands-up:
Slight detour into Perl: CPAN stands for Comprehensive Perl Archive Network and serves as the central repository for Perl modules. One way of defining the dependencies of a Perl project is writing plain text file called cpanfile
that requires all the modules to be loaded from CPAN.
So before even looking into the code contained in the project my first step was looking at all the Perl dependencies that were cataloged in the cpanfile… of which there were 65…
requires 'CGI', '>= 4.51, < 5.0'; # libcgi-pm-perl
requires 'Tie::IxHash'; # libtie-ixhash-perl
requires 'LWP::Authen::Digest'; # libwww-perl
requires 'LWP::Simple'; # libwww-perl
etc.
In the nix community there is a ever growing list of 2nix tools that translates one package managers lock files into something that fits within the nix ecosystem of immutable declarative packaging. It was at this point that I started wondering if there were any tools like that for Perl.
The short answer is no, but there are some there is some great support for adding something from meta::cpan (a repository containing it seems the Perl universe) to nixpkgs, in the form of the function nix-generate-from-cpan
which is also exposed as a utility in nixpkgs.
nix run nixpkgs#nix-generate-from-cpan <CPAN::MODULE>
for the win!
So a few nix run nixpkgs#nix-generate-from-cpan <Perl::Module>
’s later I had 40 odd shiny new Perl packages :)
This utility was great but perhaps the reason there isn’t a 2nix tool for the Perl world is that it is not fool proof… in my experience it just worked™ 70% of the time with the other 30% of the time needing minor fixes (either adding pkgs to the propagated inputs or nix-generate-from-cpan
a Perl package that was needed as a dependency).
This might be an issue with the Perl ecosystem itself as a cpanfile !=
a lock file and as the above example demonstrates it can be very vague (>=4.51, < 5.0
) and vagueness is the enemy of reproducible and thus the enemy of Nix.
However in one case it failed drastically, and truth be told I was stuck on which way to go for a few days.
The intransigent bugger was Barcode::Zbar a module that provides a Perl interface to the ZBar Barcode Reader OpenFoodFacts has the rather excellent feature where you can just scan a bar code as a discovery mechanism.
The aforementioned nix-generate-from-cpan
kindly provided
BarcodeZBar = buildPerlPackage {
pname = "Barcode-ZBar";
version = "0.04";
src = fetchurl {
url = "mirror://cpan/authors/id/S/SP/SPADIX/Barcode-ZBar-0.04.tar.gz";
sha256 = "d57e1ad471b6a29fa4134650e6eec9eb834d42cbe8bf8f0608c67d6dd0f8f431";
};
meta = {
};
};
Hmmm rather bare, didn’t even include the Zbar binary as part of its propagatedBuildInputs
.
SideNote: propagatedBuildInputs
here meaning anything that is a runtime dependency whereas buildInputs
are for dependencies that are exclusively build-time dependencies (eg. Tests and make file generators) - Perl Packaging in Nix
After fixing the inputs it was time to give it a try.
buildInputs = [ TestMore ExtUtilsMakeMaker ];
propagatedBuildInputs = [ zbar PerlMagick ];
Where upon it failed with the message:
perl5.34.0-Barcode-ZBar> ZBar.xs: In function 'XS_Barcode__ZBar_version':
perl5.34.0-Barcode-ZBar> ZBar.xs:202:9: error: too few arguments to function 'zbar_version'
Hmmmm on investigation it seems this module was last updated in 2009 and since then the zbar
project has been forked and continued developing. The ZBar project now uses semver versioning while the module is stuck in the past with major.minor
versioning.
Nixpkgs topping repology’s list for Projects up to date obviously meant that it wasn’t slouching when it came to zbar and had zoomed ahead of the Perl module to version 0.23.90
(it was never clear what version the module was expecting but 2009 put it at either 0.9
or 0.10
).
It appeared to me that I had two options 1. Naively patch this function so it takes 3 arguments in the Perl module and hope that works. 2. More realistically create an overlay for zbar for a version that was compatible with the Perl Module.
Option 1 - The Patch
Summer of Nix is all about learning so I figured it was worth a shot and after a quick watch of the excellent How to create a patch for any package by Jon Ringer (go check it out) and a quick fiddle in git I had a patch file.
From e51b51a77eab1251babc58929a4d2107172a041f Mon Sep 17 00:00:00 2001
From: Thomas Sean Dominic Kelly <thomassdk@pm.me>
Date: Fri, 6 Aug 2021 12:35:06 +0100
Subject: [PATCH] version patch
---
ZBar.xs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/ZBar.xs b/ZBar.xs
index ad6fc56..97bd2c0 100644
--- a/ZBar.xs
+++ b/ZBar.xs
@@ -198,9 +198,10 @@ zbar_version()
PREINIT:
unsigned major;
unsigned minor;
+ unsigned patch;
CODE:
- zbar_version(&major, &minor);
- RETVAL = newSVpvf("%u.%u", major, minor);
+ zbar_version(&major, &minor, &patch);
+ RETVAL = newSVpvf("%u.%u.%u", major, minor, patch);
OUTPUT:
RETVAL
--
2.32.0
Applying patches in nix is the simplest thing in the world just add it to the patch phase and your golden. The manual is a bit sparse in this regard so the code looks something like.
patchPhase = [ ./version.patch ];
This is possible as buildPerlPackage
is built on top of stdenv
allowing us to customise everything in the usual Nixy way.
Aha something is happening it seems to successfully compile but fails the tests.
The full logs are below but TLDR the salient line seems to be:
#Error: Can't load '/build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so' for module Barcode::ZBar: /build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so: undefined symbol: zbar_scanner_reset at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/x86_64-linux-thread-multi/DynaLoader.pm line 193.
Ooof undefined symbol OK so the module is looking for a symbol and not finding it in the zbar shared object.
There goes my naivety.
Logs
Click to see full logs
this derivation will be built:
/nix/store/gww59146rs399rjc3fnawrjng4pqf6dl-perl5.32.1-Barcode-ZBar-0.04.drv
building '/nix/store/gww59146rs399rjc3fnawrjng4pqf6dl-perl5.32.1-Barcode-ZBar-0.04.drv'...
unpacking sources
unpacking source archive /nix/store/g5kazmm00923w6rgcf5h6rzrlp7b1nhj-Barcode-ZBar-0.04.tar.gz
source root is Barcode-ZBar-0.04
setting SOURCE_DATE_EPOCH to timestamp 1256327204 of file Barcode-ZBar-0.04/META.yml
patching sources
applying patch /nix/store/3ix6dz6lmifqrmbs24jbjh9z07wbscbi-0001-version-patch.patch
patching file ZBar.xs
configuring
patching ./examples/processor.pl...
patching ./examples/scan_image.pl...
patching ./examples/read_one.pl...
patching ./examples/paginate.pl...
Checking if your kit is complete...
Looks good
Use of uninitialized value $thispth in concatenation (.) or string at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/Liblist/Kid.pm line 162.
Use of uninitialized value $thispth in concatenation (.) or string at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/Liblist/Kid.pm line 166.
Use of uninitialized value $thispth in concatenation (.) or string at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/Liblist/Kid.pm line 171.
Use of uninitialized value $thispth in concatenation (.) or string at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/Liblist/Kid.pm line 173.
Use of uninitialized value $thispth in concatenation (.) or string at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/Liblist/Kid.pm line 181.
Use of uninitialized value $thispth in concatenation (.) or string at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/Liblist/Kid.pm line 183.
Use of uninitialized value $thispth in concatenation (.) or string at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/Liblist/Kid.pm line 187.
Warning (mostly harmless): No library found for -lzbar
Generating a Unix-style Makefile
Writing Makefile for Barcode::ZBar
Invalid LICENSE value 'lgpl' ignored
Writing MYMETA.yml and MYMETA.json
no configure script, doing nothing
building
build flags: SHELL=/nix/store/xvvgw9sb8wk6d2c0j3ybn7sll67s3s4z-bash-4.4-p23/bin/bash
cp ZBar.pm blib/lib/Barcode/ZBar.pm
cp ZBar/Processor.pod blib/lib/Barcode/ZBar/Processor.pod
cp ZBar/ImageScanner.pod blib/lib/Barcode/ZBar/ImageScanner.pod
cp ZBar/Image.pod blib/lib/Barcode/ZBar/Image.pod
cp ZBar/Symbol.pod blib/lib/Barcode/ZBar/Symbol.pod
Running Mkbootstrap for ZBar ()
chmod 644 "ZBar.bs"
"/nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/bin/perl" -MExtUtils::Command::MM -e 'cp_nonempty' -- ZBar.bs blib/arch/auto/Barcode/ZBar/ZBar.bs 644
"/nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/bin/perl" "/nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/xsubpp" -typemap '/nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/ExtUtils/typemap' -typemap '/build/Barcode-ZBar-0.04/typemap' ZBar.xs > ZBar.xsc
mv ZBar.xsc ZBar.c
cc -c -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/no-such-path/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -DVERSION=\"0.04\" -DXS_VERSION=\"0.04\" -fPIC "-I/nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/x86_64-linux-thread-multi/CORE" ZBar.c
rm -f blib/arch/auto/Barcode/ZBar/ZBar.so
cc -shared -O2 -L/nix/store/gk42f59363p82rg2wv2mfy71jn5w4q4c-glibc-2.32-48/lib -fstack-protector-strong ZBar.o -o blib/arch/auto/Barcode/ZBar/ZBar.so \
\
chmod 755 blib/arch/auto/Barcode/ZBar/ZBar.so
Manifying 5 pod documents
running tests
check flags: SHELL=/nix/store/xvvgw9sb8wk6d2c0j3ybn7sll67s3s4z-bash-4.4-p23/bin/bash VERBOSE=y test
"/nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/bin/perl" -MExtUtils::Command::MM -e 'cp_nonempty' -- ZBar.bs blib/arch/auto/Barcode/ZBar/ZBar.bs 644
PERL_DL_NONLAZY=1 "/nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/Decoder.t ....... 1/13
# Failed test 'use Barcode::ZBar;'
# at t/Decoder.t line 10.
# Tried to use 'Barcode::ZBar'.
# Error: Can't load '/build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so' for module Barcode::ZBar: /build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so: undefined symbol: zbar_scanner_reset at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/x86_64-linux-thread-multi/DynaLoader.pm line 193.
# at t/Decoder.t line 10.
# Compilation failed in require at t/Decoder.t line 10.
# BEGIN failed--compilation aborted at t/Decoder.t line 10.
Bareword "Barcode::ZBar::Symbol::PARTIAL" not allowed while "strict subs" in use at t/Decoder.t line 48.
Bareword "Barcode::ZBar::Symbol::NONE" not allowed while "strict subs" in use at t/Decoder.t line 27.
Bareword "Barcode::ZBar::SPACE" not allowed while "strict subs" in use at t/Decoder.t line 57.
Bareword "Barcode::ZBar::Symbol::QRCODE" not allowed while "strict subs" in use at t/Decoder.t line 61.
Bareword "Barcode::ZBar::Config::ENABLE" not allowed while "strict subs" in use at t/Decoder.t line 61.
Bareword "Barcode::ZBar::Symbol::PARTIAL" not allowed while "strict subs" in use at t/Decoder.t line 69.
Bareword "Barcode::ZBar::Symbol::NONE" not allowed while "strict subs" in use at t/Decoder.t line 69.
Bareword "Barcode::ZBar::Symbol::EAN13" not allowed while "strict subs" in use at t/Decoder.t line 73.
Bareword "Barcode::ZBar::BAR" not allowed while "strict subs" in use at t/Decoder.t line 81.
Bareword "Barcode::ZBar::Symbol::EAN13" not allowed while "strict subs" in use at t/Decoder.t line 85.
Execution of t/Decoder.t aborted due to compilation errors.
# Looks like your test exited with 255 just after 1.
t/Decoder.t ....... Dubious, test returned 255 (wstat 65280, 0xff00)
Failed 13/13 subtests
t/Image.t ......... 1/22
# Failed test 'use Barcode::ZBar;'
# at t/Image.t line 10.
# Tried to use 'Barcode::ZBar'.
# Error: Can't load '/build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so' for module Barcode::ZBar: /build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so: undefined symbol: zbar_scanner_reset at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/x86_64-linux-thread-multi/DynaLoader.pm line 193.
# at t/Image.t line 10.
# Compilation failed in require at t/Image.t line 10.
# BEGIN failed--compilation aborted at t/Image.t line 10.
Bareword "Barcode::ZBar::Symbol::EAN13" not allowed while "strict subs" in use at t/Image.t line 101.
Execution of t/Image.t aborted due to compilation errors.
# Looks like your test exited with 255 just after 1.
t/Image.t ......... Dubious, test returned 255 (wstat 65280, 0xff00)
Failed 22/22 subtests
t/pod-coverage.t .. skipped: Test::Pod::Coverage required for testing pod coverage
t/pod.t ........... skipped: Test::Pod 1.00 required for testing POD
t/Processor.t ..... 1/20
# Failed test 'use Barcode::ZBar;'
# at t/Processor.t line 10.
# Tried to use 'Barcode::ZBar'.
# Error: Can't load '/build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so' for module Barcode::ZBar: /build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so: undefined symbol: zbar_scanner_reset at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/x86_64-linux-thread-multi/DynaLoader.pm line 193.
# at t/Processor.t line 10.
# Compilation failed in require at t/Processor.t line 10.
# BEGIN failed--compilation aborted at t/Processor.t line 10.
Bareword "Barcode::ZBar::Symbol::EAN13" not allowed while "strict subs" in use at t/Processor.t line 58.
Execution of t/Processor.t aborted due to compilation errors.
# Looks like your test exited with 255 just after 1.
t/Processor.t ..... Dubious, test returned 255 (wstat 65280, 0xff00)
Failed 20/20 subtests
t/Scanner.t ....... 1/3
# Failed test 'use Barcode::ZBar;'
# at t/Scanner.t line 10.
# Tried to use 'Barcode::ZBar'.
# Error: Can't load '/build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so' for module Barcode::ZBar: /build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so: undefined symbol: zbar_scanner_reset at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/x86_64-linux-thread-multi/DynaLoader.pm line 193.
# at t/Scanner.t line 10.
# Compilation failed in require at t/Scanner.t line 10.
# BEGIN failed--compilation aborted at t/Scanner.t line 10.
Can't locate object method "new" via package "Barcode::ZBar::Scanner" (perhaps you forgot to load "Barcode::ZBar::Scanner"?) at t/Scanner.t line 14.
# Looks like your test exited with 255 just after 1.
t/Scanner.t ....... Dubious, test returned 255 (wstat 65280, 0xff00)
Failed 3/3 subtests
t/ZBar.t .......... 1/3
# Failed test 'use Barcode::ZBar;'
# at t/ZBar.t line 10.
# Tried to use 'Barcode::ZBar'.
# Error: Can't load '/build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so' for module Barcode::ZBar: /build/Barcode-ZBar-0.04/blib/arch/auto/Barcode/ZBar/ZBar.so: undefined symbol: zbar_scanner_reset at /nix/store/n7hbdyp3bsmdxy2lcxivaxnq4nv8ndv3-perl-5.32.1/lib/perl5/5.32.1/x86_64-linux-thread-multi/DynaLoader.pm line 193.
# at t/ZBar.t line 10.
# Compilation failed in require at t/ZBar.t line 10.
# BEGIN failed--compilation aborted at t/ZBar.t line 10.
Undefined subroutine &Barcode::ZBar::version called at t/ZBar.t line 14.
# Looks like your test exited with 255 just after 1.
t/ZBar.t .......... Dubious, test returned 255 (wstat 65280, 0xff00)
Failed 3/3 subtests
Test Summary Report
-------------------
t/Decoder.t (Wstat: 65280 Tests: 1 Failed: 1)
Failed test: 1
Non-zero exit status: 255
Parse errors: Bad plan. You planned 13 tests but ran 1.
t/Image.t (Wstat: 65280 Tests: 1 Failed: 1)
Failed test: 1
Non-zero exit status: 255
Parse errors: Bad plan. You planned 22 tests but ran 1.
t/Processor.t (Wstat: 65280 Tests: 1 Failed: 1)
Failed test: 1
Non-zero exit status: 255
Parse errors: Bad plan. You planned 20 tests but ran 1.
t/Scanner.t (Wstat: 65280 Tests: 1 Failed: 1)
Failed test: 1
Non-zero exit status: 255
Parse errors: Bad plan. You planned 3 tests but ran 1.
t/ZBar.t (Wstat: 65280 Tests: 1 Failed: 1)
Failed test: 1
Non-zero exit status: 255
Parse errors: Bad plan. You planned 3 tests but ran 1.
Files=7, Tests=5, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.20 cusr 0.03 csys = 0.25 CPU)
Result: FAIL
Failed 5/7 test programs. 5/5 subtests failed.
make: *** [Makefile:1040: test_dynamic] Error 255
error: builder for '/nix/store/gww59146rs399rjc3fnawrjng4pqf6dl-perl5.32.1-Barcode-ZBar-0.04.drv' failed with exit code 2;
last 10 log lines:
> Non-zero exit status: 255
> Parse errors: Bad plan. You planned 3 tests but ran 1.
> t/ZBar.t (Wstat: 65280 Tests: 1 Failed: 1)
> Failed test: 1
> Non-zero exit status: 255
> Parse errors: Bad plan. You planned 3 tests but ran 1.
> Files=7, Tests=5, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.20 cusr 0.03 csys = 0.25 CPU)
> Result: FAIL
> Failed 5/7 test programs. 5/5 subtests failed.
> make: *** [Makefile:1040: test_dynamic] Error 255
For full logs, run 'nix log /nix/store/gww59146rs399rjc3fnawrjng4pqf6dl-perl5.32.1-Barcode-ZBar-0.04.drv'.
Option 2: The Overlay
Naive approach 2 lets just overlay the source code with 0.10
a version from 2009…
This wasn’t very successful as it seems the steps to build ZBar has changed significantly between versions.
However I chose 0.10 not only for the fact that it was from 2009 but also this was the oldest version in nixpkgs.
So lets substitute the current package with an this old one.
A handy tool I found along the way was Nix package versions which gives a nice web interface for finding older versions of packages and giving you the revision that they were in.
Armed with a really hacky zbar overlay lets try this again.
zbar = final: prev: {
zbar = (import (builtins.fetchGit {
url = "https://github.com/NixOS/nixpkgs/";
ref = "refs/heads/nixpkgs-unstable";
rev = "12408341763b8f2f0f0a88001d9650313f6371d5";
}) { system = "x86_64-linux"; }).zbar;
};
Sidenote: A more nixy way of doing this would be to import this ancient version of nixpkgs as an input into your flake:
inputs.nixpkgs-ancient = {
url = "github:NixOS/nixpkgs?rev=12408341763b8f2f0f0a88001d9650313f6371d5";
flake = false;
}
and then use it via:
zbar = final.callPackage ./zbar.nix { pkgs = final; pkgsAncient = import nixpkgs-ancient { system = final.system; }; };
where zbar.nix
is:
{ pkgs, pkgsAncient }:
let zbar = pkgsAncient.zbar; in
with pkgs;
with perlPackages;
buildPerlPackage {
pname = "Barcode-ZBar";
version = "0.04";
src = fetchurl {
url = "mirror://cpan/authors/id/S/SP/SPADIX/Barcode-ZBar-0.04.tar.gz";
sha256 = "d57e1ad471b6a29fa4134650e6eec9eb834d42cbe8bf8f0608c67d6dd0f8f431";
};
doCheck = true;
buildInputs = [ pkg-config TestMore ExtUtilsMakeMaker TestHarness ];
propagatedBuildInputs = [ zbar PerlMagick ];
meta = {
homepage = "https://github.com/mchehab/zbar";
description = "Perl interface to the ZBar Barcode Reader";
license = with lib.licenses; [ gpl2Plus ];
};
}
Thanks to Las for this flakier way of doing things.
Sadly this still fails with the undefined symbol
error so it seems we need an ever more ancient version of Zbar
Where things float
It seems that we have reached the point of diminishing returns and that it does not seem worth while to figure out how to build ever older versions of ZBar in the hope that this might someday work.
So what next?
Perhaps we can convince upstream to take on the maintenance of this Perl module and bring it (and their own project) kicking and screaming into the decade of the ’20s.
Sometimes your brain just needs some downtime
A few days after putting this project on the back burner I woke up with an inexplicable renewed enthusiasm for tackling this issue.
Looking back through all the resources I noticed that the maintained version of ZBar
has a series of folders named after various programming languages and platforms, including Perl.
Interesting…
It seems that when forking ZBar mchehab, the new maintainer, also made the sage decision to include all the myriad interfaces for the library and maintain them!
Armed with this new Perl module that we knew worked with the latest ZBar library it was possible to construct a new buildPerlPackage
that reused the src from the ZBar packaged in nixpkgs.
BarcodeZBar = buildPerlPackage {
pname = "Barcode-ZBar";
version = "0.04";
src = "${zbar.src}/perl";
postPatch = ''
substituteInPlace Makefile.PL --replace "-lzbar" "-L${zbar.lib}/lib -lzbar"
# This test requires network access
rm t/Processor.t
'';
doCheck = true;
buildInputs = [ TestPodCoverage TestPod DevelChecklib TestMore ExtUtilsMakeMaker ];
propagatedBuildInputs = [ zbar PerlMagick ];
meta = {
homepage = "https://github.com/mchehab/zbar/tree/master/perl";
description = "Perl interface to the ZBar Barcode Reader";
license = with lib.licenses; [ gpl2Plus ];
};
};
Et Voila we have a Perl Module that interfaces with the current version of ZBar!
Addendum
The keen-eyed among you will have noticed that there is a bit of trickery happening with the postPatch
hook.
Perl has the incredibly unhelpful error command:
Warning (mostly harmless): No library found for -lzbar
As you can imagine this is unquestionably harmful and causes the tests, and of lesser importance the final output 😛, to fail.
This happens because for some reason our propagatedBuildInputs not being added to the sandbox for the Makefile through the use of propagatedBuildInputs
(which adds paths to NIX_LDFLAGS
). Instead these had to be added manually by linking them directly in the Makefile.
It is unclear to me why this is and perhaps a issue needs to be opened that addresses this.
A quick refresher on NIX_LDFLAGS
.
Nix differs drastically from other Linux distributions (and in difference is strength) and does not store header files and libraries in the traditional /usr/include
where the compiler expects them, instead everything is in the Nix Store… Which means that somehow we need to make the compiler aware of the correct paths to these headers and libraries. This is where NIX_LDFLAGS
(and its partner in compile NIX_CFLAGS_COMPILE
) come in. The ALL CAPS should give you a clue that they are environment variables which are used to furnish the compiler (by way of command line arguments) with these correct paths. This is all done using shell-scripts that wrap around the actual compiler, for more information see the C section on the Nixos Wiki.