Merge pull request #270774 from emilytrau/libbacktrace-musl
[NixPkgs.git] / pkgs / top-level / splice.nix
blob9ac0fe2200f92cc403ff9a452bbac111b9772e01
1 # The `splicedPackages' package set, and its use by `callPackage`
3 # The `buildPackages` pkg set is a new concept, and the vast majority package
4 # expression (the other *.nix files) are not designed with it in mind. This
5 # presents us with a problem with how to get the right version (build-time vs
6 # run-time) of a package to a consumer that isn't used to thinking so cleverly.
8 # The solution is to splice the package sets together as we do below, so every
9 # `callPackage`d expression in fact gets both versions. Each derivation (and
10 # each derivation's outputs) consists of the run-time version, augmented with
11 # a `__spliced.buildHost` field for the build-time version, and
12 # `__spliced.hostTarget` field for the run-time version.
14 # For performance reasons, rather than uniformally splice in all cases, we only
15 # do so when `pkgs` and `buildPackages` are distinct. The `actuallySplice`
16 # parameter there the boolean value of that equality check.
17 lib: pkgs: actuallySplice:
19 let
21   spliceReal =
22     { pkgsBuildBuild
23     , pkgsBuildHost
24     , pkgsBuildTarget
25     , pkgsHostHost
26     , pkgsHostTarget
27     , pkgsTargetTarget
28     }:
29     let
30       mash =
31         # Other pkgs sets
32         pkgsBuildBuild // pkgsBuildTarget // pkgsHostHost // pkgsTargetTarget
33         # The same pkgs sets one probably intends
34         // pkgsBuildHost // pkgsHostTarget;
35       merge = name: {
36         inherit name;
37         value =
38           let
39             defaultValue = mash.${name};
40             # `or {}` is for the non-derivation attsert splicing case, where `{}` is the identity.
41             valueBuildBuild = pkgsBuildBuild.${name} or { };
42             valueBuildHost = pkgsBuildHost.${name} or { };
43             valueBuildTarget = pkgsBuildTarget.${name} or { };
44             valueHostHost = pkgsHostHost.${name} or { };
45             valueHostTarget = pkgsHostTarget.${name} or { };
46             valueTargetTarget = pkgsTargetTarget.${name} or { };
47             augmentedValue = defaultValue
48               // {
49               __spliced =
50                 (lib.optionalAttrs (pkgsBuildBuild ? ${name}) { buildBuild = valueBuildBuild; })
51                   // (lib.optionalAttrs (pkgsBuildHost ? ${name}) { buildHost = valueBuildHost; })
52                   // (lib.optionalAttrs (pkgsBuildTarget ? ${name}) { buildTarget = valueBuildTarget; })
53                   // (lib.optionalAttrs (pkgsHostHost ? ${name}) { hostHost = valueHostHost; })
54                   // (lib.optionalAttrs (pkgsHostTarget ? ${name}) { hostTarget = valueHostTarget; })
55                   // (lib.optionalAttrs (pkgsTargetTarget ? ${name}) {
56                   targetTarget = valueTargetTarget;
57                 });
58             };
59             # Get the set of outputs of a derivation. If one derivation fails to
60             # evaluate we don't want to diverge the entire splice, so we fall back
61             # on {}
62             tryGetOutputs = value0:
63               let
64                 inherit (builtins.tryEval value0) success value;
65               in
66               getOutputs (lib.optionalAttrs success value);
67             getOutputs = value: lib.genAttrs
68               (value.outputs or (lib.optional (value ? out) "out"))
69               (output: value.${output});
70           in
71           # The derivation along with its outputs, which we recur
72             # on to splice them together.
73           if lib.isDerivation defaultValue then augmentedValue // spliceReal {
74             pkgsBuildBuild = tryGetOutputs valueBuildBuild;
75             pkgsBuildHost = tryGetOutputs valueBuildHost;
76             pkgsBuildTarget = tryGetOutputs valueBuildTarget;
77             pkgsHostHost = tryGetOutputs valueHostHost;
78             pkgsHostTarget = getOutputs valueHostTarget;
79             pkgsTargetTarget = tryGetOutputs valueTargetTarget;
80             # Just recur on plain attrsets
81           } else if lib.isAttrs defaultValue then
82             spliceReal
83               {
84                 pkgsBuildBuild = valueBuildBuild;
85                 pkgsBuildHost = valueBuildHost;
86                 pkgsBuildTarget = valueBuildTarget;
87                 pkgsHostHost = valueHostHost;
88                 pkgsHostTarget = valueHostTarget;
89                 pkgsTargetTarget = valueTargetTarget;
90                 # Don't be fancy about non-derivations. But we could have used used
91                 # `__functor__` for functions instead.
92               } else defaultValue;
93       };
94     in
95     lib.listToAttrs (map merge (lib.attrNames mash));
97   splicePackages =
98     { pkgsBuildBuild
99     , pkgsBuildHost
100     , pkgsBuildTarget
101     , pkgsHostHost
102     , pkgsHostTarget
103     , pkgsTargetTarget
104     } @ args:
105     if actuallySplice then spliceReal args else pkgsHostTarget;
107   splicedPackages = splicePackages
108     {
109       inherit (pkgs)
110         pkgsBuildBuild pkgsBuildHost pkgsBuildTarget
111         pkgsHostHost pkgsHostTarget
112         pkgsTargetTarget
113         ;
114     } // {
115     # These should never be spliced under any circumstances
116     inherit (pkgs)
117       pkgsBuildBuild pkgsBuildHost pkgsBuildTarget
118       pkgsHostHost pkgsHostTarget
119       pkgsTargetTarget
120       buildPackages pkgs targetPackages
121       ;
122     inherit (pkgs.stdenv) buildPlatform targetPlatform hostPlatform;
123   };
125   splicedPackagesWithXorg = splicedPackages // builtins.removeAttrs splicedPackages.xorg [
126     "callPackage"
127     "newScope"
128     "overrideScope"
129     "packages"
130   ];
135   inherit splicePackages;
137   # We use `callPackage' to be able to omit function arguments that can be
138   # obtained `pkgs` or `buildPackages` and their `xorg` package sets. Use
139   # `newScope' for sets of packages in `pkgs' (see e.g. `gnome' below).
140   callPackage = pkgs.newScope { };
142   callPackages = lib.callPackagesWith splicedPackagesWithXorg;
144   newScope = extra: lib.callPackageWith (splicedPackagesWithXorg // extra);
146   # prefill 2 fields of the function for convenience
147   makeScopeWithSplicing = lib.makeScopeWithSplicing splicePackages pkgs.newScope;
148   makeScopeWithSplicing' = lib.makeScopeWithSplicing' { inherit splicePackages; inherit (pkgs) newScope; };
150   # generate 'otherSplices' for 'makeScopeWithSplicing'
151   generateSplicesForMkScope = attr:
152     let
153       split = X: lib.splitString "." "${X}.${attr}";
154     in
155     {
156       # nulls should never be reached
157       selfBuildBuild = lib.attrByPath (split "pkgsBuildBuild") null pkgs;
158       selfBuildHost = lib.attrByPath (split "pkgsBuildHost") null pkgs;
159       selfBuildTarget = lib.attrByPath (split "pkgsBuildTarget") null pkgs;
160       selfHostHost = lib.attrByPath (split "pkgsHostHost") null pkgs;
161       selfHostTarget = lib.attrByPath (split "pkgsHostTarget") null pkgs;
162       selfTargetTarget = lib.attrByPath (split "pkgsTargetTarget") { } pkgs;
163     };
165   # Haskell package sets need this because they reimplement their own
166   # `newScope`.
167   __splicedPackages = splicedPackages // { recurseForDerivations = false; };