$ nix run "git+https://codeberg.org/mhwombat/hello-flake" - [K [KHello from your flake!+Hello from your flake!
diff --git a/Makefile b/Makefile index fa3015e..3b715c4 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,8 @@ pdf : $(PDF_FILE) # The "dir" and "notdir" functions extract the directory and base filename from a path, respectively. %-generated.adoc : %.adoc0 > cd $(dir $@); run-code-inline < $(notdir $<) 2>&1 | tee $(notdir $@) +> sed -i 's/\x0d\x1b.\x4b//g' $@ +# The last line fixes some weird characters generated by some nix commands $(HTML_FILE) : $(ADOC_FILES) > asciidoctor -b html5 -d book $(ADOC_ATTRIBUTES) $(ADOC_HTML_ATTRIBUTES) -o $@ $(MAIN_ADOC_FILE) diff --git a/index.html b/index.html index d7fb79e..2be7afd 100644 --- a/index.html +++ b/index.html @@ -94,7 +94,7 @@ pre.pygments .tok-il { color: #666666 } /* Literal.Number.Integer.Long */
$ nix run "git+https://codeberg.org/mhwombat/hello-flake" - [K [KHello from your flake!+Hello from your flake!
$ nix shell "git+https://codeberg.org/mhwombat/hello-flake" - [K [K.... - -In this shell, the command is on our `$PATH`, so we can execute the -command by name.+
$ nix shell "git+https://codeberg.org/mhwombat/hello-flake"
$ hello-flake -Hello from your flake!
+In this shell, the command is on our $PATH, so we can execute the
+command by name.
Nix didn’t _install_ the package; it merely built and placed it in a -directory called the "`Nix store`". Thus we can have multiple versions +$ hello-flake +Hello from your flake!+
Nix didn’t install the package; it merely built and placed it in a +directory called the “Nix store”. Thus we can have multiple versions of a package without worrying about conflicts. We can find out the -location of the executable, if we’re curious. -
$ which hello-flake -/nix/store/qskl8ajlgnl654fhgsmv74yv8x9r3kzg-hello-flake/bin/hello-flake
+location of the executable, if we’re curious.Once we exit that shell, the `hello-flake` command is no longer -directly available.+
$ which hello-flake +/nix/store/qskl8ajlgnl654fhgsmv74yv8x9r3kzg-hello-flake/bin/hello-flake
$ exit +
Once we exit that shell, the hello-flake command is no longer
+directly available.
$ exit $ hello-flake -sh: line 3: hello-flake: command not found +sh: line 3: hello-flake: command not found
However, we can still run the command using the store path we found +
However, we can still run the command using the store path we found earlier. That’s not particularly convenient, but it does demonstrate -that the package remains in the store for future use. -
/nix/store/0xbn2hi6h1m5h4kc02vwffs2cydrbc0r-hello-flake/bin/hello-flake
+that the package remains in the store for future use.:leveloffset!: - -:leveloffset: +1 - -= The hello-flake repo - -Let’s clone the repository and see how the flake is defined.+
/nix/store/0xbn2hi6h1m5h4kc02vwffs2cydrbc0r-hello-flake/bin/hello-flake
$ git clone https://codeberg.org/mhwombat/hello-flake -Cloning into 'hello-flake'… +
Let’s clone the repository and see how the flake is defined.
+$ git clone https://codeberg.org/mhwombat/hello-flake +Cloning into 'hello-flake'... $ cd hello-flake $ ls flake.lock flake.nix hello-flake LICENSE -README.md +README.md
This is a simple repo with just a few files. Like most git repos, it -includes `LICENSE`, which contains the software license, and `README.md` -which provides information about the repo. - -The `hello-flake` file is the executable we ran earlier. +
This is a simple repo with just a few files. Like most git repos, it
+includes LICENSE, which contains the software license, and README.md
+which provides information about the repo.
The hello-flake file is the executable we ran earlier.
This particular executable is just a shell script, so we can view it.
-It’s an extremly simple script with just two lines.
+It’s an extremly simple script with just two lines.
1
+2
+3
#!/usr/bin/env sh
-[source,bash,linenums]
-.hello-flake
+echo "Hello from your flake!"
+
#!/usr/bin/env sh
-echo "Hello from your flake!"
+Now that we have a copy of the repo, we can execute this script +directly.
Now that we have a copy of the repo, we can execute this script -directly.+
$ ./hello-flake +Hello from your flake!
$ ./hello-flake -Hello from your flake!
-Not terribly exciting, I know. But starting with such a simple package +Not terribly exciting, I know. But starting with such a simple package makes it easier to focus on the flake system without getting bogged down -in the details. We’ll make this script a little more interesting later. +in the details. We’ll make this script a little more interesting later.
+
Let’s look at another file. The file that defines how to package a flake
+is always called flake.nix.
1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
{
+ # See https://github.com/mhwombat/nix-for-numbskulls/blob/main/flakes.md
+ # for a brief overview of what each section in a flake should or can contain.
-Let’s look at another file. The file that defines how to package a flake
-is always called `flake.nix`.
+ description = "a very simple and friendly flake";
-[source,nix,linenums]
-.flake.nix
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
+
+ outputs = { self, nixpkgs, flake-utils }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs { inherit system; };
+ in
+ {
+ packages = rec {
+ hello = pkgs.stdenv.mkDerivation rec {
+ name = "hello-flake";
+
+ src = ./.;
+
+ unpackPhase = "true";
+
+ buildPhase = ":";
+
+ installPhase =
+ ''
+ mkdir -p $out/bin
+ cp $src/hello-flake $out/bin/hello-flake
+ chmod +x $out/bin/hello-flake
+ '';
+ };
+ default = hello;
+ };
+
+ apps = rec {
+ hello = flake-utils.lib.mkApp { drv = self.packages.${system}.hello; };
+ default = hello;
+ };
+ }
+ );
+}
+
{ - # See https://github.com/mhwombat/nix-for-numbskulls/blob/main/flakes.md - # for a brief overview of what each section in a flake should or can contain.
-description = "a very simple and friendly flake";-
inputs = {
- nixpkgs.url = "github:NixOS/nixpkgs";
- flake-utils.url = "github:numtide/flake-utils";
-};
-outputs = { self, nixpkgs, flake-utils }:
- flake-utils.lib.eachDefaultSystem (system:
- let
- pkgs = import nixpkgs { inherit system; };
- in
- {
- packages = rec {
- hello = pkgs.stdenv.mkDerivation rec {
- name = "hello-flake";
-src = ./.;-
unpackPhase = "true";-
buildPhase = ":";-
installPhase = - '' - mkdir -p $out/bin - cp $src/hello-flake $out/bin/hello-flake - chmod +x $out/bin/hello-flake - ''; - }; - default = hello; -};-
apps = rec {
- hello = flake-utils.lib.mkApp { drv = self.packages.${system}.hello; };
- default = hello;
- };
- }
- );
-}
-If this is your first time seeing a flake definition, it probably looks ++focus on the inputs section. +If this is your first time seeing a flake definition, it probably looks intimidating. Flakes are written in a functional language called -Nixfootnote:[For an introduction to the Nix language, see -https://nixos.org/guides/nix-language.html[Nix language basics].]. Yes, -"`Nix`" is the name of both the package manager and the language it +Nix[1]. Yes, +“Nix” is the name of both the package manager and the language it uses. We’ll look at this in more detail shortly. For now, I’d like to -focus on the inputs section. - -[source,nix]
inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
inputs = { - nixpkgs.url = "github:NixOS/nixpkgs"; - flake-utils.url = "github:numtide/flake-utils"; - };
-There are just two entries, one for `nixpkgs` and one for `flake-utils`. -The first one, `nixpkgs` refers to the collection of standard software ++There are just two entries, one for
nixpkgsand one forflake-utils. +The first one,nixpkgsrefers to the collection of standard software packages that can be installed with the Nix package manager. The second, -`flake-utils`, is a collection of utilities that simplify writing -flakes. The important thing to note is that the `hello-flake` package -_depends_ on `nixpkgs` and `flake-utils`. - -Finally, let’s look at `flake.lock`, or rather, just part of it. - -[source,linenums] -.flake.lock
flake-utils, is a collection of utilities that simplify writing
+flakes. The important thing to note is that the hello-flake package
+depends on nixpkgs and flake-utils.
+Finally, let’s look at flake.lock, or rather, just part of it.
{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1681202837,
+ "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "cfacdce06f30d2b68473a46042957675eebb3401",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1681665000,
+ "narHash": "sha256-hDGTR59wC3qrQZFxVi2U3vTY+r02+Okbq080hO1C4Nk=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "3a6205d9f79fe526be03d8c465403b118ca4cf37",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+. . .
{ - "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1681665000, - "narHash": "sha256-hDGTR59wC3qrQZFxVi2U3vTY+r02+Okbq080hO1C4Nk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "3a6205d9f79fe526be03d8c465403b118ca4cf37", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - } -. . .
-If `flake.nix` seemed intimidating, then this file looks like an +-If
flake.nixseemed intimidating, then this file looks like an invocation for Cthulhu. The good news is that this file is automatically generated; you never need to write it. It contains information about all of the dependencies for the flake, including where they came from, the -exact version/revision, and hash. This lockfile _uniquely_ specifies all +exact version/revision, and hash. This lockfile uniquely specifies all flake dependencies, (e.g., version number, branch, revision, hash), so -that _anyone, anywhere, any time, can re-create the exact same -environment that the original developer used._ - -No more complaints of "`but it works on my machine!`". That is the -benefit of using flakes. - -//// -Good adoc0 scripts clean up after themselves. -$ cd .. ; rm -rf hello-flake # clean up -//// - -:leveloffset: 1 - -:leveloffset: +1 - -= Flake structure - -The basic structure of a flake is shown below. - -[source,nix,subs=quotes]
{ +
No more complaints of “but it works on my machine!”. That is the +benefit of using flakes.
+The basic structure of a flake is shown below.
+{
description = package description
inputs = dependencies
outputs = what the flake produces
nixConfig = advanced configuration options
-}
+}
== Description - -The `description` part is self-explanatory; it’s just a string. You -probably won’t need `nixConfig` unless you’re doing something fancy. I’m -going to focus on what goes into the `inputs` and `outputs` sections, -and highlight some of the things I found confusing when I began using flakes. - -== Inputs - -This section specifies the dependencies of a flake. It’s an _attribute -set_; it maps keys to values. - -To ensure that a build is reproducible, the build step runs in a _pure_ +
The description part is self-explanatory; it’s just a string. You
+probably won’t need nixConfig unless you’re doing something fancy. I’m
+going to focus on what goes into the inputs and outputs sections,
+and highlight some of the things I found confusing when I began using flakes.
This section specifies the dependencies of a flake. It’s an attribute +set; it maps keys to values.
+To ensure that a build is reproducible, the build step runs in a pure environment with no network access. Therefore, any external dependencies -must be specified in the "`inputs`" section so they can be fetched in -advance (before we enter the pure environment). - -Each entry in this section maps an input name to a _flake reference_. -This commonly takes the following form. -
NAME.url = URL-LIKE-EXPRESSION
+Each entry in this section maps an input name to a flake reference. +This commonly takes the following form.
As a first example of a flake reference, all (almost all?) flakes depend on "`nixpkgs`", +NAME.url = URL-LIKE-EXPRESSION+
As a first example of a flake reference, all (almost all?) flakes depend on “nixpkgs”, which is a large Git repository of programs and libraries that are -pre-packaged for Nix. We can write that as - -[source,nix,subs=quotes] +pre-packaged for Nix. We can write that as
+nixpkgs.url = "github:NixOS/nixpkgs/nixos-version";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-version";
+where version is replaced with the version number that you used to build
+the package, e.g. 22.11. Information about the latest nixpkgs releases
+is available at https://status.nixos.org/. You can also write the entry
+without the version number
where _version_ is replaced with the version number that you used to build -the package, e.g. `22.11`. Information about the latest nixpkgs releases -is available at https://status.nixos.org/. You can also write the entry -without the version number - -[source,nix]+
nixpkgs.url = "github:NixOS/nixpkgs/nixos";
nixpkgs.url = "github:NixOS/nixpkgs/nixos";
+or more simply,
or more simply, - -[source,nix]+
nixpkgs.url = "nixpkgs";
nixpkgs.url = "nixpkgs";
-You might be concerned that omitting the version number would make the ++(You might be concerned that omitting the version number would make the build non-reproducible. If someone else builds the flake, could they end up with a different version of nixpkgs? No! remember that the lockfile -(`flake.lock`) _uniquely_ specifies all flake inputs. - -Git and Mercurial repositories are the most common type of flake -reference, as in the examples below. - -A Git repository:: - `git+https://github.com/NixOS/patchelf` -A specific branch of a Git repository:: - `git+https://github.com/NixOS/patchelf?ref=master` -A specific revision of a Git repository:: - + - `git+https://github.com/NixOS/patchelf?ref=master&rev=f34751b88bd07d7f44f5cd3200fb4122bf916c7e` -A tarball:: - `https://github.com/NixOS/patchelf/archive/master.tar.gz` - -You can find more examples of flake references in the -https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#examples[Nix -Reference Manual]. - -[NOTE] -==== -Although you probably won’t need to use it, there is another syntax for -flake references that you might encounter. This example - -[source,nix]
flake.lock) uniquely specifies all flake inputs.
+Git and Mercurial repositories are the most common type of flake +reference, as in the examples below.
+git+https://github.com/NixOS/patchelf
git+https://github.com/NixOS/patchelf?ref=master
+git+https://github.com/NixOS/patchelf?ref=master&rev=f34751b88bd07d7f44f5cd3200fb4122bf916c7e
You can find more examples of flake references in the +Nix +Reference Manual.
+| + + | +
+
+
+Although you probably won’t need to use it, there is another syntax for +flake references that you might encounter. This example +
+
+
-
-inputs.import-cargo = { - type = "github"; - owner = "edolstra"; - repo = "import-cargo"; -}; +is equivalent to
+
-
is equivalent to - -[source,nix]+
|
+
inputs.import-cargo.url = "github:edolstra/import-cargo";
-==== - -Each of the `inputs` is fetched, evaluated and passed to the `outputs` ++input. +Each of the
inputsis fetched, evaluated and passed to theoutputsfunction as a set of attributes with the same name as the corresponding -input. - -== Outputs - -This section is a function that essentially returns the recipe for -building the flake. - -We said above that `inputs` are passed to the `outputs`, so we need to -list them as parameters. This example references the `import-cargo` -dependency defined in the previous example. - -[source,nix,subs=quotes]
This section is a function that essentially returns the recipe for +building the flake.
+We said above that inputs are passed to the outputs, so we need to
+list them as parameters. This example references the import-cargo
+dependency defined in the previous example.
outputs = { self, nixpkgs, import-cargo }: {
+ definitions for outputs
+};
outputs = { self, nixpkgs, import-cargo }: { - definitions for outputs -};
-So what actually goes in the highlighted section? +So what actually goes in the highlighted section? That depends on the programming languages your software is written in, the build system you use, and more. There are Nix functions and tools that can simplify much of this, and new, easier-to-use ones are released -regularly. We’ll look at some of these in the next section. - -:leveloffset: 1 - -:leveloffset: +1 - -= A generic flake - -The previous section presented a very high-level view of flakes, +regularly. We’ll look at some of these in the next section.
+
The previous section presented a very high-level view of flakes, focusing on the basic structure. In this section, we will add a bit more -detail. - -Flakes are written in the Nix programming language, which is a +detail.
+Flakes are written in the Nix programming language, which is a functional language. As with most programming languages, there are many ways to achieve the same result. Below is an example you can follow when -writing your own flakes. I’ll explain the example in some detail. - -[source,subs=quotes] ----- -{ - description = "#_brief package description_#"; +writing your own flakes. I’ll explain the example in some detail.
+{
+ description = "brief package description";
inputs = {
- [.highlight01]#nixpkgs#.url = "github:NixOS/nixpkgs";
- [.highlight02]#flake-utils#.url = "github:numtide/flake-utils";
- [.highlight03]#..._other dependencies_...# ❶
+ nixpkgs.url = "github:NixOS/nixpkgs";
+ flake-utils.url = "github:numtide/flake-utils";
+ ...other dependencies... ❶
};
- outputs = { self, [.highlight01]#nixpkgs#, [.highlight02]#flake-utils#, [.highlight03]#..._other dependencies_...# ❷ }:
+ outputs = { self, nixpkgs, flake-utils, ...other dependencies... ❷ }:
flake-utils.lib.eachDefaultSystem (system: ❸
let
pkgs = import nixpkgs { inherit system; };
@@ -720,124 +780,129 @@ writing your own flakes. I’ll explain the example in some detail.
{
devShells = rec {
default = pkgs.mkShell {
- packages = [ #_packages needed for development shell_#; ❹ ]))
+ packages = [ packages needed for development shell; ❹ ]))
];
};
packages = rec {
- [.highlight04]#myPackageName# = #_package definition_#; ❺
- default = [.highlight04]#myPackageName#;
+ myPackageName = package definition; ❺
+ default = myPackageName;
};
apps = rec {
- [.highlight04]#myPackageName# = flake-utils.lib.mkApp { drv = self.packages.${system}.[.highlight04]#myPackageName#; };
- default = [.highlight04]#myPackageName#;
+ myPackageName = flake-utils.lib.mkApp { drv = self.packages.${system}.myPackageName; };
+ default = myPackageName;
};
}
);
-}
-----
-
-We discussed how to specify flake inputs `❶` in the previous section, so
+}
+We discussed how to specify flake inputs ❶ in the previous section, so
this part of the flake should be familiar. Remember also that any
dependencies in the input section should also be listed at the beginning
-of the outputs section `❷`.
-
-Now it’s time to look at the content of the output section. If we want
+of the outputs section ❷.
Now it’s time to look at the content of the output section. If we want
the package to be available for multiple systems (e.g.,
-"`x86_64-linux`", "`aarch64-linux`", "`x86_64-darwin`", and
-"`aarch64-darwin`"), we need to define the output for each of those
+“x86_64-linux”, “aarch64-linux”, “x86_64-darwin”, and
+“aarch64-darwin”), we need to define the output for each of those
systems. Often the definitions are identical, apart from the name of the
-system. The eachDefaultSystem function `❸` provided by flake-utils allows
+system. The eachDefaultSystem function ❸ provided by flake-utils allows
us to write a single definition using a variable for the system name.
The function then iterates over all default systems to generate the
-outputs for each one.
-
-The `devShells` variable specifies the environment that should be
+outputs for each one.
The devShells variable specifies the environment that should be
available when doing development on the package. If you don’t need a
-special development environment, you can omit this section. At `❹` you
+special development environment, you can omit this section. At ❹ you
would list any tools (e.g., compilers and language-specific build tools)
you want to have available in a development shell. If the compiler needs
access to language-specific packages, there are Nix functions to assist
with that. These functions are very language-specific, and not always
well-documented. We will see examples for some languages later in the
tutorial. In general, I recommend that you do a web search for
-"`nix language`", and try to find resources that were written or updated
-recently.
-
-The `packages` variable defines the packages that this flake provides.
-The package definition `❺` depends on the programming languages your
+“nix language”, and try to find resources that were written or updated
+recently.
The packages variable defines the packages that this flake provides.
+The package definition ❺ depends on the programming languages your
software is written in, the build system you use, and more. There are
Nix functions and tools that can simplify much of this, and new,
easier-to-use ones are released regularly. Again, I recommend that you
-do a web search for "`nix language`", and try to find resources that
-were written or updated recently.
-
-The `apps` variable identifies any applications provided by the flake.
-In particular, it identifies the default executable ❻ that `nix run`
-will run if you don’t specify an app.
-
-Below is a list of some functions that are commonly used in
-this section.
-
-General-purpose::
- The standard environment provides `mkDerivation`, which is especially
- useful for the typical `./configure; make; make install` scenario.
- It’s customisable.
-Python::
- `buildPythonApplication`, `buildPythonPackage`.
-Haskell::
- `mkDerivation` (Haskell version, which is a wrapper around the
- standard environment version), `developPackage`, `callCabal2Nix`.
-
-:leveloffset: 1
-
-:leveloffset: +1
-
-= Another look at hello-flake
-
-Now that we have a better understanding of the structure of `flake.nix`,
-let’s have a look at the one we saw earlier, in the `hello-flake` repo.
-If you compare this flake definition to the colour-coded template
-presented in the previous section, most of it should look familiar.
-
-[subs=quotes]
-.flake.nix
-
{ - description = "a very simple and friendly flake";
+The apps variable identifies any applications provided by the flake.
+In particular, it identifies the default executable ❻ that nix run
+will run if you don’t specify an app.
Below is a list of some functions that are commonly used in +this section.
+The standard environment provides mkDerivation, which is especially
+useful for the typical ./configure; make; make install scenario.
+It’s customisable.
buildPythonApplication, buildPythonPackage.
mkDerivation (Haskell version, which is a wrapper around the
+standard environment version), developPackage, callCabal2Nix.
Now that we have a better understanding of the structure of flake.nix,
+let’s have a look at the one we saw earlier, in the hello-flake repo.
+If you compare this flake definition to the colour-coded template
+presented in the previous section, most of it should look familiar.
inputs = {
- nixpkgs.url = "github:NixOS/nixpkgs";
- flake-utils.url = "github:numtide/flake-utils";
-};
-outputs = { self, nixpkgs, flake-utils }:
- flake-utils.lib.eachDefaultSystem (system:
- let
- pkgs = import nixpkgs { inherit system; };
- in
- {
- packages = rec {
- hello =
- . . .
- _SOME UNFAMILIAR STUFF_
- . . .
+{
+ description = "a very simple and friendly flake";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
+
+ outputs = { self, nixpkgs, flake-utils }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs { inherit system; };
+ in
+ {
+ packages = rec {
+ hello =
+ . . .
+ SOME UNFAMILIAR STUFF
+ . . .
+ };
+ default = hello;
};
- default = hello;
- };
- apps = rec {
+
+ apps = rec {
hello = flake-utils.lib.mkApp { drv = self.packages.${system}.hello; };
default = hello;
};
@@ -846,146 +911,171 @@ presented in the previous section, most of it should look familiar.
}
This `flake.nix` doesn’t have a `devShells` section, because development +++This
+flake.nixdoesn’t have adevShellssection, because development on the current version doesn’t require anything beyond -the "`bare bones`" linux commands. Later we will add a feature that requires -additional development tools. +the “bare bones” linux commands. Later we will add a feature that requires +additional development tools.++Now let’s look at the section I labeled
+SOME UNFAMILIAR STUFFand +see what it does.+-+packages = rec { + hello = pkgs.stdenv.mkDerivation rec { ❶ + name = "hello-flake"; -Now let’s look at the section I labeled `SOME UNFAMILIAR STUFF` and -see what it does. + src = ./.; ❷ -[subs=quotes]+ unpackPhase = "true"; + + buildPhase = ":"; + + installPhase = + '' + mkdir -p $out/bin ❸ + cp $src/hello-flake $out/bin/hello-flake ❹ + chmod +x $out/bin/hello-flake ❺ + ''; + };----packages = rec { - hello = pkgs.stdenv.mkDerivation rec { ❶ - name = "hello-flake";-----src = ./.; ❷-----unpackPhase = "true";-----buildPhase = ":";-----installPhase = - '' - mkdir -p $out/bin ❸ - cp $src/hello-flake $out/bin/hello-flake ❹ - chmod +x $out/bin/hello-flake ❺ - ''; -};--+-This flake uses `mkDerivation` `❶` which is a very useful +++This flake uses
+mkDerivation❶which is a very useful general-purpose package builder provided by the Nix standard environment. It’s especially useful for the typical -`./configure; make; make install` scenario, but for this flake we don’t -even need that. - -The `name` variable is the name of the flake, as it would appear in a +./configure; make; make installscenario, but for this flake we don’t +even need that.++The
+namevariable is the name of the flake, as it would appear in a package listing if we were to add it to Nixpkgs or another package -collection. The `src` variable `❷` supplies the location of the source -files, relative to `flake.nix`. When a flake is accessed for the first +collection. Thesrcvariable❷supplies the location of the source +files, relative toflake.nix. When a flake is accessed for the first time, the repository contents are fetched in the form of a tarball. The -`unpackPhase` variable indicates that we do want the tarball to be -unpacked. - -The `buildPhase` variable is a sequence of Linux commands to build the +unpackPhasevariable indicates that we do want the tarball to be +unpacked.++The
+buildPhasevariable is a sequence of Linux commands to build the package. Typically, building a package requires compiling the source code. However, that’s not required for a simple shell script. So -`buildPhase` consists of a single command, `:`, -which is a no-op or "`do nothing`" command. - -The `installPhase` variable is a sequence of Linux commands that will do -the actual installation. In this case, we create a directory `❸` for the -installation, copy the `hello-flake` script there `❹`, and make the -script executable `❺`. The environment variable `$src` refers to the -source directory, which we specified earlier `❷`. - -Earlier we said that the build step runs in a pure environment to ensure +buildPhaseconsists of a single command,:, +which is a no-op or “do nothing” command.++The
+installPhasevariable is a sequence of Linux commands that will do +the actual installation. In this case, we create a directory❸for the +installation, copy thehello-flakescript there❹, and make the +script executable❺. The environment variable$srcrefers to the +source directory, which we specified earlier❷.++Earlier we said that the build step runs in a pure environment to ensure that builds are reproducible. This means no Internet access; indeed no access to any files outside the build directory. During the build and install phases, the only commands available are those provided by the Nix standard environment and the external dependencies identified in the -`inputs` section of the flake. - -I’ve mentioned the Nix standard environment before, but I didn’t explain -what it is. The standard environment, or `stdenv`, refers to the -functionality that is available during the build and install phases of a -Nix package (or flake). It includes the commands listed -belowfootnote:[For more information on the standard environment, see the -https://nixos.org/manual/nixpkgs/stable/#sec-tools-of-stdenv[Nixpkgs -manual]]. - -* The GNU C Compiler, configured with C and C++ support. -* GNU coreutils (contains a few dozen standard Unix commands). -* GNU findutils (contains find). -* GNU diffutils (contains diff, cmp). -* GNU sed. -* GNU grep. -* GNU awk. -* GNU tar. -* gzip, bzip2 and xz. -* GNU Make. -* Bash. -* The patch command. -* On Linux, stdenv also includes the patchelf utility. - -Only a few environment variables are available. The most interesting -ones are listed below. - -* `$name` is the package name. -* `$src` refers to the source directory. -* `$out` is the path to the location in the Nix store where the package -will be added. -* `$system` is the system that the package is being built for. -* `$PWD` and `$TMP` both point to a temporary build directories -* `$HOME` and `$PATH` point to nonexistent directories, so the build -cannot rely on them. - -:leveloffset: 1 - -:leveloffset: +1 - -= Modifying the flake - -== The Nix development shell - -Let’s make a simple modification to the script. This will give you an -opportunity to check your understanding of flakes. - -The first step is to enter a development shell. - -//// -The user would have done this in an earlier section. -However, my adoc0 scripts clean up after themselves, so we need to do it again. -$ git clone https://codeberg.org/mhwombat/hello-flake -Cloning into 'hello-flake'... -$ cd hello-flake -//// -
inputssection of the flake.-+$ nix develop - [K [K….
+I’ve mentioned the Nix standard environment before, but I didn’t explain +what it is. The standard environment, or
+stdenv, refers to the +functionality that is available during the build and install phases of a +Nix package (or flake). It includes the commands listed +below[2].+++
+- +
+The GNU C Compiler, configured with C and C++ support.
+- +
+GNU coreutils (contains a few dozen standard Unix commands).
+- +
+GNU findutils (contains find).
+- +
+GNU diffutils (contains diff, cmp).
+- +
+GNU sed.
+- +
+GNU grep.
+- +
+GNU awk.
+- +
+GNU tar.
+- +
+gzip, bzip2 and xz.
+- +
+GNU Make.
+- +
+Bash.
+- +
+The patch command.
+- +
+On Linux, stdenv also includes the patchelf utility.
+++Only a few environment variables are available. The most interesting +ones are listed below.
++++
+- +
++
$nameis the package name.- +
++
$srcrefers to the source directory.- +
++
$outis the path to the location in the Nix store where the package +will be added.- +
++
$systemis the system that the package is being built for.- +
++
$PWDand$TMPboth point to a temporary build directories- +
++
$HOMEand$PATHpoint to nonexistent directories, so the build +cannot rely on them.
Let’s make a simple modification to the script. This will give you an +opportunity to check your understanding of flakes.
+The first step is to enter a development shell.
+$ nix develop+
The flake.nix file specifies all of the tools that are needed during
@@ -1027,7 +1117,7 @@ the build outputs in a directory called result.
$ nix build - [K [K$ result/bin/hello-flake +$ result/bin/hello-flake Hello from your flake!
nix run.
$ nix run - [K [KHello from your flake!+Hello from your flake!
result.
+Now we’re ready to make the flake a little more interesting.
Instead of using the echo command in the script, we can use the Linux cowsay
@@ -1247,10 +1338,10 @@ don’t need to git push the changes until we’re ready to share t
$ git commit hello-flake flake.nix -m 'added bovine feature'
-[main cfd67d4] added bovine feature
+[main 9e2fb59] added bovine feature
2 files changed, 7 insertions(+), 1 deletion(-)
$ nix run
-
[K
[K ________________________
+ ________________________
< Hello from your flake! >
------------------------
\ ^__^
@@ -1262,7 +1353,7 @@ $ nix run
If you’re getting confused about when to use the different commands, it’s because there’s more than one way to use Nix. I tend to think of it @@ -1326,7 +1417,7 @@ not execute anything (perhaps it’s just a library).
It is a bit annoying to modify flake.nix and ether rebuild or reload
the development environment every time you need another tool. However,
@@ -1335,8 +1426,11 @@ to the exact versions, are captured in flake.lock, and that anyone
else will be able to reproduce the development environment.
At last we are ready to create a flake from scratch! Start with an empty directory and create a git repository.
@@ -1349,8 +1443,8 @@ $ git init Initialized empty Git repository in /home/amy/codeberg/nix-book/source/python-flake/hello-python/.git/Next, we’ll create a simple Python program.
Next, create a Python script to build the package. We’ll use Python’s setuptools, but you can use other build tools. For more information on @@ -1472,7 +1566,7 @@ package manually.
$ python -m build -/nix/store/9c03r86hcdn43dm3hsgjirifvyzfkhwh-python3-3.10.12/bin/python: No module named build+/nix/store/2c7sgx69p6mmp76cvmi5j6c72dj76jj8-python3-3.10.12/bin/python: No module named build
exit followed by the
After a lot of output messages, the build succeeds.
Now we should write flake.nix. We already know how to write most of
the flake from the examples we did earlier. The two parts that will be
@@ -1687,6 +1781,9 @@ $ nix run
warning: Git tree '/home/amy/codeberg/nix-book/source/python-flake/hello-python' is dirty
warning: creating lock file '/home/amy/codeberg/nix-book/source/python-flake/hello-python/flake.lock'
warning: Git tree '/home/amy/codeberg/nix-book/source/python-flake/hello-python' is dirty
+this derivation will be built:
+ /nix/store/qpyvxm7r2savmcx7b5d6x55ggpvc2567-hello-flake-python.drv
+building '/nix/store/qpyvxm7r2savmcx7b5d6x55ggpvc2567-hello-flake-python.drv'...
Hello from inside a Python program built with a Nix flake!
$ git add flake.lock $ git commit -a -m 'initial commit' -[master (root-commit) f66e03b] initial commit +[master (root-commit) d954bad] initial commit 4 files changed, 127 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix @@ -1716,7 +1813,7 @@ another directory and running it from there.$ cd .. $ nix run ./hello-python - [K [KHello from inside a Python program built with a Nix flake!+Hello from inside a Python program built with a Nix flake!
There may be times where all you need is a shell. Perhaps you’re doing a quick, one-off task. @@ -1744,8 +1843,8 @@ In this situation, the older, non-flake way of using Nix may be more convenient. The examples in this chapter will illustrate the process.
This shell provides access to two packages from nixpkgs: hello and cowsay.
@@ -1792,8 +1891,8 @@ $ cowsay "moo"The command-line equivalent would be nix-shell -p hello cowsay
This shell provides access to three Haskell packages that are on my hard drive.
@@ -1906,8 +2005,8 @@ mkShell {This shell provides access to four Haskell packages that are on my hard drive. The fourth package depends on the first three to build.
@@ -1956,8 +2055,8 @@ mkShell {This shell has the environment variable FOO set to “bar”
You can use nix-shell to run scripts in arbitrary languages, providing
the necessary dependencies. This is particularly convenient for
@@ -2003,8 +2104,8 @@ separate flake.nix.
nix-shell. The second should declares the scrpt
interpreter and any dependencies. Here are some examples.