Skip to content

Commit 5e0b10c

Browse files
committed
nix: multiple systems flake from scratch
1 parent 93c6e62 commit 5e0b10c

2 files changed

Lines changed: 92 additions & 6 deletions

File tree

src/tools/nix.md

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ The following shows a *bare bones* flake using the
128128
In general, a derivation is a declarative description of how to run an
129129
*executable (builder)* on a set of *inputs (input derivations aka dependencies)*
130130
to produce a set of *outputs (store paths)*.
131-
```nix
131+
```nixos
132132
{{#include nix/bare-bones-derivation/flake.nix}}
133133
```
134134
Understanding this example is crucial as any abstractions such as the
@@ -171,7 +171,7 @@ Alternatively there is `stdenvNoCC.mkDerivation` which provides an environment
171171
without a C compiler.
172172
173173
The example show a simple build and installation of a C file.
174-
```nix
174+
```nixos
175175
{{#include nix/stdenv/flake.nix}}
176176
```
177177
> Use [`NIX_DEBUG=[0-7]`][nixpkgs-nixdebug] to enable `stdenv` debug logging.
@@ -211,7 +211,7 @@ an environment without a C compiler.
211211
The example shows an environment with the `zig` compiler and `zls`, the zig lsp
212212
server. Running `nix develop` will drop into a shell where these packages are
213213
available.
214-
```nix
214+
```nixos
215215
{{#include nix/devshell/flake.nix}}
216216
```
217217
@@ -248,7 +248,7 @@ is the [`nixpkgs.lib.genAttrs`][nixpkgs-genattrs] function, which allows to
248248
create an attribute set from a list of keys and a lambda function which computes
249249
the values of the attribute set.
250250
251-
```nix
251+
```nixos
252252
nix-repl> pkgs.lib.genAttrs [ "a" "b" ] (arg: "some-value-${arg}")
253253
{
254254
a = "some-value-a";
@@ -258,15 +258,24 @@ nix-repl> pkgs.lib.genAttrs [ "a" "b" ] (arg: "some-value-${arg}")
258258
259259
This can be used to build a flake to support multiple systems. The following
260260
shows a small example for two systems which defines a dev shell and a formatter.
261-
```nix
261+
```nixos
262262
{{#include nix/for-systems/flake.nix}}
263263
```
264264
265+
### a flake for multiple systems from scratch
266+
The following shows how to build the `nixpkgs.lib.genAttrs` utility from scratch
267+
with nix `builtins`. This mainly serves as learning but may come in handy when
268+
doing work without `nixpkgs`.
269+
270+
```nixos
271+
{{#include nix/for-systems-from-scratch/flake.nix}}
272+
```
273+
265274
## nix lang basics
266275
Nix is a functional language, where everything is an expression.
267276
The following shows enough nix lang to come quite far.
268277
269-
```nix
278+
```nixos
270279
$ nix repl
271280

272281
nix-repl> 1 + 2
@@ -376,6 +385,26 @@ nix-repl> myfn { inherit x ; y = 2; }
376385
> `foo.nix`, which returns the function (the value), which is then
377386
> called with the attribute set as input.
378387
388+
### useful builtins
389+
390+
```nixos
391+
# The "map" builtin takes a function and a list, then calls the function on
392+
# each list value and replaces the value with the result of the function.
393+
nix-repl> builtins.map (val: "some val ${val}") ["a" "b"]
394+
[
395+
"some val a"
396+
"some val b"
397+
]
398+
399+
# The "listToAttrs" builtin takes a list of name / value pairs (attribute sets)
400+
# and turns the list into a attribute set build from the name / value pairs.
401+
nix-repl> builtins.listToAttrs [{ name = "A"; value = "a"; } { name = "B"; value = "b"; }]
402+
{
403+
A = "a";
404+
B = "b";
405+
}
406+
```
407+
379408
### access flakes in the repl
380409
381410
```
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
description = "a flake for multiple systems from scratch";
3+
4+
inputs = {
5+
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
6+
};
7+
8+
outputs =
9+
{ self, nixpkgs }:
10+
let
11+
systems = [
12+
"x86_64-linux"
13+
"aarch64-linux"
14+
];
15+
16+
# "forSystems" is a function, which takes as argument a function.
17+
# It then calls the function passed for each value in the list "systems",
18+
# and passes the nixpkgs imported for the given system.
19+
# Finally it returns an attribute set where each key is the system in the
20+
# "systems" list and the value is what is returned from the invoked user
21+
# function.
22+
#
23+
# The pseudo code below shows the output.
24+
# {
25+
# systems[0] = f pkgs;
26+
# systems[1] = f pkgs;
27+
# ...
28+
# }
29+
#
30+
# The "listToAttrs" builtin turns a list of name / value pairs (attribute
31+
# sets) into an attribute set.
32+
# > listToAttrs [ { name = "A"; value = "a"; } ... ] -> { A = "a"; ... }
33+
#
34+
# The "map" builtin takes a function and a list, then calls the function
35+
# on each list value and replaces the value with the result of the function.
36+
# > map (v: "m${v}") [ "a" "b" ... ] -> [ "ma" "mb" ... ]
37+
forSystems =
38+
f:
39+
builtins.listToAttrs (
40+
builtins.map (system: {
41+
name = system;
42+
value = f (import nixpkgs { inherit system; });
43+
}) systems
44+
);
45+
in
46+
{
47+
formatter = forSystems (pkgs: pkgs.nixfmt);
48+
49+
devShells = forSystems (pkgs: {
50+
default = pkgs.mkShell {
51+
packages = [
52+
pkgs.strace
53+
];
54+
};
55+
});
56+
};
57+
}

0 commit comments

Comments
 (0)