Skip to content

Commit a8fc1b1

Browse files
committed
[RFC 0083] common interface package sets
1 parent 123e94a commit a8fc1b1

File tree

1 file changed

+268
-0
lines changed

1 file changed

+268
-0
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
---
2+
feature: common-interface-package-sets
3+
start-date: 2020-12-19
4+
author: Frederik Rietdijk (@FRidh)
5+
co-authors:
6+
related-issues:
7+
---
8+
9+
# Summary
10+
[summary]: #summary
11+
12+
The Nixpkgs package set consists of a large amount of packages of which a
13+
significant amount of grouped into sub package sets. This RFC recommends a
14+
common interface for these package sets.
15+
16+
# Motivation
17+
[motivation]: #motivation
18+
19+
The Nixpkgs package set consists of a large amount of packages of which a
20+
significant amount of grouped into sub package sets. Sets exist for various
21+
languages, frameworks and plugins.
22+
23+
They are typically grouped together for one of the following two reasons:
24+
- clarity, e.g. because they're written in the same language or framework;
25+
- necessity, e.g. for compatibility reasons.
26+
27+
Over time different methods for defining package sets were created. Currently
28+
multiple methods are in use in Nixpkgs and pull requests are opened to modify
29+
sub package sets interfaces from one kind to another. Not only is this confusing
30+
for users but it also causes trouble; in some cases overriding of derivations
31+
inside a set is not possible or cross-compilation is broken.
32+
33+
This RFC thus aims to unify the package sets to a common interface for the
34+
following reasons:
35+
- simplify usage of package sets and reduce confusion surrounding them;
36+
- single approach for dealing with overrides;
37+
- handle variants of a package set;
38+
- ensure cross-compilation works.
39+
40+
Often one also wants to build an environment with an interpreter or main program
41+
and some additional packages or plugins. This RFC will therefore also recommend
42+
a function each package set should offer for doing so, when appliceable that is.
43+
44+
## Related issues
45+
46+
TODO: refer to these issues in correct place.
47+
48+
- Common override interface derivations https://github.com/NixOS/rfcs/pull/67
49+
- Make PHP packages overrideable https://github.com/NixOS/nixpkgs/pull/107044
50+
- Change in emacs interface https://github.com/NixOS/nixpkgs/pull/107152
51+
- Package set for Octave https://github.com/NixOS/nixpkgs/issues/65398#issuecomment-743926570
52+
- Python package set is not overrideable
53+
https://github.com/NixOS/nixpkgs/issues/44426
54+
- Support `overrideScope'` in Python package set
55+
https://github.com/NixOS/nixpkgs/pull/105374
56+
- Common `overrideArgs` for sub package sets
57+
https://github.com/NixOS/nixpkgs/pull/46842. May be resolved using
58+
`overrideAuto` in https://github.com/NixOS/rfcs/pull/67.
59+
60+
# Detailed design
61+
[design]: #detailed-design
62+
63+
We will now look in more detail at what a common interface should offer.
64+
65+
## Attribute name of the package set: `fooPackages` versus `foo.pkgs`
66+
67+
Two different interfaces are common in Nixpkgs when referring to package sets:
68+
- `fooPackages`
69+
- `foo.pkgs`
70+
71+
TODO which one to pick? Consider also overriding of the interpreter or main program and how that should propagate. Consider also the function for generating variants, where you need to have a name under which your interpreter or main program is available in the subpackage set.
72+
## Variants
73+
Often multiple variants of a package set need to be created. E.g., in case of
74+
emacs or Python there are different versions of the program and each of them
75+
should have their own package set. For this reason it is important that one can
76+
easily create a new variant
77+
78+
```nix
79+
fooPackagesFor = foo: import ./foo-packages.nix { ... };
80+
fooPackages_3_6 = fooPackagesFor foo_3_6;
81+
```
82+
83+
## Set overriding
84+
It should be possible to override packages in a sub package set and have the
85+
other packages in the set take that override into account. To that end, a scope
86+
is created
87+
88+
```nix
89+
lib.makeScope pkgs.newScope (self: with self; {
90+
...
91+
}
92+
```
93+
94+
that can be overridden using `overrideScope'`
95+
96+
```nix
97+
fooPackages_3_6.overrideScope' overrides;
98+
```
99+
100+
where `overrides` is of the form
101+
102+
```nix
103+
(final: previous: { ... })
104+
```
105+
106+
In case one uses overlays with Nixpkgs, one could now make the overrides
107+
composible using
108+
109+
```nix
110+
fooPackages_3_6 = fooPackages_3_6.overrideScope' overrides;
111+
```
112+
113+
## Package overriding
114+
115+
Now that it is possible to override a set, a common interface to overriding the
116+
packages inside the set is needed as well. This is treated in [RFC
117+
67](https://github.com/NixOS/rfcs/pull/67).
118+
119+
## Cross-compilation
120+
121+
For cross-compilation it is important that `callPackage` in the sub package set
122+
has access to the spliced versions of the sub package set. Until recently, there
123+
were no spliced sub package sets in Nixpkgs, but support was added for Python
124+
utilizing the `makeScopeWithSplicing` function. There is [room for
125+
improvement](https://github.com/NixOS/nixpkgs/pull/105374).
126+
127+
An important aspect for making this work is that, when constructing the package
128+
set, it needs to know its own top-level attribute.
129+
130+
...
131+
132+
133+
To support nested package sets, the full attribute path is needed, including
134+
dots.
135+
136+
```nix
137+
`fooPackages_3_6.subFooPackages_2_5`
138+
```
139+
140+
## Single function for creating a package set
141+
142+
To ease the creation of a package set, a single function is proposed for
143+
creating a set given a main program and an attribute name.
144+
145+
146+
```nix
147+
makePackageSet = ...
148+
```
149+
150+
151+
A package set can then be created
152+
153+
```
154+
fooPackagesFor = foo: callPackages
155+
156+
fooPackages =
157+
158+
```
159+
160+
## Composing an environment
161+
162+
Thus far we considered building a package set and overriding it. Somewhat
163+
orthogonal yet still commonly needed, is a method to compose an environment of
164+
packages inside the package set.
165+
166+
Starting with Haskell and later adopted by other package sets is a
167+
`withPackages(ps: [...])` function that allows you to compose an environment with chosen
168+
packages from the set.
169+
170+
This RFC recommends each package set should have such a function, in case it is
171+
appliceable. An example of where it would not make sense to include such a
172+
function is in case of a [Qt package
173+
set](https://github.com/NixOS/nixpkgs/pull/102168) because you would not be
174+
interested in having a Qt with libraries during runtime and nothing else.
175+
176+
Haskell introduced the function as part of its package set, that is, one uses
177+
`haskellPackages.ghcWithPackages (ps: [...])`. Some time later Python added such
178+
function, but as part of the interpreter `python3.withPackages(ps: [...])`.
179+
Since then, many other sets also added `withPackages` as part of the
180+
interpreter or main program.
181+
182+
Should the `withPackages` function be part of the main program or the package
183+
set? If we override the package set using `overrideScope'`, then the updated
184+
package set is visible to attributes of the package set, that is
185+
186+
```
187+
(fooPackages.overrideScope' overrides).withPackages
188+
```
189+
190+
and
191+
192+
```
193+
(fooPackages.overrideScope' overrides).foo.withPackages
194+
```
195+
196+
will consider the updates.
197+
198+
### `fooPackages` versus `foo.pkgs` again...
199+
200+
TODO
201+
202+
Unfortunately, having `withPackages` as part of the main program makes it
203+
somewhat more difficult to use it when overrides are needed as well. One would have to write
204+
205+
```nix
206+
(foo_3_6.pkgs.overrideScope' overrides).foo.withPackages(ps: [...])
207+
```
208+
Indeed, the `withPackages` of the main program inside the sub set needs to be used. Using
209+
210+
TODO the actual recommendation
211+
212+
# Examples and Interactions
213+
214+
## Create a package set
215+
216+
The following example shows how to create a package set
217+
218+
...
219+
220+
## Override a package set
221+
222+
The following example shows how to override a package set
223+
224+
```nix
225+
fooPackages.overrideScope' (final: previous: {
226+
...
227+
})
228+
```
229+
230+
## Compose an environment
231+
232+
The following example shows how to compose an environment
233+
234+
TODO
235+
236+
```
237+
fooPackages.foo.withPackages(ps: [...])
238+
```
239+
240+
or
241+
242+
```
243+
fooPackages.withPackages(ps: [...])
244+
```
245+
246+
## Deprecating old interfaces
247+
248+
It it is recommended that package sets adopt the new interface and deprecate
249+
their current one. For compatibility reasons it may not be possible to use the
250+
recommended functions to construct the new interface, requiring custom
251+
solutions.
252+
253+
# Drawbacks
254+
[drawbacks]: #drawbacks
255+
256+
By not recommending a common interface, package sets may continue to have
257+
different interfaces and change even in opposite directions.
258+
259+
# Alternatives
260+
[alternatives]: #alternatives
261+
262+
# Future work
263+
[future]: #future-work
264+
265+
- Document the recommended interface in the Nixpkgs manual.
266+
- Adopt the recommended interface in existing package sets in Nixpkgs.
267+
- Encourage tools that create package sets, e.g. from lock files, to also adopt
268+
this interface.

0 commit comments

Comments
 (0)