Chris Stryczynski
Chris Stryczynski

Reputation: 33861

How to specify package/derivation runtime dependencies with Nix?

I'm making a haskell program and I'm setting buildInput like this to include pkgs.ffmpeg-full:

(myHaskellPackages.callCabal2nix "App" (./.) {}).overrideAttrs (oldAttrs: {
  buildInputs = (oldAttrs.buildInputs or []) ++ [ pkgs.ffmpeg-full ];
})

However this seems to make the ffmpeg package accessible during build time only rather than runtime of the application.

What attribute do I need to set for ffmpeg-full to be available during runtime - being able to invoke the ffmpeg executable?

There is a section about runtime dependencies in nix pills but I don't understand that section, it doesn't make sense how it can always determine runtime dependencies by hashes alone? I mean if I reference an executable in a shell script - surely nix does not parse the shell script to determine the executable I reference. https://nixos.org/guides/nix-pills/automatic-runtime-dependencies.html#idm140737320205792

Something is different for runtime dependencies however. Build dependencies are automatically recognized by Nix once they are used in any derivation call, but we never specify what are the runtime dependencies for a derivation.

There's really black magic involved. It's something that at first glance makes you think "no, this can't work in the long term", but at the same time it works so well that a whole operating system is built on top of this magic.

In other words, Nix automatically computes all the runtime dependencies of a derivation, and it's possible thanks to the hash of the store paths.

Upvotes: 4

Views: 5118

Answers (2)

Daniil Iaitskov
Daniil Iaitskov

Reputation: 6039

default.nix:

{
  ghc ? "ghc8106",
  pkgs ? import <nixpkgs> {}
}:
with pkgs.haskell.lib;
let
  haskellPkgs = pkgs.haskell.packages.${ghc};
  inherit (pkgs) lib;

  mySourceRegexes = [
    "^app.*$"
    "^.*\\.cabal$"
    "package.yaml"
  ];

  myApp = (haskellPkgs.callCabal2nix "my-hello"
    (lib.sourceByRegex ./. mySourceRegexes) { });

in myApp
   .overrideAttrs(
      oa: {
        nativeBuildInputs = oa.nativeBuildInputs ++ [pkgs.hello pkgs.makeWrapper];
        installPhase = oa.installPhase + ''
          ln -s ${pkgs.hello.out}/bin/hello $out/bin/hello
        '';
        postFixup = ''
          wrapProgram $out/bin/x-exe --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.hello ]}
        '';
      })

src/Main.hs:

module Main where

import System.Process (callCommand)

main :: IO ()
main = do
  putStrLn "HELLO"
  callCommand "hello"
  putStrLn "BYE"

Upvotes: 2

Chris Stryczynski
Chris Stryczynski

Reputation: 33861

Seems this is not directly supported with an explicitly stated list of dependencies. However we can indirectly achieve this with "wrapping".


I found more information about wrapping here: https://nixos.wiki/wiki/Nix_Cookbook#Wrapping_packages

So I can do a ls that references the package.

...
appPkg = (myHaskellPackages.callCabal2nix "HaskellNixCabalStarter" (./.) {}).overrideAttrs (oldAttrs: {
  buildInputs = (oldAttrs.buildInputs or []) ++ [ pkgs.ffmpeg-full ];
  });
in
(pkgs.writeScriptBin "finderapp" ''
  #!${pkgs.stdenv.shell}

  ls ${pkgs.ffmpeg-full}/bin/ffmpeg
  exec ${appPkg}/bin/app
''
)

We can verify the built package(?) correctly depends on the appropriate with:

nix-store -q --references result
/nix/store/0cq84xic2absp75ciajv4lfx5ah1fb59-ffmpeg-full-4.2.2
/nix/store/rm1hz1lybxangc8sdl7xvzs5dcvigvf7-bash-4.4-p23
/nix/store/wlvnjx53xfangaa4m5rmabknjbgpvq3d-HaskellNixCabalStarter-0.1.0.0

Upvotes: 1

Related Questions