Custom printer driver not loaded

Hello,

I am trying to package the driver for my printer (Brother DCP2520DW) to upstream it after testing it but after adding it by following the steps given in the wiki as such :

let
  my_printer = pkgs.callPackage ../../pkgs/printer/dcp2520dw.nix {};
in
# ... [ non relevant part of the configuration ]
services.printing = {
      enable = true;
      drivers =
      [        my_printer # Enable my Brother DCP2520DW configuration
      ];
    };

where dcp2520dw.nix is an adaptation of an already nixpkgs packaged derivation (brgenml1lpr) :

{ stdenv, fetchurl, pkgsi686Linux, dpkg, makeWrapper, coreutils, gnused, gawk, file, cups, utillinux, xxd, runtimeShell, ghostscript, a2ps, which, perl, glibc}:

# LPR : https://download.brother.com/welcome/dlf101759/dcpl2520dwlpr-3.2.0-1.i386.deb
let
  myPatchElf = file: with stdenv.lib; ''
    patchelf --set-interpreter \
      ${stdenv.glibc}/lib/ld-linux${optionalString stdenv.is64bit "-x86-64"}.so.2 \
      ${file}
  '';
in
stdenv.mkDerivation rec {
  name = "dcpl2520dwlpr-${version}";
  version = "3.2.0-1";
  src = fetchurl {
    url =
      "https://download.brother.com/welcome/dlf101759/dcpl2520dwlpr-${version}.i386.deb";
    sha256 = "0zzlx5gasg0ma8y6484rkg6s18ig0xz930yfa4y1rgzs20xlx8l1";
  };

  nativeBuildInputs = [ makeWrapper ];
  buildInputs = [ cups ghostscript dpkg a2ps which perl glibc ];
  unpackPhase = ''
    ar x $src
    tar xfvz data.tar.gz
  '';

  patchPhase = ''
    INFDIR=opt/brother/Printers/DCPL2520DW/inf
    LPDDIR=opt/brother/Printers/DCPL2520DW/lpd
    # Setup max debug log by default.
    substituteInPlace $LPDDIR/filter_DCPL2520DW \
      --replace "BR_PRT_PATH =~" "BR_PRT_PATH = \"$out/opt/brother/Printers/DCPL2520DW\"; #" \
      --replace "PRINTER =~" "PRINTER = \"DCPL2520DW\"; #"
    ${myPatchElf "$INFDIR/braddprinter"}
    ${myPatchElf "$LPDDIR/brprintconflsr3"}
    ${myPatchElf "$LPDDIR/rawtobr3"}
  '';

  installPhase = ''
    INFDIR=opt/brother/Printers/DCPL2520DW/inf
    LPDDIR=opt/brother/Printers/DCPL2520DW/lpd
    mkdir -p $out/$INFDIR
    cp -rp $INFDIR/* $out/$INFDIR
    mkdir -p $out/$LPDDIR
    cp -rp $LPDDIR/* $out/$LPDDIR
    wrapProgram $out/$LPDDIR/filter_DCPL2520DW \
      --prefix PATH ":" "${ghostscript}/bin" \
      --prefix PATH ":" "${which}/bin"
  '';

  dontPatchELF = true;
}

I do not get any fields in the GNOME System Printer to select as a driver. Why ?

N.B. : the package build fine with nix-build.

Could you show us the tree of your build (tree ./result)? Maybe there’s a problem with the file’s layout which makes services.printing.drivers not include it in your /etc/cups or whatever…

Thank you so much for taking the time to respond.

So actually, the mystery deepens :
I figured that if I wanted the driver to work at least with CUPS, I would have to use the CUPS wrapper (whose the source is included in the spoiler at the end of this post) but when building I do not get the same files (cf log down) as when I do with the same URL ! I am baffled at that and trying to make sense of that now… Of course I am doing something dumb but I do not see what.

Log from the build
building '/nix/store/42wnj5ly9capmw46c75m9x1w0gqppipg-dcpl2520dwcupswrapper-3.2.0-1.drv'...
unpacking sources
./
./usr/
./usr/share/
./usr/share/doc/
./opt/
./opt/brother/
./opt/brother/Printers/
./opt/brother/Printers/BrGenML1/
./opt/brother/Printers/BrGenML1/cupswrapper/
./opt/brother/Printers/BrGenML1/cupswrapper/brother-BrGenML1-cups-en.ppd
./opt/brother/Printers/BrGenML1/cupswrapper/brother_lpdwrapper_BrGenML1
./opt/brother/Printers/BrGenML1/cupswrapper/paperconfigml1
patching sources
substitute(): ERROR: file 'opt/brother/Printers/DCPL2520DW/cupswrapper/brother_lpdwrapper_DCPL2520DW' does not exist
Log from the manual extracting
./usr/
./usr/share/
./usr/share/doc/
./etc/
./etc/opt/
./etc/opt/brother/
./etc/opt/brother/Printers/
./etc/opt/brother/Printers/DCPL2520DW/
./etc/opt/brother/Printers/DCPL2520DW/inf/
./opt/
./opt/brother/
./opt/brother/Printers/
./opt/brother/Printers/DCPL2520DW/
./opt/brother/Printers/DCPL2520DW/inf/
./opt/brother/Printers/DCPL2520DW/inf/brDCPL2520DWfunc
./opt/brother/Printers/DCPL2520DW/inf/brDCPL2520DWrc
./opt/brother/Printers/DCPL2520DW/inf/braddprinter
./opt/brother/Printers/DCPL2520DW/inf/setupPrintcap
./opt/brother/Printers/DCPL2520DW/lpd/
./opt/brother/Printers/DCPL2520DW/lpd/brprintconflsr3
./opt/brother/Printers/DCPL2520DW/lpd/filter_DCPL2520DW
./opt/brother/Printers/DCPL2520DW/lpd/rawtobr3
./var/
./var/spool/
./var/spool/lpd/
./var/spool/lpd/DCPL2520DW/
CUPS wrapper derivation source
{ stdenv, fetchurl, makeWrapper, cups, perl, coreutils, gnused, gnugrep
, dcpl2520dwlpr, debugLvl ? "0"}:

stdenv.mkDerivation rec {

  name = "dcpl2520dwcupswrapper-3.2.0-1";
  src = fetchurl {
    url = "https://download.brother.com/welcome/dlf101760/${name}.i386.deb";
    sha256 = "0kd2a2waqr10kfv1s8is3nd5dlphw4d1343srdsbrlbbndja3s6r";
  };

  unpackPhase = ''
    ar x $src
    tar xfvz data.tar.gz
  '';

  nativeBuildInputs = [ makeWrapper ];
  buildInputs = [ cups perl coreutils gnused gnugrep dcpl2520dwlpr ];

  dontBuild = true;

  patchPhase = ''
    WRAPPER=opt/brother/Printers/DCPL2520DW/cupswrapper/brother_lpdwrapper_DCPL2520DW
    PAPER_CFG=opt/brother/Printers/DCPL2520DW/cupswrapper/paperconfigml1

    substituteInPlace $WRAPPER \
      --replace "basedir =~" "basedir = \"${dcpl2520dwlpr}/opt/brother/Printers/DCPL2520DW\"; #" \
      --replace "PRINTER =~" "PRINTER = \"DCPL2520DW\"; #" \
      --replace "\$DEBUG=0;" "\$DEBUG=${debugLvl};"

    # Fixing issue #1 and #2.
    substituteInPlace $WRAPPER \
      --replace "\`cp " "\`cp -p " \
      --replace "\$TEMPRC\`" "\$TEMPRC; chmod a+rw \$TEMPRC\`" \
      --replace "\`mv " "\`cp -p "

    # This config script make this assumption that the *.ppd are found in a global location `/etc/cups/ppd`.
    substituteInPlace $PAPER_CFG \
      --replace "/etc/cups/ppd" "$out/share/cups/model"
  '';


  installPhase = ''
    CUPSFILTER_DIR=$out/lib/cups/filter
    CUPSPPD_DIR=$out/share/cups/model
    CUPSWRAPPER_DIR=opt/brother/Printers/DCPL2520DW/cupswrapper

    mkdir -p $out/$CUPSWRAPPER_DIR
    cp -rp $CUPSWRAPPER_DIR/* $out/$CUPSWRAPPER_DIR

    mkdir -p $CUPSFILTER_DIR
    # Fixing issue #4.
    makeWrapper \
      $out/$CUPSWRAPPER_DIR/brother_lpdwrapper_DCPL2520DW \
      $CUPSFILTER_DIR/brother_lpdwrapper_DCPL2520DW \
      --prefix PATH : ${coreutils}/bin \
      --prefix PATH : ${gnused}/bin \
      --prefix PATH : ${gnugrep}/bin

    mkdir -p $CUPSPPD_DIR
    ln -s $out/$CUPSWRAPPER_DIR/brother-DCPL2520DW-cups-en.ppd $CUPSPPD_DIR
  '';

  dontPatchELF = true;
  dontStrip = true;

}

I obviously updated the previous script (cited above) to this :


{ config, pkgs, lib, ... }:

with lib;
let
  dcp2520dw_lpr = pkgs.callPackage ../../pkgs/dcp2520dw-lpr.nix {};
  dcp2520dw_cups = pkgs.callPackage ../../pkgs/dcp2520dw-cups.nix {dcpl2520dwlpr = dcp2520dw_lpr; };
in
{
 #  [...]
    services.printing = {
      # Enable CUPS to print documents.
      enable = true;
      drivers =
        [
          # Enable my Brother DCP2520DW configuration
          dcp2520dw_lpr # LPR driver
          dcp2520dw_cups # CUPS wrapper
        ];
    };
  };

}

Continue the investigation with me :

I tried to take a look at the derivation of the source of the CUPS wrapper and it does not match ;

Here is the derivation (given by invocation to nix show-derivation) of the CUPS wrapper :

{
  "/nix/store/a0cbi93vjmn95z0px1szjmxj23g2vqzm-dcpl2520dwcupswrapper-3.2.0-1.drv": {
# [...]
"src": "/nix/store/pxi1n9d3brv04i7w5dhc0c0yss65fa37-dcpl2520dwcupswrapper-3.2.0-1.i386.deb",
# [...]
}
}

Then looking at the derivation of the source :

{
  "/nix/store/5wynlb63wdm6z7lhfl1bz5nwqsmmplqx-dcpl2520dwcupswrapper-3.2.0-1.i386.deb.drv": {
# [...]
    "outputs": {
      "out": {
        "path": "/nix/store/pxi1n9d3brv04i7w5dhc0c0yss65fa37-dcpl2520dwcupswrapper-3.2.0-1.i386.deb",
        "hashAlgo": "sha256",
        "hash": "d9e8a164b36bd1bc74cb7a90111ae1f0d2569a1d3a221db69b2064acb850a24d"
      }
# [...]
     }
}

Two notable things :

  • I am really talking about the same source file (check both "src" from the first and "path" from the second).
  • The hash from the derivation of the source is not the same as the one given in the script posted above (quoted below)

Why am I seeing those discrepancies ? Am I making the wrong assumptions about the hash of derivations and their sources ?

This would explain why the extracted source is the not the same as the one I am seeing by doing it downloading and extracting manually… but does not tell me how to package the drivers for NixOS…

The issue is solved quite simply : provide the correct for the source or Nix will pick the wrong one.

Yes, it’s a fixed output derivation.
So the store hash doesn’t depend on the inputs, it merely depends on the hash that you gave.
The advantage is, that we can get the same output in multiple different ways.
In your case the URL was already downloaded and cached, so nix assumes it’s the same for the other URL, where the output hash is the same.