-
-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC 0092] Computed derivations #92
Changes from 27 commits
3a8338a
3b8422a
4da9193
800b5f3
f708983
6a87c1b
36193e5
ffb9203
5564fdb
22f8322
7f5f854
5c9f1fb
5e56f21
ba7dcce
8bcb4e6
baae1e6
9448a2a
37a643e
14b134d
1b0a6a1
3fe1c3d
a38f245
4022058
6c01e4d
6d97de1
2079528
fd7bb41
ec622cd
ad74b68
0eaa6bb
49070db
c50ee43
98ea32a
c01f07c
3f187a3
7d18780
5e92cc9
1e2012c
5836c02
970ff43
d6d6b17
6ab3338
5f7d4da
ea388e7
f6741c4
b5aa21d
866dc5e
098fe68
fed8991
854fd9b
f853a6f
1abaf30
ef1d9aa
5115ebb
fdbf778
2388cbe
404ad6d
a906a7c
4d579ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,235 @@ | ||||||||||||||
--- | ||||||||||||||
feature: plan-dynamism | ||||||||||||||
start-date: 2019-02-01 | ||||||||||||||
author: John Ericson (@Ericson2314) | ||||||||||||||
co-authors: (find a buddy later to help out with the RFC) | ||||||||||||||
shepherd-team: (names, to be nominated and accepted by RFC steering committee) | ||||||||||||||
shepherd-leader: (name to be appointed by RFC steering committee) | ||||||||||||||
related-issues: (will contain links to implementation PRs) | ||||||||||||||
--- | ||||||||||||||
|
||||||||||||||
# Summary | ||||||||||||||
[summary]: #summary | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this section could use a paragraph actually describing the benefit. You list some problems that are hard to solve in the Motivation but a succinct summary would be useful. Possibly something like: Plan Dynamism would allow making Nix derivations available for large numbers of packages from language-specific package repositories such as NPM or crates.io with very little per-package effort |
||||||||||||||
|
||||||||||||||
We need build plan dynamism -- interleaved building and planning -- to cope with the ever-growing world of language-specific package managers. | ||||||||||||||
Propose to allow derivations to build derivations, and depend on those built derivations, as the core primitive for this. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
Additionally, introduce a new primop to leverage this in making IFD, still the gold standard for ease of use, more efficient and compatible with `hydra.nixos.org`'s queue runner. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IFD should probable be defined (or a definition be linked) early on. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Solved. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you give an example what this is the gold standard for with ease of use? Usually IFD is just a mess to debug.. not sure I would call that the gold standard. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess I don't mean to say it's great in relative terms, but the other options like
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
# Motivation | ||||||||||||||
[motivation]: #motivation | ||||||||||||||
|
||||||||||||||
Nix's design encourages a separation of build *planning* from build *execution*: | ||||||||||||||
evaluation of the Nix language produces derivations, and then then those derivations are built. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
This usually a great thing. | ||||||||||||||
It's enforced the separation of the more complex Nix expression language from the simpler derivation language. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which do you mean?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
("has" is usually only contracted to "'s" when part of "has got".) |
||||||||||||||
It's also encouraged Nixpkgs to take the "birds eye" view and successful grapple a ton of complexity that would have overwhelmed a more traditional package repository. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
Nixpkgs, along with every other distro, also faces a looming crisis: new open source software is increasingly not intended to be packaged by distros at all. | ||||||||||||||
Many languages now support very large library ecosystems, with dependencies expressed in a language-specific package manager. | ||||||||||||||
To this new generation of developers, the distro (or homebrew) is a crufty relic from an earlier age to bootstrap modernity, and then be forgotten about. | ||||||||||||||
|
||||||||||||||
Right now, to deal with these packages, we either convert by hand, or commit lots generated code into Nixpkgs. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
But it's don't think it's either of those is healthy or sustainable. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
The problem with the first is sheer effort; we'll never be able to keep up. | ||||||||||||||
The problem with the second is bloating Nixpkgs but more importantly reproducability: If someone wants to update that generated code it is unclear how. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it may be worth expanding on this slightly. Basically each language system will have it's own script or command to update these generated files. This inconsistency is difficult to learn and hard to tool in a generic way. |
||||||||||||||
All these mean that potential users coming from this new model of development find Nix / Nixpkgs cumbersome and unsuited to their needs. | ||||||||||||||
|
||||||||||||||
The core feature here, derivations that build derivations, is the best fundamental primitive for this problem. | ||||||||||||||
It's very performant, being well-adapted for Nix's current scheduler. | ||||||||||||||
Unlike recursive Nix, there's is no potential for half-built dependencies to sit around waiting for other builds, wasting resources. | ||||||||||||||
Each build step (derivation) always runs start to finish blocking on nothing. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
comma for clarity |
||||||||||||||
It's very efficient, because it doesn't obligate the use of the Nix expression language. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The direct object of "obligate" should be the person(s) obligated to do something, not the thing to be done. Maybe
Suggested change
or
Suggested change
or
Suggested change
|
||||||||||||||
Finally, it's quite compatible with `--dry-run`. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just "quite" compatible? What does that mean? |
||||||||||||||
|
||||||||||||||
However, "import from derivation" is still far and away the easiest method to use, and the one that existing tools to convert to Nix use. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
We should continue to support it, finding a way for `hydra.nixos.org` to allow it, so those tools with IFD can be used in Nixpkgs and become first-class members of the Nix ecosystem. | ||||||||||||||
We have a fairly straightforward mechanism, only slightly more cumbersome than IFD today, to allow evaluation to be deferred after imported things are built. | ||||||||||||||
This frees up the Hydra evaluator to finish before building, and also meshes well with any plan to build more than one eval-realized path at a time. | ||||||||||||||
This should allow us to drop the `hydra.nixos.org` restriction. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it generally known what restriction this refers to? |
||||||||||||||
|
||||||||||||||
With these steps, I think we will be able to successfully convert to Nix a bunch of developers that mainly work in one language, and didn't even think they were in need of a better distro. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
In turn, I hope these upstream packages and ecosystems might even care about packaging and integration of the sort that we do. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Packages and ecosystems can't care. Their developers and maintainers can and might. |
||||||||||||||
This would create a virtuous cycle where Nix is easier to use by more people, and Nixpkgs is easier to maintain as upstream packages better match our values. | ||||||||||||||
|
||||||||||||||
# Detailed design | ||||||||||||||
[design]: #detailed-design | ||||||||||||||
|
||||||||||||||
We can break this down nicely into steps. | ||||||||||||||
|
||||||||||||||
## Dynamic derivations | ||||||||||||||
|
||||||||||||||
*This is implemented in https://github.com/NixOS/nix/pull/4628.* | ||||||||||||||
|
||||||||||||||
1. Derivation outputs can be valid derivations: | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
1. Allow derivation outputs to be content addressed with the "text hashing" scheme. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
2. Lift the restriction barring derivations output paths from ending in `.drv` if they are so content-addressed | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm also not quite understanding this. Are you saying that currently a Nix derivation can't have an output that ends in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't seem to be documented in the nix manual. This is the check: https://github.com/NixOS/nix/blob/57f321f3ce311228ad9ab7eac8b108aeb4fa4026/src/libexpr/primops.cc#L1110-L1115 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might just help with the reading to put in a little additional glue in this doc regarding CA. I guess the key idea, which is not explicitly mentioned is:
Something like a "2000 feet flight height view" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is however still a leap of faith due to input-addressing (as in the extensional model which is described in chapter 5 here). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tried to expand on the big picture with https://github.com/NixOS/rfcs/pull/92/files#r646174922, does that solve it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That link is dead by now, maybe can you link to a commit diff? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fixed now.
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
2. Extend the CLI to take advantage of such derivations: | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Specifying the CLI here feels a bit odd. Shouldn't this feature, at first, be transparent to the CLI? If someone uses the new hydra-safe IFD that shouldn't matter to the CLI. In general overloading the "installables" attribute more and more (first flakes with Can't we be explicit about the intentions?
This would at least keep a clear separation of attributes and expression/derivation to build without adding more and more complexity into "installables". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So Flake's Here's another way to think about it: what would # build the out output
$ nix path-info /nix/store/something-....drv out mean with your proposal? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even more concretely I hope that this example shows how There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the topic of |
||||||||||||||
|
||||||||||||||
We hopefully will soon allow CLI "installable" args in the form | ||||||||||||||
``` | ||||||||||||||
single-installable ::= <path> ! <output-name> | ||||||||||||||
``` | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
where the first path is a derivation, and the second is the output we want to build. | ||||||||||||||
|
||||||||||||||
We should generalize the grammar like so: | ||||||||||||||
``` | ||||||||||||||
single-installable ::= <single-installable> ! <output-name> | ||||||||||||||
| <path> | ||||||||||||||
|
||||||||||||||
multi-installable ::= <single-installable> | ||||||||||||||
| <single-installable> ! * | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
Now that we have `path` vs `path!*`, we also don't need `---derivation` as a disambiguator, and so that should be removed along with all the complexity that goes with it. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably be clarified. I took me three readings to figure out that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh sheesh, yes I never said what the semantics were. Did that in addition to the examples @asymmetric asked for. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it make sense now? (before I mark this resolved.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The example clarifies things yeah! I am unsure though if the mention of I guess we have a bit of a problem that this RFC somewhat overlaps with problems related to the Installables abstraction and the unstable CLI? |
||||||||||||||
(`toBuildables` in the the nix commands should always be pure functions and not consult the store.) | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
3. Extend the scheduler and derivation dependencies similarly: | ||||||||||||||
|
||||||||||||||
- Derivations can depended on the outputs of derivations that are themselves derivation outputs. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
The schedule will substitute derivations to simplify dependencies as computed derivations are built, just like how floating content addressed derivations are realized. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Is this documented anywhere? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the word "floating" here relevant for general understanding? I have a sense it can be dropped. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes; in fact it's a favorite of mine. Fixed output derivations are also content addressed --- and much of my early implementation work was to ensure that the new content addressed derivations matched their fixed counterparts and we didn't have needless semantic drift. "Floating" is meant to contrast with "fixed". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think reader will have no choice but to honour your expertise. 😄 |
||||||||||||||
|
||||||||||||||
- Missing derivations get their own full fledged goals so they can be built, not just fetched from substituters. | ||||||||||||||
|
||||||||||||||
4. Add a new `outputOf` primop: | ||||||||||||||
|
||||||||||||||
`builtins.outputOf drv outputName` produces a placeholder string with the appropriate string context to access the output of that name produced by that derivation. | ||||||||||||||
The placeholder string is quite analogous to that used for floating content addressed derivation outputs. | ||||||||||||||
This isn't needed today when we statically know the derivation and thus it's outputs to make attributes for them, but it is needed for built derivations because we don't know either the final derivation or its output names in advanced. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
## Deferred import from derivation. | ||||||||||||||
|
||||||||||||||
Create a new primop `assumeDerivation` that takes a single expression. | ||||||||||||||
It's semantics are as follows: | ||||||||||||||
|
||||||||||||||
- If the underlying expression evaluates (shallowly) without needing to build derivations (for `import`, `readFile`, etc.), and is a derivation, simply return that. | ||||||||||||||
``` | ||||||||||||||
e ⇓ e' | ||||||||||||||
e' is derivation | ||||||||||||||
------ | ||||||||||||||
builtins.assumeDerivation e ⇓ e' | ||||||||||||||
``` | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a section explaining this syntax? I assume it's familiar for PLT folks, but it's very cryptic to me :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those are inference rules expressed in operational semantics. You can read that as I agree with asymmetric, we're not a PLT-focused symposium, prose is fine here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a more accessible presentation would be better. This is pseudo-formal, because (AFAIK) the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Unfortunately not everyone has that background. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A "translation" would suffice. Those compaxt bits of formalisms are great, once one has learned to parse them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well.....I'll put it this way:
So I am fine writing some sort of prose explanation, but I rather do it once the RFC is further along. P.S. whether you love our hate this stuff, https://www.youtube.com/watch?v=dCuZkaaou0Q is a fun talk. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could include a link to a short introduction to natural deduction. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is gone we can remove this. |
||||||||||||||
|
||||||||||||||
- If the underlying expression cannot evaluate (shallowly) without building on or more paths, defer evaluation into a derivation-producing-derivation, and take it's output with `builtins.outputOf`: | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
``` | ||||||||||||||
e gets stuck on builds | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is "stuck"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "synchronous waiting" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. stuck term, term that cannot finish evaluating. Traditionally that would be an open term with a free variable "blocking" a ~~regex~ redex. I consider an unbuilt path that is to be inspected quite analogous as it also a "dangling" reference of sorts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
regex -> redex (reducible expression) |
||||||||||||||
defer = derivation { | ||||||||||||||
inputDrvs = builds; | ||||||||||||||
buildCommand = "nix-instantiate ${reified e} > $out" | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One issue that is somewhat independent of this RFC, but relevant for it to be useful: We also need a “standalone” There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure of that? Evaluation is current designed so that like it or not, writing drv files is a side effect. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that at the time of writing I was not aware of recursive nix being possible in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup. I would want to limit recursive nix so one can just add paths to store (including DRVs), not build things. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I think that should at least be mentioned for clarity. If I understand it correctly, then maybe the following derivation would be clearer: derivation {
buildCommand = "cp $(nix-instantiate ${reifed e}) $out";
} In this case, the inner (recursive) instantiation would add the derivation file to the outer store, but due to content addressability of derivations, its There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This reification is rather hand-wavy. The language implementation can't serialize arbitrary closures. Such a feature isn't impossible but has consequences:
Compared to a somewhat naive serialization, another partial solution is to do "event sourcing" in the spirit of transient (Haskell). To implement that, the evaluator must only be accessible through a facade interface that tracks exactly how an evaluation came to be: which files were provided to it and which external traversals and function calls were made, etc. This method, if it even applies here, seems to solve the thunk dilemma, but doesn't solve the other problems and requires significant changes to the evaluator. The other problems remain unsolved. Is not serializing the closure an option? We could suspend the evaluation by just retaining the reference to the thunk, assigning it a random id and wait for the daemon to get back to us. This defeats the desired separation between the evaluation and build processes. It does let a derivation like I hope I've just misunderstood something, because I'd like this to succeed. I just don't see a good way to implement this. |
||||||||||||||
} | ||||||||||||||
------ | ||||||||||||||
builtins.assumeDerivation e ⇓ builtins.outputOf e "out" | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
This allows downstream non-dynamic derivations to be evaluated without getting stuck on their dynamic upstream ones. | ||||||||||||||
They just depend on the derivation computed by the deferred eval derivations, and those substitutions are performed by the scheduler. | ||||||||||||||
|
||||||||||||||
# Examples and Interactions | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/hackage-packages.nix concretely change? |
||||||||||||||
[examples-and-interactions]: #examples-and-interactions | ||||||||||||||
|
||||||||||||||
Here is everything put together with a Haskell and `cabal2nix` example. | ||||||||||||||
|
||||||||||||||
Given the following code, and assuming `bar` will depend on `foo` | ||||||||||||||
```nix | ||||||||||||||
mkScope (self: { | ||||||||||||||
foo = builtins.assumeDerivation (self.callCabal2nix "foo" ./foo); | ||||||||||||||
bar = builtins.assumeDerivation (self.callCabal2nix "bar" ./bar); | ||||||||||||||
}) | ||||||||||||||
``` | ||||||||||||||
We get something like the following derivations with dependencies | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Get" from what? Instantiation, or realisation?
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
``` | ||||||||||||||
(cabal2nix foo)!out ----> deFoo = deferred eval (fooNix: self.callPackage fooNix) | ||||||||||||||
(cabal2nix bar)!out ----> deBar = deferred eval (barNix: self.callPackage barNix) | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's only used to disambiguate this text and tell drv apart from deferred drv. However, I was wondering if this (or something similar) could be made a convention of assumeDerivation to more easily idententify asyncly built derivations. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah this example is a mess of unclear notation. (I am disgruntled by this in complete contrast to my standing by the sequent notation I like a lot.) |
||||||||||||||
``` | ||||||||||||||
and evaluated nix | ||||||||||||||
```nix | ||||||||||||||
mkScope (self: { | ||||||||||||||
foo = builtins.outputOf /nix/store/deFoo.drv "out"; | ||||||||||||||
bar = builtins.outputOf /nix/store/deBar.drv "out"; | ||||||||||||||
}) | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
If we then build `bar` we will get something steps like: | ||||||||||||||
|
||||||||||||||
1. ``` | ||||||||||||||
deBar!out | ||||||||||||||
``` | ||||||||||||||
2. Expand `deBar` in to see dep | ||||||||||||||
``` | ||||||||||||||
((cabal2nix bar)!out ----> (deferred eval (fooNix: self.callPackage barNix {}))!out | ||||||||||||||
``` | ||||||||||||||
3. Build cabal2nix and inline path for simplicity (or if cabal2nix job is floating CA derivation) | ||||||||||||||
``` | ||||||||||||||
(deferred eval self.callPackage built-barNix)!out | ||||||||||||||
``` | ||||||||||||||
4. Build deferred eval job and substitute | ||||||||||||||
``` | ||||||||||||||
deFoo!out ----> bar.drv!out | ||||||||||||||
``` | ||||||||||||||
5. Expand `deFoo` in to see dep | ||||||||||||||
``` | ||||||||||||||
((cabal2nix foo)!out ----> (deferred eval (fooNix: self.callPackage fooNix {}))!out ----> bar.drv!out | ||||||||||||||
``` | ||||||||||||||
6. Build cabal2nix and inline path for simplicity (or if cabal2nix job is floating CA derivation) | ||||||||||||||
``` | ||||||||||||||
(deferred eval self.callPackage built-fooNix)!out ----> bar.drv!out | ||||||||||||||
``` | ||||||||||||||
7. Build deferred eval job and substitute | ||||||||||||||
``` | ||||||||||||||
foo.drv!out ----> bar.drv!out | ||||||||||||||
``` | ||||||||||||||
8. Build foo and realize bar | ||||||||||||||
``` | ||||||||||||||
bar.drv[foo-path/foo!out]!out | ||||||||||||||
``` | ||||||||||||||
9. Build bar | ||||||||||||||
``` | ||||||||||||||
bar-path | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
The above is no doubt hard to read -- I am sorry about that --- but here are a few things to note: | ||||||||||||||
|
||||||||||||||
- The scheduler "substitutes on demand" giving us a lazy evaluation of sorts. | ||||||||||||||
This means that in the extreme case where we to make to, e.g., make a derivation for every C compiler invocation, we can avoid storing a very large completely static graph all at once. | ||||||||||||||
|
||||||||||||||
- At the same time, the derivations can be built in many different orders, so one can intentionally build all the `cabal2nix` derivations first and try to accumulate up the biggest static graph with `--dry-run`. | ||||||||||||||
This approximates what would happen in the "infinitely parallel" case when the scheduler will try to dole out work to do as fast as it can. | ||||||||||||||
|
||||||||||||||
# Drawbacks | ||||||||||||||
[drawbacks]: #drawbacks | ||||||||||||||
|
||||||||||||||
The main drawback is that the *only* the stub expressions are "pure" derivation. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
For other sort of values, we have no choice but wait. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
That means we cannot defer the `pname` `meta` etc. fields: either make do with the bare string `builtins.outputOf` provides, or *statically* add a fake `name` and `meta` etc. that must be manually synced with the deferred eval derivation if it is to match. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
# Alternatives | ||||||||||||||
[alternatives]: #alternatives | ||||||||||||||
|
||||||||||||||
- Do nothing, and continue to have no good answer for language-specific package mangers. | ||||||||||||||
Ericson2314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
- Instead of deferring only certain portions of the evaluation with `builtins.asssumeDerivation`, simply restart the entire eval. | ||||||||||||||
Quite simple, and no existing IFD code today needs to change. | ||||||||||||||
|
||||||||||||||
- Abandon IFD and just let users use the underlying dynamic derivation feature. | ||||||||||||||
This was my first idea, but I became worried that this was too hard to use for simple experiments. | ||||||||||||||
|
||||||||||||||
# Unresolved questions | ||||||||||||||
[unresolved]: #unresolved-questions | ||||||||||||||
|
||||||||||||||
The exact way the outputs refer to the replacement derivations / their outputs is subject to bikeshedding. | ||||||||||||||
|
||||||||||||||
# Future work | ||||||||||||||
[future]: #future-work | ||||||||||||||
|
||||||||||||||
1. Actually use this stuff in Nixpkgs with modification to the existing "lang2nix" tools. | ||||||||||||||
This is the lowest hanging fruit and most import thing. | ||||||||||||||
|
||||||||||||||
2. Try to breach the build system package manager divide. | ||||||||||||||
Just as there are foreign packages graphs to convert to Nix, there are Ninja and Make graphs we can also convert to Nix. | ||||||||||||||
This might really help with big builds like Chromium and LLVM. | ||||||||||||||
|
||||||||||||||
3. Try to convince upstream tools to use Nix like CMake, Meson, etc. use Ninja. | ||||||||||||||
Rather than converting Ninja plans, we might convince those tools to have purpose-built Nix backends. | ||||||||||||||
Language-specific package mangers that don't use Ninja today might also be modified to "let Nix do that actual building". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.