0

I'm currently trying to package some closed-source software into Nix derivations. The app is distributed as a large pile of .deb files, and most of them contain libraries that the other parts of the app can use.

To simplify, assume that app.deb contains the actual application, and lib.deb contains a library that the app requires.

Currently I have:

# default.nix
let
  nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-23.11";
  pkgs = import nixpkgs {
    config = { };
    overlays = [ ];
  };
in {
  lib = pkgs.callPackage ./lib.nix { };
  app = pkgs.callPackage ./app.nix { };
}
# lib.nix
{ lib, stdenv, autoPatchelfHook, dpkg, requireFile,
libcxx, libgcc, }:

stdenv.mkDerivation {
  pname = "myapp-lib";
  version = "1.0.0";
  src = requireFile {
    name = "lib.deb";
    sha256 = "313e8686118ccba397de0bdfca101f1053b758227fd9d3510ea78644f2450bfe";
    url = "https://softwarecorp.example/downloads";
  };

  nativeBuildInputs = [
    dpkg
    autoPatchelfHook
  ];

  unpackPhase = "dpkg-deb -x $src .";

  buildInputs = [ libcxx libgcc ];

  installPhase = ''
    cp -r lib $out/
  '';
}
# app.nix
{ lib, stdenv, autoPatchelfHook, dpkg, requireFile,
libcxx, }:

stdenv.mkDerivation {
  pname = "myapp-bin";
  version = "1.0.0";
  src = requireFile {
    name = "app.deb";
    sha256 = "f4abbdb3f83d982569c5cd30ce5ad63ec4e49011d165e17a2c59d9a613f163b9";
    url = "https://softwarecorp.example/downloads";
  };

  nativeBuildInputs = [
    dpkg
    autoPatchelfHook
  ];

  unpackPhase = "dpkg-deb -x $src .";

  buildInputs = [ libcxx ];

  installPhase = ''
    cp -r bin $out/
  '';

  runtimeDependencies = [ myapp-lib ];  # <-- how to do this?
}

The lib derivation builds on its own, and now I want to add the things it contains to the app derivation. I can't just add it to the regular list of package dependencies at the top of the file. I'd also like to avoid submitting the package to nixpkgs at this time, because I'm not sure I'll be able to package the app fully, and I don't want to become its maintainer before I know it can be done.

Alternatively, are there any good patterns for packaging closed-source software like this that would avoid needing to make lots of derivations? From what I can tell, the libraries here all have the same version, and are never used anywhere else in the company's products, so building a single derivation could be acceptable here.

2 Answers 2

0

To avoid making two derivation could simply not package the library and simply import it before the installPhase. This could be done by extracting the library files in postUnpack:

# app.nix
{
  stdenv,
  autoPatchelfHook,
  dpkg,
  requireFile,
  libcxx,
}: let
  myLib = requireFile {
    name = "lib.deb";
    sha256 = "313e8686118ccba397de0bdfca101f1053b758227fd9d3510ea78644f2450bfe";
    url = "https://softwarecorp.example/downloads";
  };
in
  stdenv.mkDerivation {
    pname = "myapp-bin";
    version = "1.0.0";
    src = requireFile {
      name = "app.deb";
      sha256 = "f4abbdb3f83d982569c5cd30ce5ad63ec4e49011d165e17a2c59d9a613f163b9";
      url = "https://softwarecorp.example/downloads";
    };

    nativeBuildInputs = [
      dpkg
      autoPatchelfHook
    ];

    unpackPhase = "dpkg-deb -x $src .";

    postUnpack = ''
      dpkg-deb -x ${myLib} .
      cp -r lib $out/
    '';

    buildInputs = [libcxx];

    installPhase = ''
      cp -r bin $out/
    '';
  }

The package epson-alc1100 is an example of this kind of implementation.

4
  • And if I need to extend this to many other libraries, then I'd add multiple instances of the myLib declaration and more dpkg-deb -x lines into the postUnpack section?
    – Danya02
    Commented Mar 17 at 11:13
  • Yes exactly, just beware of potential conflicts when extracting multiple libraries with dpkg -x. Commented Mar 17 at 11:17
  • Well, the original software intends that you just install every .deb file in sequence, so I assume that's not going to be an issue.
    – Danya02
    Commented Mar 17 at 11:18
  • It should not be since usually each library file have a different name. Commented Mar 17 at 11:23
0

First of all, you need to be able to access the lib derivation while you are writing the expression for app. So you should change the bottom of default.nix to have a "recursive" set where the elements can refer to each other, and pass lib as an argument to app:

{
  lib = pkgs.callPackage ./lib.nix { };
  app = pkgs.callPackage ./app.nix { inherit lib; };
}

Now app.nix needs to have an argument named lib, but it looks like you already added that. (Actually, in your real code I hope the argument is named something else, because pkgs.lib is a library provided by nixpkgs, and you want to be able to use that in your derivation without a name conflict.)

Now in app.nix, just write inherit lib; in your set that you are passing to mkDerivation. This is equivalent to lib = lib;, and that means it will set an environment variable named lib equal to the output path of the lib derivation. (Despite what you wrote in your question, I don't think runtimeDependencies is a valid argument to mkDerivation.)

Now in your builder script for app you can do whatever is needed to make lib be a runtime dependency of app. For example, you might write ln -s $out/lib $lib to make a symbolic link. The exact details of what you are going to do here depends on the details of how the app finds its libraries, and I don't have those details so I can only tell your generalities.

Run nix-build -A app and look in the result symlink in your current directory to see what you built, and make sure it refers to lib in the way you are expecting.

2
  • Like I asked the other answer, how do you extend this to many derivations being used? Just copy the line into lib2 = ... and inherit lib2;?
    – Danya02
    Commented Mar 20 at 20:44
  • Yeah, for each derivation that depends on libraries defined in the same set, just write inherit lib1 lib2 lib3;. There is probably some fancy Nix way to make callPackage work for your project and save you a little bit of typing, but writing out the dependencies explicitly will help you understand the structure of your system better. Commented Mar 20 at 21:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .