dc214ed99b
For historical reasons, callPackage has the xorg packages in scope. This unstable building block is more versatile without the xorg hack baked in.
135 lines
6.1 KiB
Nix
135 lines
6.1 KiB
Nix
# 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.
|
|
#
|
|
# For performance reasons, rather than uniformally splice in all cases, we only
|
|
# do so when `pkgs` and `buildPackages` are distinct. The `actuallySplice`
|
|
# parameter there the boolean value of that equality check.
|
|
lib: pkgs: actuallySplice:
|
|
|
|
let
|
|
|
|
spliceReal = { pkgsBuildBuild, pkgsBuildHost, pkgsBuildTarget
|
|
, pkgsHostHost, pkgsHostTarget
|
|
, pkgsTargetTarget
|
|
}: let
|
|
mash =
|
|
# Other pkgs sets
|
|
pkgsBuildBuild // pkgsBuildTarget // pkgsHostHost // pkgsTargetTarget
|
|
# The same pkgs sets one probably intends
|
|
// pkgsBuildHost // pkgsHostTarget;
|
|
merge = name: {
|
|
inherit name;
|
|
value = let
|
|
defaultValue = mash.${name};
|
|
# `or {}` is for the non-derivation attsert splicing case, where `{}` is the identity.
|
|
valueBuildBuild = pkgsBuildBuild.${name} or {};
|
|
valueBuildHost = pkgsBuildHost.${name} or {};
|
|
valueBuildTarget = pkgsBuildTarget.${name} or {};
|
|
valueHostHost = throw "`valueHostHost` unimplemented: pass manually rather than relying on splice.";
|
|
valueHostTarget = pkgsHostTarget.${name} or {};
|
|
valueTargetTarget = pkgsTargetTarget.${name} or {};
|
|
augmentedValue = defaultValue
|
|
# TODO(@Ericson2314): Stop using old names after transition period
|
|
// (lib.optionalAttrs (pkgsBuildHost ? ${name}) { nativeDrv = valueBuildHost; })
|
|
// (lib.optionalAttrs (pkgsHostTarget ? ${name}) { crossDrv = valueHostTarget; })
|
|
// {
|
|
__spliced =
|
|
(lib.optionalAttrs (pkgsBuildBuild ? ${name}) { buildBuild = valueBuildBuild; })
|
|
// (lib.optionalAttrs (pkgsBuildTarget ? ${name}) { buildTarget = valueBuildTarget; })
|
|
// { hostHost = valueHostHost; }
|
|
// (lib.optionalAttrs (pkgsTargetTarget ? ${name}) { targetTarget = valueTargetTarget;
|
|
});
|
|
};
|
|
# Get the set of outputs of a derivation. If one derivation fails to
|
|
# evaluate we don't want to diverge the entire splice, so we fall back
|
|
# on {}
|
|
tryGetOutputs = value0: let
|
|
inherit (builtins.tryEval value0) success value;
|
|
in getOutputs (lib.optionalAttrs success value);
|
|
getOutputs = value: lib.genAttrs
|
|
(value.outputs or (lib.optional (value ? out) "out"))
|
|
(output: value.${output});
|
|
in
|
|
# The derivation along with its outputs, which we recur
|
|
# on to splice them together.
|
|
if lib.isDerivation defaultValue then augmentedValue // spliceReal {
|
|
pkgsBuildBuild = tryGetOutputs valueBuildBuild;
|
|
pkgsBuildHost = tryGetOutputs valueBuildHost;
|
|
pkgsBuildTarget = tryGetOutputs valueBuildTarget;
|
|
pkgsHostHost = tryGetOutputs valueHostHost;
|
|
pkgsHostTarget = getOutputs valueHostTarget;
|
|
pkgsTargetTarget = tryGetOutputs valueTargetTarget;
|
|
# Just recur on plain attrsets
|
|
} else if lib.isAttrs defaultValue then spliceReal {
|
|
pkgsBuildBuild = valueBuildBuild;
|
|
pkgsBuildHost = valueBuildHost;
|
|
pkgsBuildTarget = valueBuildTarget;
|
|
pkgsHostHost = {};
|
|
pkgsHostTarget = valueHostTarget;
|
|
pkgsTargetTarget = valueTargetTarget;
|
|
# 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));
|
|
|
|
splicePackages = { pkgsBuildBuild, pkgsBuildHost, pkgsBuildTarget
|
|
, pkgsHostHost, pkgsHostTarget
|
|
, pkgsTargetTarget
|
|
} @ args:
|
|
if actuallySplice then spliceReal args else pkgsHostTarget;
|
|
|
|
splicedPackages = splicePackages rec {
|
|
pkgsBuildBuild = pkgs.buildPackages.buildPackages;
|
|
pkgsBuildHost = pkgs.buildPackages;
|
|
pkgsBuildTarget =
|
|
if pkgs.stdenv.targetPlatform == pkgs.stdenv.hostPlatform
|
|
then pkgsBuildHost
|
|
else assert pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform; pkgsHostTarget;
|
|
pkgsHostHost = {}; # unimplemented
|
|
pkgsHostTarget = pkgs;
|
|
pkgsTargetTarget = pkgs.targetPackages;
|
|
} // {
|
|
# These should never be spliced under any circumstances
|
|
inherit (pkgs) pkgs buildPackages targetPackages;
|
|
inherit (pkgs.stdenv) buildPlatform targetPlatform hostPlatform;
|
|
};
|
|
|
|
splicedPackagesWithXorg = splicedPackages // splicedPackages.xorg;
|
|
|
|
in
|
|
|
|
{
|
|
inherit splicePackages;
|
|
|
|
# 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 splicedPackagesWithXorg;
|
|
|
|
newScope = extra: lib.callPackageWith (splicedPackagesWithXorg // extra);
|
|
|
|
# Haskell package sets need this because they reimplement their own
|
|
# `newScope`.
|
|
__splicedPackages = splicedPackages // { recurseForDerivations = false; };
|
|
}
|