about summary refs log tree commit diff
path: root/pkgs/top-level/splice.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/top-level/splice.nix')
-rw-r--r--pkgs/top-level/splice.nix76
1 files changed, 76 insertions, 0 deletions
diff --git a/pkgs/top-level/splice.nix b/pkgs/top-level/splice.nix
new file mode 100644
index 0000000000000..f57f42020c27a
--- /dev/null
+++ b/pkgs/top-level/splice.nix
@@ -0,0 +1,76 @@
+# The `splicedPackages' package set, and its use by `callPackage`
+#
+# The `buildPackages` pkg set is a new concept, and the vast majority package
+# expression (the other *.nix files) are not designed with it in mind. This
+# presents us with a problem with how to get the right version (build-time vs
+# run-time) of a package to a consumer that isn't used to thinking so cleverly.
+#
+# The solution is to splice the package sets together as we do below, so every
+# `callPackage`d expression in fact gets both versions. Each# derivation (and
+# each derivation's outputs) consists of the run-time version, augmented with a
+# `nativeDrv` field for the build-time version, and `crossDrv` field for the
+# run-time version.
+#
+# We could have used any names we want for the disambiguated versions, but
+# `crossDrv` and `nativeDrv` were somewhat similarly used for the old
+# cross-compiling infrastructure. The names are mostly invisible as
+# `mkDerivation` knows how to pull out the right ones for `buildDepends` and
+# friends, but a few packages use them directly, so it seemed efficient (to
+# @Ericson2314) to reuse those names, at least initially, to minimize breakage.
+lib: pkgs:
+
+let
+  defaultBuildScope = pkgs.buildPackages // pkgs.buildPackages.xorg;
+  # TODO(@Ericson2314): we shouldn't preclude run-time fetching by removing
+  # these attributes. We should have a more general solution for selecting
+  # whether `nativeDrv` or `crossDrv` is the default in `defaultScope`.
+  pkgsWithoutFetchers = lib.filterAttrs (n: _: !lib.hasPrefix "fetch" n) pkgs;
+  defaultRunScope = pkgsWithoutFetchers // pkgs.xorg;
+
+  splicer = buildPkgs: runPkgs: let
+    mash = buildPkgs // runPkgs;
+    merge = name: {
+      inherit name;
+      value = let
+        defaultValue = mash.${name};
+        buildValue = buildPkgs.${name} or {};
+        runValue = runPkgs.${name} or {};
+        augmentedValue = defaultValue
+          // (lib.optionalAttrs (buildPkgs ? ${name}) { nativeDrv = buildValue; })
+          // (lib.optionalAttrs (runPkgs ? ${name}) { crossDrv = runValue; });
+        # Get the set of outputs of a derivation
+        getOutputs = value:
+          lib.genAttrs (value.outputs or []) (output: value.${output});
+      in
+        # Certain *Cross derivations will fail assertions, but we need their
+        # nativeDrv. We are assuming anything that fails to evaluate is an
+        # attrset (including derivation) and thus can be unioned.
+        if !(builtins.tryEval defaultValue).success then augmentedValue
+        # The derivation along with its outputs, which we recur
+        # on to splice them together.
+        else if lib.isDerivation defaultValue then augmentedValue
+          // splicer (getOutputs buildValue) (getOutputs runValue)
+        # Just recur on plain attrsets
+        else if lib.isAttrs defaultValue then splicer buildValue runValue
+        # Don't be fancy about non-derivations. But we could have used used
+        # `__functor__` for functions instead.
+        else defaultValue;
+    };
+  in lib.listToAttrs (map merge (lib.attrNames mash));
+
+  splicedPackages = splicer defaultBuildScope defaultRunScope;
+
+in
+
+{
+  splicedPackages = splicedPackages // { recurseForDerivations = false; };
+
+  # We use `callPackage' to be able to omit function arguments that can be
+  # obtained `pkgs` or `buildPackages` and their `xorg` package sets. Use
+  # `newScope' for sets of packages in `pkgs' (see e.g. `gnome' below).
+  callPackage = pkgs.newScope {};
+
+  callPackages = lib.callPackagesWith splicedPackages;
+
+  newScope = extra: lib.callPackageWith (splicedPackages // extra);
+}