mirror of
https://codeberg.org/mhwombat/nix-book.git
synced 2026-01-07 14:27:24 +08:00
3015 lines
No EOL
149 KiB
HTML
3015 lines
No EOL
149 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="Asciidoctor 2.0.20">
|
||
<meta name="author" content="Amy de Buitléir">
|
||
<title>Wombat’s Book of Nix</title>
|
||
<style>
|
||
@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";
|
||
@import "https://cdn.jsdelivr.net/gh/asciidoctor/asciidoctor@2.0/data/stylesheets/asciidoctor-default.css";
|
||
|
||
.highlight01 {background: #66ffff}
|
||
.highlight02 {background: #b3ff66}
|
||
.highlight03 {background: #ffd966}
|
||
.highlight04 {background: #b366ff}
|
||
|
||
</style>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||
<style>
|
||
pre.pygments .hll { background-color: #ffffcc }
|
||
pre.pygments { background: #f8f8f8; }
|
||
pre.pygments .tok-c { color: #3D7B7B; font-style: italic } /* Comment */
|
||
pre.pygments .tok-err { border: 1px solid #FF0000 } /* Error */
|
||
pre.pygments .tok-k { color: #008000; font-weight: bold } /* Keyword */
|
||
pre.pygments .tok-o { color: #666666 } /* Operator */
|
||
pre.pygments .tok-ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
|
||
pre.pygments .tok-cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
|
||
pre.pygments .tok-cp { color: #9C6500 } /* Comment.Preproc */
|
||
pre.pygments .tok-cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
|
||
pre.pygments .tok-c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
|
||
pre.pygments .tok-cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
|
||
pre.pygments .tok-gd { color: #A00000 } /* Generic.Deleted */
|
||
pre.pygments .tok-ge { font-style: italic } /* Generic.Emph */
|
||
pre.pygments .tok-gr { color: #E40000 } /* Generic.Error */
|
||
pre.pygments .tok-gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||
pre.pygments .tok-gi { color: #008400 } /* Generic.Inserted */
|
||
pre.pygments .tok-go { color: #717171 } /* Generic.Output */
|
||
pre.pygments .tok-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||
pre.pygments .tok-gs { font-weight: bold } /* Generic.Strong */
|
||
pre.pygments .tok-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||
pre.pygments .tok-gt { color: #0044DD } /* Generic.Traceback */
|
||
pre.pygments .tok-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
|
||
pre.pygments .tok-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
|
||
pre.pygments .tok-kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
|
||
pre.pygments .tok-kp { color: #008000 } /* Keyword.Pseudo */
|
||
pre.pygments .tok-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
|
||
pre.pygments .tok-kt { color: #B00040 } /* Keyword.Type */
|
||
pre.pygments .tok-m { color: #666666 } /* Literal.Number */
|
||
pre.pygments .tok-s { color: #BA2121 } /* Literal.String */
|
||
pre.pygments .tok-na { color: #687822 } /* Name.Attribute */
|
||
pre.pygments .tok-nb { color: #008000 } /* Name.Builtin */
|
||
pre.pygments .tok-nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||
pre.pygments .tok-no { color: #880000 } /* Name.Constant */
|
||
pre.pygments .tok-nd { color: #AA22FF } /* Name.Decorator */
|
||
pre.pygments .tok-ni { color: #717171; font-weight: bold } /* Name.Entity */
|
||
pre.pygments .tok-ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
|
||
pre.pygments .tok-nf { color: #0000FF } /* Name.Function */
|
||
pre.pygments .tok-nl { color: #767600 } /* Name.Label */
|
||
pre.pygments .tok-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||
pre.pygments .tok-nt { color: #008000; font-weight: bold } /* Name.Tag */
|
||
pre.pygments .tok-nv { color: #19177C } /* Name.Variable */
|
||
pre.pygments .tok-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||
pre.pygments .tok-w { color: #bbbbbb } /* Text.Whitespace */
|
||
pre.pygments .tok-mb { color: #666666 } /* Literal.Number.Bin */
|
||
pre.pygments .tok-mf { color: #666666 } /* Literal.Number.Float */
|
||
pre.pygments .tok-mh { color: #666666 } /* Literal.Number.Hex */
|
||
pre.pygments .tok-mi { color: #666666 } /* Literal.Number.Integer */
|
||
pre.pygments .tok-mo { color: #666666 } /* Literal.Number.Oct */
|
||
pre.pygments .tok-sa { color: #BA2121 } /* Literal.String.Affix */
|
||
pre.pygments .tok-sb { color: #BA2121 } /* Literal.String.Backtick */
|
||
pre.pygments .tok-sc { color: #BA2121 } /* Literal.String.Char */
|
||
pre.pygments .tok-dl { color: #BA2121 } /* Literal.String.Delimiter */
|
||
pre.pygments .tok-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
|
||
pre.pygments .tok-s2 { color: #BA2121 } /* Literal.String.Double */
|
||
pre.pygments .tok-se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
|
||
pre.pygments .tok-sh { color: #BA2121 } /* Literal.String.Heredoc */
|
||
pre.pygments .tok-si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
|
||
pre.pygments .tok-sx { color: #008000 } /* Literal.String.Other */
|
||
pre.pygments .tok-sr { color: #A45A77 } /* Literal.String.Regex */
|
||
pre.pygments .tok-s1 { color: #BA2121 } /* Literal.String.Single */
|
||
pre.pygments .tok-ss { color: #19177C } /* Literal.String.Symbol */
|
||
pre.pygments .tok-bp { color: #008000 } /* Name.Builtin.Pseudo */
|
||
pre.pygments .tok-fm { color: #0000FF } /* Name.Function.Magic */
|
||
pre.pygments .tok-vc { color: #19177C } /* Name.Variable.Class */
|
||
pre.pygments .tok-vg { color: #19177C } /* Name.Variable.Global */
|
||
pre.pygments .tok-vi { color: #19177C } /* Name.Variable.Instance */
|
||
pre.pygments .tok-vm { color: #19177C } /* Name.Variable.Magic */
|
||
pre.pygments .tok-il { color: #666666 } /* Literal.Number.Integer.Long */
|
||
</style>
|
||
</head>
|
||
<body class="book toc2 toc-left">
|
||
<div id="header">
|
||
<h1>Wombat’s Book of Nix</h1>
|
||
<div class="details">
|
||
<span id="author" class="author">Amy de Buitléir, 2023-11-18</span><br>
|
||
</div>
|
||
<div id="toc" class="toc2">
|
||
<div id="toctitle">Table of Contents</div>
|
||
<ul class="sectlevel1">
|
||
<li><a href="#_introduction">1. Introduction</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_why_nix">1.1. Why Nix?</a></li>
|
||
<li><a href="#_why_flakes">1.2. Why <em>flakes</em>?</a></li>
|
||
<li><a href="#_prerequisites">1.3. Prerequisites</a></li>
|
||
<li><a href="#_see_an_error_or_want_more">1.4. See an error? Or want more?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_hello_flake">2. Hello, flake!</a></li>
|
||
<li><a href="#_the_hello_flake_repo">3. The hello-flake repo</a></li>
|
||
<li><a href="#_flake_structure">4. Flake structure</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_description">4.1. Description</a></li>
|
||
<li><a href="#_inputs">4.2. Inputs</a></li>
|
||
<li><a href="#_outputs">4.3. Outputs</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_a_generic_flake">5. A generic flake</a></li>
|
||
<li><a href="#_another_look_at_hello_flake">6. Another look at hello-flake</a></li>
|
||
<li><a href="#_modifying_the_flake">7. Modifying the flake</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_the_nix_development_shell">7.1. The Nix development shell</a></li>
|
||
<li><a href="#_introducing_a_dependency">7.2. Introducing a dependency</a></li>
|
||
<li><a href="#_development_workflows">7.3. Development workflows</a></li>
|
||
<li><a href="#_this_all_seems_like_a_hassle">7.4. This all seems like a hassle!</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_a_new_flake_from_scratch">8. A new flake from scratch</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_haskell">8.1. Haskell</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_a_simple_haskell_program">8.1.1. A simple Haskell program</a></li>
|
||
<li><a href="#_optional_testing_before_packaging">8.1.2. (Optional) Testing before packaging</a>
|
||
<ul class="sectlevel4">
|
||
<li><a href="#_some_unsuitable_shells">Some unsuitable shells</a></li>
|
||
<li><a href="#_a_suitable_shell_for_a_quick_test">A suitable shell for a quick test</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_the_cabal_file">8.1.3. The cabal file</a></li>
|
||
<li><a href="#_optional_building_and_running_with_cabal_install">8.1.4. (Optional) Building and running with cabal-install</a></li>
|
||
<li><a href="#_the_nix_flake">8.1.5. The Nix flake</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_python">8.2. Python</a>
|
||
<ul class="sectlevel3">
|
||
<li><a href="#_a_simple_python_program">8.2.1. A simple Python program</a></li>
|
||
<li><a href="#_a_python_builder">8.2.2. A Python builder</a></li>
|
||
<li><a href="#_the_nix_flake_2">8.2.3. The Nix flake</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_nix_shell_recipes">9. nix-shell recipes</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_shell_with_access_to_a_package_from_the_nixpkgsnixos_repo">9.1. Shell with access to a package from the Nixpkgs/NixOS repo</a></li>
|
||
<li><a href="#_shell_with_access_to_a_package_defined_in_a_remote_git_repo">9.2. Shell with access to a package defined in a remote git repo</a></li>
|
||
<li><a href="#_shell_with_access_to_a_specific_revision_of_a_flake">9.3. Shell with access to a specific revision of a flake</a></li>
|
||
<li><a href="#_shell_with_access_to_a_haskell_package_on_your_local_computer">9.4. Shell with access to a Haskell package on your local computer</a></li>
|
||
<li><a href="#_shell_with_access_to_a_haskell_package_on_your_local_computer_with_interdependencies">9.5. Shell with access to a Haskell package on your local computer, with interdependencies</a></li>
|
||
<li><a href="#_shell_with_runtime_access_to_a_haskell_library_on_your_local_computer_no_cabal_file_required">9.6. Shell with runtime access to a Haskell library on your local computer (no <code>.cabal</code> file required)</a></li>
|
||
<li><a href="#_shell_with_an_environment_variable_set">9.7. Shell with an environment variable set</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_nix_shell_shebangs">10. Nix-shell shebangs</a>
|
||
<ul class="sectlevel2">
|
||
<li><a href="#_a_bash_script_depending_on_a_package_in_the_nixpkgs_repo">10.1. A Bash script depending on a package in the nixpkgs repo.</a></li>
|
||
<li><a href="#_a_haskell_script_depending_on_a_haskell_library_package_in_the_nixpkgs_repo">10.2. A Haskell script depending on a Haskell library package in the nixpkgs repo.</a></li>
|
||
<li><a href="#_a_python_script_depending_on_a_package_in_the_nixpkgs_repo">10.3. A Python script depending on a package in the nixpkgs repo.</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div id="content">
|
||
<div id="preamble">
|
||
<div class="sectionbody">
|
||
<div class="imageblock">
|
||
<div class="content">
|
||
<img src="images/wombat.svg" alt="wombat reclining against a lambda">
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This book is available
|
||
<a href="https://mhwombat.codeberg.page/nix-book/">online</a>
|
||
and as a downloadable
|
||
<a href="https://codeberg.org/mhwombat/nix-book/raw/branch/pages/wombats-book-of-nix.pdf">PDF</a>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_introduction">1. Introduction</h2>
|
||
<div class="sectionbody">
|
||
<div class="sect2">
|
||
<h3 id="_why_nix">1.1. Why Nix?</h3>
|
||
<div class="paragraph">
|
||
<p>If you’ve opened this PDF, you already have your own motivation for
|
||
learning Nix. Here’s how it helps me. As a researcher, I tend to work on
|
||
a series of short-term projects, mostly demos and prototypes. For each
|
||
one, I typically develop some software using a compiler, often with some
|
||
open source libraries. Often I use other tools to analyse data or
|
||
generate documentation, for example.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Problems would arise when handing off the project to colleagues; they
|
||
would report errors when trying to build or run the project. Belatedly I
|
||
would realise that my code relies on a library that they need to
|
||
install. Or perhaps they had installed the library, but the version
|
||
they’re using is incompatible.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Using containers helped with the problem. However, I didn’t want to
|
||
<em>develop</em> in a container. I did all my development in my nice, familiar,
|
||
environment with my custom aliases and shell prompt. and <em>then</em> I
|
||
containerised the software. This added step was annoying for me, and if
|
||
my colleague wanted to do some additional development, they would
|
||
probably extract all of the source code from the container first anyway.
|
||
Containers are great, but this isn’t the ideal use case for them.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Nix allows me to work in my custom environment, but forces me to specify
|
||
any dependencies. It automatically tracks the version of each dependency
|
||
so that it can replicate the environment wherever and whenever it’s
|
||
needed.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_why_flakes">1.2. Why <em>flakes</em>?</h3>
|
||
<div class="paragraph">
|
||
<p>Flakes are labeled as an experimental feature, so it might seem safer to
|
||
avoid them. However, they have been in use for years, and there is
|
||
widespread adoption, so the aren’t going away any time soon. Flakes are
|
||
easier to understand, and offer more features than the traditional Nix
|
||
approach. After weighing the pros and cons, I feel it’s better to learn
|
||
and use flakes; and this seems to be the general consensus.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_prerequisites">1.3. Prerequisites</h3>
|
||
<div class="paragraph">
|
||
<p>To follow along with the examples in this book, you will need access to a computer
|
||
or (virtual machine) with Nix (or NixOS) installed and <em>flakes enabled</em>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>I recommend the installer from
|
||
<a href="https://zero-to-nix.com/start/install">zero-to-nix.com</a>. This installer
|
||
automatically enables flakes.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>More documentation (and another installer) available at
|
||
<a href="https://nixos.org/">nixos.org</a>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To <em>enable flakes on an existing Nix or NixOS installation</em>,
|
||
see the instructions in the <a href="https://nixos.wiki/wiki/Flakes">NixOS wiki</a>.</p>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>There are hyphenated and unhyphenated versions of many Nix commands.
|
||
For example, <code>nix-shell</code> and <code>nix shell</code> are two different commands.
|
||
Don’t confuse them!</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Generally speaking, the unhyphenated versions are for working directly
|
||
with flakes, while the hyphenated versions are for everything else.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_see_an_error_or_want_more">1.4. See an error? Or want more?</h3>
|
||
<div class="paragraph">
|
||
<p>If notice an error, or you’re interested in an area that isn’t covered in this book, feel free to open an
|
||
<a href="https://codeberg.org/mhwombat/nix-book/issues">issue</a>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_hello_flake">2. Hello, flake!</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>Before learning to write Nix flakes, let’s learn how to use them. I’ve
|
||
created a simple example of a flake in this git
|
||
<a href="https://codeberg.org/mhwombat/hello-flake">repository</a>. To run this
|
||
flake, you don’t need to install anything; simply run the command below.
|
||
The first time you use a flake, Nix has to fetch and build it, which
|
||
may take time. Subsequent invocations should be instantaneous.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run "git+https://codeberg.org/mhwombat/hello-flake"
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>That’s a lot to type every time we want to use this package. Instead, we
|
||
can enter a shell with the package available to us, using the
|
||
<code>nix shell</code> command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix shell "git+https://codeberg.org/mhwombat/hello-flake"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In this shell, the command is on our <code>$PATH</code>, so we can execute the
|
||
command by name.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Nix didn’t <em>install</em> 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.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ which hello-flake
|
||
/nix/store/qskl8ajlgnl654fhgsmv74yv8x9r3kzg-hello-flake/bin/hello-flake</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Once we exit that shell, the <code>hello-flake</code> command is no longer
|
||
directly available.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ exit
|
||
$ hello-flake
|
||
sh: line 3: hello-flake: command not found</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">/nix/store/0xbn2hi6h1m5h4kc02vwffs2cydrbc0r-hello-flake/bin/hello-flake</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_the_hello_flake_repo">3. The hello-flake repo</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>Let’s clone the repository and see how the flake is defined.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ 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</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This is a simple repo with just a few files. Like most git repos, it
|
||
includes <code>LICENSE</code>, which contains the software license, and <code>README.md</code>
|
||
which provides information about the repo.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>hello-flake</code> 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.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello-flake</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#!/usr/bin/env sh</span>
|
||
|
||
<span class="tok-nb">echo</span><span class="tok-w"> </span><span class="tok-s2">"Hello from your flake!"</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now that we have a copy of the repo, we can execute this script
|
||
directly.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ ./hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s look at another file. The file that defines how to package a flake
|
||
is always called <code>flake.nix</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span>
|
||
<span class="normal">42</span>
|
||
<span class="normal">43</span>
|
||
<span class="normal">44</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-c1"># See https://github.com/mhwombat/nix-for-numbskulls/blob/main/flakes.md</span>
|
||
<span class="tok-c1"># for a brief overview of what each section in a flake should or can contain.</span>
|
||
|
||
<span class="tok-ss">description =</span> <span class="tok-s2">"a very simple and friendly flake"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">inputs =</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs =</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs =</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">packages =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello =</span> pkgs<span class="tok-o">.</span>stdenv<span class="tok-o">.</span>mkDerivation <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">name =</span> <span class="tok-s2">"hello-flake"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">src =</span> <span class="tok-o">.</span><span class="tok-l">/.</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">unpackPhase =</span> <span class="tok-s2">"true"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">buildPhase =</span> <span class="tok-s2">":"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">installPhase =</span>
|
||
<span class="tok-s1">''</span>
|
||
<span class="tok-s1"> mkdir -p $out/bin</span>
|
||
<span class="tok-s1"> cp $src/hello-flake $out/bin/hello-flake</span>
|
||
<span class="tok-s1"> chmod +x $out/bin/hello-flake</span>
|
||
<span class="tok-s1"> ''</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">default =</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">apps =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello =</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkApp <span class="tok-p">{</span> <span class="tok-ss">drv =</span> self<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-err">$</span><span class="tok-p">{</span>system<span class="tok-p">}</span><span class="tok-o">.</span>hello<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default =</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If this is your first time seeing a flake definition, it probably looks
|
||
intimidating. Flakes are written in a functional language called
|
||
Nix<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnotedef_1" title="View footnote.">1</a>]</sup>. 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.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-ss">inputs =</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>There are just two entries, one for <code>nixpkgs</code> and one for <code>flake-utils</code>.
|
||
The first one, <code>nixpkgs</code> refers to the collection of standard software
|
||
packages that can be installed with the Nix package manager. The second,
|
||
<code>flake-utils</code>, is a collection of utilities that simplify writing
|
||
flakes. The important thing to note is that the <code>hello-flake</code> package
|
||
<em>depends</em> on <code>nixpkgs</code> and <code>flake-utils</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Finally, let’s look at <code>flake.lock</code>, or rather, just part of it.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.lock</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="linenums"><span></span>{
|
||
"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"
|
||
}
|
||
. . .</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If <code>flake.nix</code> seemed 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 <em>uniquely</em> specifies all
|
||
flake dependencies, (e.g., version number, branch, revision, hash), so
|
||
that <em>anyone, anywhere, any time, can re-create the exact same
|
||
environment that the original developer used.</em></p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>No more complaints of “but it works on my machine!”. That is the
|
||
benefit of using flakes.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_flake_structure">4. Flake structure</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>The basic structure of a flake is shown below.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix">{
|
||
description = <em>package description</em>
|
||
inputs = <em>dependencies</em>
|
||
outputs = <em>what the flake produces</em>
|
||
nixConfig = <em>advanced configuration options</em>
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_description">4.1. Description</h3>
|
||
<div class="paragraph">
|
||
<p>The <code>description</code> part is self-explanatory; it’s just a string. You
|
||
probably won’t need <code>nixConfig</code> unless you’re doing something fancy. I’m
|
||
going to focus on what goes into the <code>inputs</code> and <code>outputs</code> sections,
|
||
and highlight some of the things I found confusing when I began using flakes.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_inputs">4.2. Inputs</h3>
|
||
<div class="paragraph">
|
||
<p>This section specifies the dependencies of a flake. It’s an <em>attribute
|
||
set</em>; it maps keys to values.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To ensure that a build is reproducible, the build step runs in a <em>pure</em>
|
||
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).</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Each entry in this section maps an input name to a <em>flake reference</em>.
|
||
This commonly takes the following form.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">NAME.url = URL-LIKE-EXPRESSION</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix">nixpkgs.url = "github:NixOS/nixpkgs/nixos-<em>version</em>";</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>where <em>version</em> is replaced with the version number that you used to build
|
||
the package, e.g. <code>22.11</code>. Information about the latest nixpkgs releases
|
||
is available at <a href="https://status.nixos.org/" class="bare">https://status.nixos.org/</a>. You can also write the entry
|
||
without the version number</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>nixpkgs<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:NixOS/nixpkgs/nixos"</span><span class="tok-p">;</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>or more simply,</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>nixpkgs<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"nixpkgs"</span><span class="tok-p">;</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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
|
||
(<code>flake.lock</code>) <em>uniquely</em> specifies all flake inputs.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Git and Mercurial repositories are the most common type of flake
|
||
reference, as in the examples below.</p>
|
||
</div>
|
||
<div class="dlist">
|
||
<dl>
|
||
<dt class="hdlist1">A Git repository</dt>
|
||
<dd>
|
||
<p><code>git+https://github.com/NixOS/patchelf</code></p>
|
||
</dd>
|
||
<dt class="hdlist1">A specific branch of a Git repository</dt>
|
||
<dd>
|
||
<p><code>git+https://github.com/NixOS/patchelf?ref=master</code></p>
|
||
</dd>
|
||
<dt class="hdlist1">A specific revision of a Git repository</dt>
|
||
<dd>
|
||
<p><br>
|
||
<code>git+https://github.com/NixOS/patchelf?ref=master&rev=f34751b88bd07d7f44f5cd3200fb4122bf916c7e</code></p>
|
||
</dd>
|
||
<dt class="hdlist1">A tarball</dt>
|
||
<dd>
|
||
<p><code><a href="https://github.com/NixOS/patchelf/archive/master.tar.gz" class="bare">https://github.com/NixOS/patchelf/archive/master.tar.gz</a></code></p>
|
||
</dd>
|
||
</dl>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You can find more examples of flake references in the
|
||
<a href="https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#examples">Nix
|
||
Reference Manual</a>.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>Although you probably won’t need to use it, there is another syntax for
|
||
flake references that you might encounter. This example</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>inputs<span class="tok-o">.</span><span class="tok-nb">import</span><span class="tok-ss">-cargo =</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">type =</span> <span class="tok-s2">"github"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">owner =</span> <span class="tok-s2">"edolstra"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">repo =</span> <span class="tok-s2">"import-cargo"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>is equivalent to</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span>inputs<span class="tok-o">.</span><span class="tok-nb">import</span><span class="tok-err">-</span>cargo<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:edolstra/import-cargo"</span><span class="tok-p">;</span></code></pre>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Each of the <code>inputs</code> is fetched, evaluated and passed to the <code>outputs</code>
|
||
function as a set of attributes with the same name as the corresponding
|
||
input.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_outputs">4.3. Outputs</h3>
|
||
<div class="paragraph">
|
||
<p>This section is a function that essentially returns the recipe for
|
||
building the flake.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We said above that <code>inputs</code> are passed to the <code>outputs</code>, so we need to
|
||
list them as parameters. This example references the <code>import-cargo</code>
|
||
dependency defined in the previous example.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix">outputs = { self, nixpkgs, import-cargo }: {
|
||
<mark><em>definitions for outputs</em></mark>
|
||
};</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_a_generic_flake">5. A generic flake</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>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.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code>{
|
||
description = "<mark><em>brief package description</em></mark>";
|
||
|
||
inputs = {
|
||
<span class="highlight01">nixpkgs</span>.url = "github:NixOS/nixpkgs";
|
||
<span class="highlight02">flake-utils</span>.url = "github:numtide/flake-utils";
|
||
<span class="highlight03">...<em>other dependencies</em>...</span> ❶
|
||
};
|
||
|
||
outputs = { self, <span class="highlight01">nixpkgs</span>, <span class="highlight02">flake-utils</span>, <span class="highlight03">...<em>other dependencies</em>...</span> ❷ }:
|
||
flake-utils.lib.eachDefaultSystem (system: ❸
|
||
let
|
||
pkgs = import nixpkgs { inherit system; };
|
||
python = pkgs.python3;
|
||
in
|
||
{
|
||
devShells = rec {
|
||
default = pkgs.mkShell {
|
||
packages = [ <mark><em>packages needed for development shell</em></mark>; ❹ ]))
|
||
];
|
||
};
|
||
|
||
packages = rec {
|
||
<span class="highlight04">myPackageName</span> = <mark><em>package definition</em></mark>; ❺
|
||
default = <span class="highlight04">myPackageName</span>;
|
||
};
|
||
|
||
apps = rec {
|
||
<span class="highlight04">myPackageName</span> = flake-utils.lib.mkApp { drv = self.packages.${system}.<span class="highlight04">myPackageName</span>; };
|
||
default = <span class="highlight04">myPackageName</span>;
|
||
};
|
||
}
|
||
);
|
||
}</code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We discussed how to specify flake inputs <code>❶</code> 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 <code>❷</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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
|
||
systems. Often the definitions are identical, apart from the name of the
|
||
system. The eachDefaultSystem function <code>❸</code> 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.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>devShells</code> 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 <code>❹</code> 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.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>packages</code> variable defines the packages that this flake provides.
|
||
The package definition <code>❺</code> 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.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>apps</code> variable identifies any applications provided by the flake.
|
||
In particular, it identifies the default executable ❻ that <code>nix run</code>
|
||
will run if you don’t specify an app.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Below is a list of some functions that are commonly used in
|
||
this section.</p>
|
||
</div>
|
||
<div class="dlist">
|
||
<dl>
|
||
<dt class="hdlist1">General-purpose</dt>
|
||
<dd>
|
||
<p>The standard environment provides <code>mkDerivation</code>, which is especially
|
||
useful for the typical <code>./configure; make; make install</code> scenario.
|
||
It’s customisable.</p>
|
||
</dd>
|
||
<dt class="hdlist1">Python</dt>
|
||
<dd>
|
||
<p><code>buildPythonApplication</code>, <code>buildPythonPackage</code>.</p>
|
||
</dd>
|
||
<dt class="hdlist1">Haskell</dt>
|
||
<dd>
|
||
<p><code>mkDerivation</code> (Haskell version, which is a wrapper around the
|
||
standard environment version), <code>developPackage</code>, <code>callCabal2Nix</code>.</p>
|
||
</dd>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_another_look_at_hello_flake">6. Another look at hello-flake</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>Now that we have a better understanding of the structure of <code>flake.nix</code>,
|
||
let’s have a look at the one we saw earlier, in the <code>hello-flake</code> repo.
|
||
If you compare this flake definition to the colour-coded template
|
||
presented in the previous section, most of it should look familiar.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="nowrap">{
|
||
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 =
|
||
. . .
|
||
<em>SOME UNFAMILIAR STUFF</em>
|
||
. . .
|
||
};
|
||
default = hello;
|
||
};
|
||
|
||
apps = rec {
|
||
hello = flake-utils.lib.mkApp { drv = self.packages.${system}.hello; };
|
||
default = hello;
|
||
};
|
||
}
|
||
);
|
||
}</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This <code>flake.nix</code> doesn’t have a <code>devShells</code> section, 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.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now let’s look at the section I labeled <code>SOME UNFAMILIAR STUFF</code> and
|
||
see what it does.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap"> 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 ❺
|
||
'';
|
||
};</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>This flake uses <code>mkDerivation</code> <code>❶</code> which is a very useful
|
||
general-purpose package builder provided by the Nix standard
|
||
environment. It’s especially useful for the typical
|
||
<code>./configure; make; make install</code> scenario, but for this flake we don’t
|
||
even need that.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>name</code> variable 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 <code>src</code> variable <code>❷</code> supplies the location of the source
|
||
files, relative to <code>flake.nix</code>. When a flake is accessed for the first
|
||
time, the repository contents are fetched in the form of a tarball. The
|
||
<code>unpackPhase</code> variable indicates that we do want the tarball to be
|
||
unpacked.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>buildPhase</code> variable 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
|
||
<code>buildPhase</code> consists of a single command, <code>:</code>,
|
||
which is a no-op or “do nothing” command.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>installPhase</code> variable is a sequence of Linux commands that will do
|
||
the actual installation. In this case, we create a directory <code>❸</code> for the
|
||
installation, copy the <code>hello-flake</code> script there <code>❹</code>, and make the
|
||
script executable <code>❺</code>. The environment variable <code>$src</code> refers to the
|
||
source directory, which we specified earlier <code>❷</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>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
|
||
<code>inputs</code> section of the flake.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>I’ve mentioned the Nix standard environment before, but I didn’t explain
|
||
what it is. The standard environment, or <code>stdenv</code>, 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<sup class="footnote">[<a id="_footnoteref_2" class="footnote" href="#_footnotedef_2" title="View footnote.">2</a>]</sup>.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p>The GNU C Compiler, configured with C and C++ support.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU coreutils (contains a few dozen standard Unix commands).</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU findutils (contains find).</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU diffutils (contains diff, cmp).</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU sed.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU grep.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU awk.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU tar.</p>
|
||
</li>
|
||
<li>
|
||
<p>gzip, bzip2 and xz.</p>
|
||
</li>
|
||
<li>
|
||
<p>GNU Make.</p>
|
||
</li>
|
||
<li>
|
||
<p>Bash.</p>
|
||
</li>
|
||
<li>
|
||
<p>The patch command.</p>
|
||
</li>
|
||
<li>
|
||
<p>On Linux, stdenv also includes the patchelf utility.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Only a few environment variables are available. The most interesting
|
||
ones are listed below.</p>
|
||
</div>
|
||
<div class="ulist">
|
||
<ul>
|
||
<li>
|
||
<p><code>$name</code> is the package name.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$src</code> refers to the source directory.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$out</code> is the path to the location in the Nix store where the package
|
||
will be added.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$system</code> is the system that the package is being built for.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$PWD</code> and <code>$TMP</code> both point to a temporary build directories</p>
|
||
</li>
|
||
<li>
|
||
<p><code>$HOME</code> and <code>$PATH</code> point to nonexistent directories, so the build
|
||
cannot rely on them.</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_modifying_the_flake">7. Modifying the flake</h2>
|
||
<div class="sectionbody">
|
||
<div class="sect2">
|
||
<h3 id="_the_nix_development_shell">7.1. The Nix development shell</h3>
|
||
<div class="paragraph">
|
||
<p>Let’s make a simple modification to the script. This will give you an
|
||
opportunity to check your understanding of flakes.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The first step is to enter a development shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix develop
|
||
copying path '/nix/store/wv33zvn4m0j6qlipy5ybfrixgipnfnyj-xgcc-12.2.0-libgcc' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/5w5qpm9z3iyib615pdih6nvk9spv3jbv-gcc-12.2.0-libgcc' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/jrid72i6ii9wx2ia6fyr2b1plri2m07l-libunistring-1.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/9j1pfpw69j4lqh24gvwksfqnbs1q70ww-linux-headers-6.2' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/y382xj6bh8h4mmm22sw1a6q81rijrxl7-libidn2-2.3.4' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/1n2l5law9g3b77hcfyp50vrhhssbrj5g-glibc-2.37-8' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/qgjrd7fj77877x1w3qg0d619cqqd8wm8-attr-2.5.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/xl922qxqxr5f2wa4vgfmai2pd9sman12-expand-response-params' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/ap4yi3pmi4vfblpijzgxssl96cy0icyp-gmp-6.2.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/nja07wpjdb6lyghi4izc30psw7j2kwxd-pcre-8.45' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/5533i5qzsxysjf38p1nlza9g9wvh09wk-xz-5.4.2' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/zlf0f88vj30sc7567b80l52d19pbdmy2-bash-5.2-p15' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/hyh6hg6rzm77rs4nix61nfwnxx2aqn40-ed-1.19' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/93z4n7zy5hwpn06279jlmak75jmq1db1-gnused-4.9' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/by4gv37sharnf370ki60zam5s7qklqqh-bzip2-1.0.8' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/vg9f8pmd2g0x3gb53nxwkw3yxizl3jpk-gnumake-4.4.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/4rwqxm67y0zkbxjg14zl9fdxf30cpgvy-gawk-5.2.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/g012c53brxmb0if3lpmkjwmxk74hjflh-gcc-12.2.0-lib' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/v1nar35045dqwf8yy572yvbbcg2w2678-glibc-2.37-8-bin' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/2ldgh1qis9p4zf8bgsdm7897gw8vv36g-zlib-1.2.13' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/gz0kx5v2asvlbf7gzr4v24h7dpza70zf-bzip2-1.0.8-bin' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/c01b2gmx1fjjkpnvj6bxy9q49g8qkpka-gnugrep-3.7' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/swf1dckghdx7nza1lxz6s462pafwd7wa-patch-2.7.6' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/ddygk5wqzmz69yqirrpcby2a28fam4g1-acl-2.3.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/z5818pmhspx5772s4cp6ckhwhbin2f09-xz-5.4.2-bin' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/anzfrab5qhaz3xw53v6a934s8ypgfhix-binutils-2.40-lib' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/0xpv4lac3ybc6hm9gg7ywkdazs4vsj8l-file-5.44' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/wb2dlc8kpvrn960vq7j7c8822pi43n48-glibc-2.37-8-dev' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/2nprqmdmjmy5i2sii7j21fznmkwimqcr-gzip-1.12' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/clbzka4dzv2wym7971qsbbgx77g3p258-isl-0.20' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/r0zb1rcf1q2lmyqvg5d0vwy1f57zk05h-mpfr-4.2.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/lcfhnr6wrj9ssd3dxs39sprvz6qrxlj5-gnutar-1.34' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/f4qnwzv6y0nq8lix33jr5ykkyybs6fxf-binutils-2.40' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/kdgk1mgka2xd4rkmnfmcv3k2gm9jid6n-gmp-with-cxx-6.2.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/2y0q33dmn7846bpqcnfch4a0q2q6dmya-patchelf-0.15.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/5din34jk6dvk0wrlfw0hg1wzxxaaypyj-libmpc-1.3.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/arbxkmcgv9h8pjgj95c6d7r86yb77rl5-coreutils-9.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/aafdki1nf49k5vxq6gx2yabiybk2bjmw-gcc-12.2.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/q951w69v8kbdrw6shdpibnl594yfr0by-diffutils-3.9' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/j5wraaxv16fcl10x11566a3807nr4nlr-findutils-4.9.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/f83wjm5wpcxxbzwmr56q9iclsn0simph-binutils-wrapper-2.40' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/nlgyw2fv0cm8rkz8qm1jyw78vyif1bl9-gcc-wrapper-12.2.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/5s1yg5l36wzgy1dj0vv1ibarc4g7vrdr-stdenv-linux' from 'https://cache.nixos.org'...
|
||
building '/nix/store/llapcvnqicjlhmhll353498bdpcbxb2g-hello-flake-env.drv'...
|
||
these 4 paths will be fetched (1.80 MiB download, 11.01 MiB unpacked):
|
||
/nix/store/pk3kkaafln68gzxawk57qp9m5h5285va-bash-interactive-5.2-p15
|
||
/nix/store/33lnr4ji9f4d2cdigrwc1d4pbkjy4vq9-bash-interactive-5.2-p15-man
|
||
/nix/store/q5mhssfls6iych80439511vz7539gd95-ncurses-6.4
|
||
/nix/store/s8axd2sknp45d2jmxkasmq8zxd1mv068-readline-8.2p1
|
||
copying path '/nix/store/33lnr4ji9f4d2cdigrwc1d4pbkjy4vq9-bash-interactive-5.2-p15-man' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/q5mhssfls6iych80439511vz7539gd95-ncurses-6.4' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/s8axd2sknp45d2jmxkasmq8zxd1mv068-readline-8.2p1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/pk3kkaafln68gzxawk57qp9m5h5285va-bash-interactive-5.2-p15' from 'https://cache.nixos.org'...</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The <code>flake.nix</code> file specifies all of the tools that are needed during
|
||
development of the package. The <code>nix develop</code> command puts us in a shell
|
||
with those tools. As it turns out, we didn’t need any extra tools
|
||
(beyond the standard environment) for development yet, but that’s
|
||
usually not the case. Also, we will soon need another tool.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>A development environment only allows you to <em>develop</em> the package.
|
||
Don’t expect the package <em>outputs</em> (e.g. executables) to be available
|
||
until you build them. However, our script doesn’t need to be compiled,
|
||
so can’t we just run it?</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ hello-flake
|
||
bash: line 16: hello-flake: command not found</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>That worked before; why isn’t it working now? Earlier we used
|
||
<code>nix shell</code> to enter a <em>runtime</em> environment where <code>hello-flake</code> was
|
||
available and on the <code>$PATH</code>. This time we entered a <em>development</em>
|
||
environment using the <code>nix develop</code> command. Since the flake hasn’t been
|
||
built yet, the executable won’t be on the <code>$PATH</code>. We can, however, run
|
||
it by specifying the path to the script.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ ./hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We can also build the flake using the <code>nix build</code> command, which places
|
||
the build outputs in a directory called <code>result</code>.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix build
|
||
this derivation will be built:
|
||
/nix/store/zncdnvnjwvz4dd2zfgcjizxlm5gvdf0x-hello-flake.drv
|
||
building '/nix/store/zncdnvnjwvz4dd2zfgcjizxlm5gvdf0x-hello-flake.drv'...
|
||
$ result/bin/hello-flake
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Rather than typing the full path to the executable, it’s more convenient
|
||
to use <code>nix run</code>.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
Hello from your flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a summary of the more common Nix commands.</p>
|
||
</div>
|
||
<table class="tableblock frame-all grid-all stretch">
|
||
<colgroup>
|
||
<col style="width: 17%;">
|
||
<col style="width: 83%;">
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th class="tableblock halign-left valign-top">command</th>
|
||
<th class="tableblock halign-left valign-top">Action</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix develop</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Enters a <em>development</em> shell with all the required
|
||
development tools (e.g. compilers and linkers) available (as specified
|
||
by <code>flake.nix</code>).</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix shell</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Enters a <em>runtime</em> shell where the flake’s executables are
|
||
available on the <code>$PATH</code>.</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix build</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Builds the flake and puts the output in a directory called
|
||
<code>result</code>.</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix run</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Runs the flake’s default executable, rebuilding the package
|
||
first if needed. Specifically, it runs the version in the Nix store, not
|
||
the version in <code>result</code>.</p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_introducing_a_dependency">7.2. Introducing a dependency</h3>
|
||
<div class="paragraph">
|
||
<p>Now we’re ready to make the flake a little more interesting.
|
||
Instead of using the <code>echo</code> command in the script, we can use the Linux <code>cowsay</code>
|
||
command.
|
||
Here’s the <code>hello-flake</code> file, with the modified line highlighted.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello-flake</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-c1">#!/usr/bin/env sh</span>
|
||
|
||
cowsay <span class="tok-s2">"Hello from your flake!"</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s test the modified script.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ ./hello-flake
|
||
./hello-flake: line 3: cowsay: command not found</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>What went wrong? Remember that we are in a <em>development</em> shell. Since
|
||
<code>flake.nix</code> didn’t define the <code>devShells</code> variable, the development
|
||
shell only includes the Nix standard environment. In particular, the
|
||
<code>cowsay</code> command is not available.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>To fix the problem, we can modify <code>flake.nix</code>.
|
||
We don’t need to add <code>cowsay</code> to the <code>inputs</code> section because it’s included in <code>nixpkgs</code>,
|
||
which is already an input.
|
||
However, we also want it to be available in a develoment shell.
|
||
The highlighted modifications below will accomplish that.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><span></span><span class="tok-p">{</span>
|
||
<span class="tok-c1"># See https://github.com/mhwombat/nix-for-numbskulls/blob/main/flakes.md</span>
|
||
<span class="tok-c1"># for a brief overview of what each section in a flake should or can contain.</span>
|
||
|
||
<span class="tok-ss">description =</span> <span class="tok-s2">"a very simple and friendly flake"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">inputs =</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs =</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs =</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="hll"> <span class="tok-ss">devShells =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
</span><span class="hll"> <span class="tok-ss">default =</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
</span><span class="hll"> <span class="tok-ss">packages =</span> <span class="tok-p">[</span> pkgs<span class="tok-o">.</span>cowsay <span class="tok-p">];</span>
|
||
</span><span class="hll"> <span class="tok-p">};</span>
|
||
</span><span class="hll"> <span class="tok-p">};</span>
|
||
</span>
|
||
<span class="tok-ss">packages =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello =</span> pkgs<span class="tok-o">.</span>stdenv<span class="tok-o">.</span>mkDerivation <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">name =</span> <span class="tok-s2">"hello-flake"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">src =</span> <span class="tok-o">.</span><span class="tok-l">/.</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">unpackPhase =</span> <span class="tok-s2">"true"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">buildPhase =</span> <span class="tok-s2">":"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">installPhase =</span>
|
||
<span class="tok-s1">''</span>
|
||
<span class="tok-s1"> mkdir -p $out/bin</span>
|
||
<span class="tok-s1"> cp $src/hello-flake $out/bin/hello-flake</span>
|
||
<span class="tok-s1"> chmod +x $out/bin/hello-flake</span>
|
||
<span class="tok-s1"> ''</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">default =</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">apps =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello =</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkApp <span class="tok-p">{</span> <span class="tok-ss">drv =</span> self<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-err">$</span><span class="tok-p">{</span>system<span class="tok-p">}</span><span class="tok-o">.</span>hello<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default =</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now we restart the development shell and see that the <code>cowsay</code> command is
|
||
available and the script works. Because we’ve updated source files
|
||
but haven’t <code>git commit</code>ed the new version, we get a warning message
|
||
about it being “dirty”. It’s just a warning, though; the script runs
|
||
correctly.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix develop
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/modify-hello-flake/hello-flake' is dirty
|
||
copying path '/nix/store/wy0incigsdz3nai26lxmn9ibchnb0qd6-libxcrypt-4.4.33' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/m6kc0wg6zii4bcw0fqxmclgy27ph09va-perl-5.36.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/gfi27h4y5n4aralcxrc0377p8mjb1cvb-cowsay-3.7.0' from 'https://cache.nixos.org'...
|
||
building '/nix/store/r6q8nnmkq8jf94w1xwv0d3fjig2ghs7m-nix-shell-env.drv'...
|
||
$ which cowsay # is it available now?
|
||
/nix/store/gfi27h4y5n4aralcxrc0377p8mjb1cvb-cowsay-3.7.0/bin/cowsay
|
||
$ ./hello-flake
|
||
________________________
|
||
< Hello from your flake! >
|
||
------------------------
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Alternatively, we could use <code>nix run</code>.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/modify-hello-flake/hello-flake' is dirty
|
||
this derivation will be built:
|
||
/nix/store/7p6j8as345vfsjg8hcb61m6c2a7bxi2v-hello-flake.drv
|
||
building '/nix/store/7p6j8as345vfsjg8hcb61m6c2a7bxi2v-hello-flake.drv'...
|
||
________________________
|
||
< Hello from your flake! >
|
||
------------------------
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note, however, that <code>nix run</code> rebuilt the package in the Nix store and
|
||
ran <em>that</em>. It did not alter the copy in the <code>result</code> directory, as
|
||
we’ll see next.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cat result/bin/hello-flake
|
||
#!/nix/store/zlf0f88vj30sc7567b80l52d19pbdmy2-bash-5.2-p15/bin/sh
|
||
|
||
echo "Hello from your flake!"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If we want to update the version in <code>result</code>, we need <code>nix build</code> again.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix build
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/modify-hello-flake/hello-flake' is dirty
|
||
$ cat result/bin/hello-flake
|
||
#!/nix/store/zlf0f88vj30sc7567b80l52d19pbdmy2-bash-5.2-p15/bin/sh
|
||
|
||
cowsay "Hello from your flake!"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s <code>git commit</code> the changes and verify that the warning goes away. We
|
||
don’t need to <code>git push</code> the changes until we’re ready to share them.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git commit hello-flake flake.nix -m 'added bovine feature'
|
||
[main f7b93da] added bovine feature
|
||
2 files changed, 7 insertions(+), 1 deletion(-)
|
||
$ nix run
|
||
________________________
|
||
< Hello from your flake! >
|
||
------------------------
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_development_workflows">7.3. Development workflows</h3>
|
||
<div class="paragraph">
|
||
<p>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
|
||
as two different development workflows.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>My usual, <em>high-level workflow</em> is quite simple.</p>
|
||
</div>
|
||
<div class="olist arabic">
|
||
<ol class="arabic">
|
||
<li>
|
||
<p><code>nix run</code> to re-build (if necessary) and run the executable.</p>
|
||
</li>
|
||
<li>
|
||
<p>Fix any problems in <code>flake.nix</code> or the source code.</p>
|
||
</li>
|
||
<li>
|
||
<p>Repeat until the package works properly.</p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>In the high-level workflow, I don’t use a development shell because I
|
||
don’t need to directly invoke development tools such as compilers and
|
||
linkers. Nix invokes them for me according to the output definition in
|
||
<code>flake.nix</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Occasionally I want to work at a lower level, and invoke compiler,
|
||
linkers, etc. directly. Perhaps want to work on one component without
|
||
rebuilding the entire package. Or perhaps I’m confused by some error
|
||
message, so I want to temporarily bypass Nix and work directly with
|
||
the compiler. In this case I temporarily switch to a <em>low-level
|
||
workflow</em>.</p>
|
||
</div>
|
||
<div class="olist arabic">
|
||
<ol class="arabic">
|
||
<li>
|
||
<p><code>nix develop</code> to enter a development shell with any development tools
|
||
I need (e.g. compilers, linkers, documentation generators).</p>
|
||
</li>
|
||
<li>
|
||
<p>Directly invoke tools such as compilers.</p>
|
||
</li>
|
||
<li>
|
||
<p>Fix any problems in <code>flake.nix</code> or the source code.</p>
|
||
</li>
|
||
<li>
|
||
<p>Directly invoke the executable. Note that the location of the
|
||
executable depends on the development tools – It probably isn’t
|
||
<code>result</code>!</p>
|
||
</li>
|
||
<li>
|
||
<p>Repeat until the package works properly.</p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>I generally only use <code>nix build</code> if I just want to build the package but
|
||
not execute anything (perhaps it’s just a library).</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_this_all_seems_like_a_hassle">7.4. This all seems like a hassle!</h3>
|
||
<div class="paragraph">
|
||
<p>It is a bit annoying to modify <code>flake.nix</code> and ether rebuild or reload
|
||
the development environment every time you need another tool. However,
|
||
this Nix way of doing things ensures that all of your dependencies, down
|
||
to the exact versions, are captured in <code>flake.lock</code>, and that anyone
|
||
else will be able to reproduce the development environment.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_a_new_flake_from_scratch">8. A new flake from scratch</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>At last we are ready to create a flake from scratch!
|
||
The sections in this chapter are very similar;
|
||
read the one for your language of choice.
|
||
If you’re interested in a language that I haven’t covered, feel free to suggest it by creating an
|
||
<a href="https://codeberg.org/mhwombat/nix-book/issues">issue</a>.</p>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_haskell">8.1. Haskell</h3>
|
||
<div class="paragraph">
|
||
<p>Start with an empty directory and create a git repository.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ mkdir hello-haskell
|
||
$ cd hello-haskell
|
||
$ git init
|
||
Initialized empty Git repository in /home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell/.git/</pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_a_simple_haskell_program">8.1.1. A simple Haskell program</h4>
|
||
<div class="paragraph">
|
||
<p>Next, we’ll create a simple Haskell program.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Main.hs</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="haskell"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span>
|
||
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-kr">import</span><span class="tok-w"> </span><span class="tok-nn">Network.HostName</span>
|
||
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">IO</span><span class="tok-w"> </span><span class="tok-nb">()</span>
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-kr">do</span>
|
||
<span class="tok-w"> </span><span class="tok-n">putStrLn</span><span class="tok-w"> </span><span class="tok-s">"Hello from Haskell inside a Nix flake!"</span>
|
||
<span class="tok-w"> </span><span class="tok-n">h</span><span class="tok-w"> </span><span class="tok-ow"><-</span><span class="tok-w"> </span><span class="tok-n">getHostName</span>
|
||
<span class="tok-w"> </span><span class="tok-n">putStrLn</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-s">"Your hostname is: "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">h</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_optional_testing_before_packaging">8.1.2. (Optional) Testing before packaging</h4>
|
||
<div class="paragraph">
|
||
<p>Before we package the program, let’s verify that it runs. We’re going to
|
||
need a Haskell compiler. By now you’ve probably figured out that we can write a
|
||
<code>flake.nix</code> and define a development shell that includes Haskell. We’ll
|
||
do that shortly, but first I want to show you a handy shortcut. We can
|
||
lauch a <em>temporary</em> shell with any Nix packages we want. This is
|
||
convenient when you just want to try out some new software and you’re
|
||
not sure if you’ll use it again. It’s also convenient when you’re not
|
||
ready to write <code>flake.nix</code> (perhaps you’re not sure what tools and
|
||
packages you need), and you want to experiment a bit first.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The command to enter a temporary shell is</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>nix-shell -p <em>packages</em></code></p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If there are multiple packages, they should be separated by spaces.</p>
|
||
</div>
|
||
<div class="admonitionblock important">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-important" title="Important"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>The command used here is <code>nix-shell</code> with a hyphen, not <code>nix shell</code>
|
||
with a space; those are two different commands. In fact there are
|
||
hyphenated and non-hyphenated versions of many Nix commands, and yes,
|
||
it’s confusing. The non-hyphenated commands were introduced when support
|
||
for flakes was added to Nix. I predict that eventually all hyphenated
|
||
commands will be replaced with non-hyphenated versions. Until then, a
|
||
useful rule of thumb is that non-hyphenated commands are for for working
|
||
directly with flakes; hyphenated commands are for everything else.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_some_unsuitable_shells">Some unsuitable shells</h5>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>In this section, we will try commands that fail in subtle ways.
|
||
Examining these failures will give you a much better understanding of Haskell development with Nix,
|
||
and help you avoid (or at least diagnose) similar problems in future.
|
||
If you’re impatient, you can skip to the next section to see the right way to do it.
|
||
You can come back to this section later to learn more.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s enter a shell with the Glasgow Haskell Compiler ("ghc") and try to run the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell -p ghc
|
||
$ runghc Main.hs
|
||
|
||
Main.hs:1:1: error:
|
||
Could not find module ‘Network.HostName’
|
||
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
||
|
|
||
1 | import Network.HostName
|
||
| ^^^^^^^^^^^^^^^^^^^^^^^</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The error message tells us that we need the module <code>Network.HostName</code>.
|
||
That module is provided by the Haskell package called <code>hostname</code>.
|
||
Let’s exit that shell and try again, this time adding the <code>hostname</code> package.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ exit
|
||
$ nix-shell -p "[ghc hostname]"
|
||
$ runghc Main.hs
|
||
|
||
Main.hs:1:1: error:
|
||
Could not find module ‘Network.HostName’
|
||
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
||
|
|
||
1 | import Network.HostName
|
||
| ^^^^^^^^^^^^^^^^^^^^^^^</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>That reason that failed is that we asked for the wrong package.
|
||
The Nix package <code>hostname</code> isn’t the Haskell package we wanted,
|
||
it’s a different package entirely (an alias for <code>hostname-net-tools</code>.)
|
||
The package we want is in the <em>package set</em> called <code>haskellPackages</code>, so we can refer to it as <code>haskellPackages.hostname</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s try that again, with the correct package.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ exit
|
||
$ nix-shell -p "[ghc haskellPackages.hostname]"
|
||
$ runghc Main.hs
|
||
|
||
Main.hs:1:1: error:
|
||
Could not find module ‘Network.HostName’
|
||
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
||
|
|
||
1 | import Network.HostName
|
||
| ^^^^^^^^^^^^^^^^^^^^^^^</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Now what’s wrong?
|
||
The syntax we used in the <code>nix-shell</code> command above is fine, but it doesn’t make the package <em>available to GHC</em>!</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect4">
|
||
<h5 id="_a_suitable_shell_for_a_quick_test">A suitable shell for a quick test</h5>
|
||
<div class="paragraph">
|
||
<p>Consider the Haskell "pandoc" package, which provides both an executable (the Nix package <code>pandoc</code>)
|
||
and a library (the Nix package <code>haskellPackages.pandoc</code>).
|
||
There are several different shells we could create involving both Pandoc and GHC,
|
||
and it’s important to understand the differences between them.</p>
|
||
</div>
|
||
<table class="tableblock frame-all grid-all stretch">
|
||
<colgroup>
|
||
<col style="width: 50%;">
|
||
<col style="width: 50%;">
|
||
</colgroup>
|
||
<tbody>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix-shell -p "[ghc pandoc]"</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Makes the Pandoc <em>executable</em> available at the command line, but the <em>library</em> won’t be visible to GHC.</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ pandoc ])"</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Makes the Pandoc <em>library</em> visible to GHC, but we won’t be able to run the <em>executable</em>.</p></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>nix-shell -p "[pandoc (haskellPackages.ghcWithPackages (pkgs: with pkgs; [ pandoc ]))]"</code></p></td>
|
||
<td class="tableblock halign-left valign-top"><p class="tableblock">Makes the Pandoc <em>executable</em> available at the command line, and the <em>library</em> visible to GHC.</p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="paragraph">
|
||
<p>Now we can create a shell that can run the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ hostname ])"
|
||
$ runghc Main.hs
|
||
Hello from Haskell inside a Nix flake!
|
||
Your hostname is: wombat11k</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Success! Now we know the program works.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_the_cabal_file">8.1.3. The cabal file</h4>
|
||
<div class="paragraph">
|
||
<p>It’s time to write a Cabal file for this program.
|
||
This is just an ordinary Cabal file; we don’t need to do anything special for Nix.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello-flake-haskell.cabal</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="cabal"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span></pre></div></td><td class="code"><div><pre><span></span>cabal-version: 3.0
|
||
name: hello-flake-haskell
|
||
version: 1.0.0
|
||
synopsis: A simple demonstration using a Nix flake to package a Haskell program that prints a greeting.
|
||
description:
|
||
For more information and a tutorial on how to use this package,
|
||
please see the README at <https://codeberg.org/mhwombat/hello-flake-haskell#readme>.
|
||
homepage: https://codeberg.org/mhwombat/hello-flake-haskell
|
||
bug-reports: https://codeberg.org/mhwombat/hello-flake-haskell/issues
|
||
license: GPL-3.0-only
|
||
license-file: LICENSE
|
||
author: Amy de Buitléir
|
||
maintainer: amy@nualeargais.ie
|
||
copyright: (c) 2023 Amy de Buitléir
|
||
category: Text
|
||
build-type: Simple
|
||
|
||
executable hello-flake-haskell
|
||
main-is: Main.hs
|
||
build-depends:
|
||
base,
|
||
hostname
|
||
-- NOTE: Best practice is to specify version constraints for the packages we depend on.
|
||
-- However, I'm confident that this package will only be used as a Nix flake.
|
||
-- Nix will automatically ensure that anyone running this program is using the
|
||
-- same library versions that I used to build it.
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_optional_building_and_running_with_cabal_install">8.1.4. (Optional) Building and running with cabal-install</h4>
|
||
<div class="paragraph">
|
||
<p>At this point, I would normally write <code>flake.nix</code> and use Nix to build the program.
|
||
I’ll cover that in the next section.
|
||
However, it’s useful to know how to build the package manually in a Nix envronment,
|
||
without using a Nix flake.
|
||
When you’re new to Nix, this can help you differentiate between problems in your flake definition
|
||
and problems in your Cabal file.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cabal build
|
||
sh: line 35: cabal: command not found</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Aha! We need <code>cabal-install</code> in our shell.
|
||
Rather than launch another shell-within-a-shell, let’s exit create a new one.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ exit
|
||
$ nix-shell -p "[ cabal-install (haskellPackages.ghcWithPackages (pkgs: with pkgs; [ hostname ]))]"
|
||
$ cabal build
|
||
Resolving dependencies...
|
||
Build profile: -w ghc-9.4.7 -O1
|
||
In order, the following will be built (use -v for more details):
|
||
- hello-flake-haskell-1.0.0 (exe:hello-flake-haskell) (first run)
|
||
Configuring executable 'hello-flake-haskell' for hello-flake-haskell-1.0.0..
|
||
Warning: Packages using 'cabal-version: >= 1.10' and before 'cabal-version:
|
||
3.4' must specify the 'default-language' field for each component (e.g.
|
||
Haskell98 or Haskell2010). If a component uses different languages in
|
||
different modules then list the other ones in the 'other-languages' field.
|
||
Warning: The 'license-file' field refers to the file 'LICENSE' which does not
|
||
exist.
|
||
Preprocessing executable 'hello-flake-haskell' for hello-flake-haskell-1.0.0..
|
||
Building executable 'hello-flake-haskell' for hello-flake-haskell-1.0.0..
|
||
[1 of 1] Compiling Main ( Main.hs, /home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell/dist-newstyle/build/x86_64-linux/ghc-9.4.7/hello-flake-haskell-1.0.0/x/hello-flake-haskell/build/hello-flake-haskell/hello-flake-haskell-tmp/Main.o )
|
||
[2 of 2] Linking /home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell/dist-newstyle/build/x86_64-linux/ghc-9.4.7/hello-flake-haskell-1.0.0/x/hello-flake-haskell/build/hello-flake-haskell/hello-flake-haskell
|
||
$ cabal run
|
||
Hello from Haskell inside a Nix flake!
|
||
Your hostname is: wombat11k
|
||
$ exit</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>After a lot of output messages, the build succeeds and the program runs.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_the_nix_flake">8.1.5. The Nix flake</h4>
|
||
<div class="paragraph">
|
||
<p>Now we should write <code>flake.nix</code>. We already know how to write most of
|
||
the flake from the examples we did earlier. The two parts that would be
|
||
different are the development shell and the package builder.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>However, there’s a simpler way, using <code>haskell-flake</code>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-ss">description =</span> <span class="tok-s2">"a flake using Haskell"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-c1"># This example uses haskell-flake to make things simpler.</span>
|
||
<span class="tok-c1"># See https://haskell.flake.page/ for more information and examples.</span>
|
||
|
||
<span class="tok-ss">inputs =</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:nixos/nixpkgs/nixpkgs-unstable"</span><span class="tok-p">;</span>
|
||
flake-parts<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:hercules-ci/flake-parts"</span><span class="tok-p">;</span>
|
||
haskell-flake<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:srid/haskell-flake"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">outputs =</span> inputs<span class="tok-p">@{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-parts<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span>
|
||
flake-parts<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkFlake <span class="tok-p">{</span> <span class="tok-k">inherit</span> inputs<span class="tok-p">;</span> <span class="tok-p">}</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">systems =</span> nixpkgs<span class="tok-o">.</span>lib<span class="tok-o">.</span>systems<span class="tok-o">.</span>flakeExposed<span class="tok-p">;</span>
|
||
<span class="tok-ss">imports =</span> <span class="tok-p">[</span> inputs<span class="tok-o">.</span>haskell-flake<span class="tok-o">.</span>flakeModule <span class="tok-p">];</span>
|
||
|
||
<span class="tok-ss">perSystem =</span> <span class="tok-p">{</span> self'<span class="tok-p">,</span> pkgs<span class="tok-p">,</span> <span class="tok-o">...</span> <span class="tok-p">}:</span> <span class="tok-p">{</span>
|
||
haskellProjects<span class="tok-o">.</span><span class="tok-ss">default =</span> <span class="tok-p">{};</span>
|
||
|
||
<span class="tok-c1"># haskell-flake doesn't set the default package, but you can do it here.</span>
|
||
packages<span class="tok-o">.</span><span class="tok-ss">default =</span> self'<span class="tok-o">.</span>packages<span class="tok-o">.</span>hello-flake-haskell<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The above definition will work for most of your haskell projects;
|
||
simply change the <code>description</code> and the package name in <code>packages.default</code>.
|
||
Let’s try out the new flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell' is dirty
|
||
error: getting status of '/nix/store/0ccnxa25whszw7mgbgyzdm4nqc0zwnm8-source/flake.nix': No such file or directory</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Why can’t it find <code>flake.nix</code>? Nix flakes only “see” files that are
|
||
part of the repository. We need to add all of the important files to the
|
||
repo before building or running the flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.nix hello-flake-haskell.cabal Main.hs
|
||
$ nix run
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell' is dirty
|
||
warning: creating lock file '/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell/flake.lock'
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/haskell-flake/hello-haskell' is dirty
|
||
these 2 derivations will be built:
|
||
/nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv
|
||
/nix/store/czq5qmg6mxlzyy7zwxq84c3jg8njy6m9-hello-flake-haskell-1.0.0.drv
|
||
building '/nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv'...
|
||
error: builder for '/nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv' failed with exit code 1;
|
||
last 7 log lines:
|
||
> unpacking source archive /nix/store/hhgjzgy9ly522nl99y8h6m4kl6cknfin-source-hello-flake-haskell
|
||
> source root is source-hello-flake-haskell
|
||
> Config file path source is default config file.
|
||
> Config file not found: /build/source-hello-flake-haskell/.config/cabal/config
|
||
> Writing default configuration to
|
||
> /build/source-hello-flake-haskell/.config/cabal/config
|
||
> /build/source-hello-flake-haskell/./LICENSE: withBinaryFile: does not exist (No such file or directory)
|
||
For full logs, run 'nix log /nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv'.
|
||
error: 1 dependencies of derivation '/nix/store/czq5qmg6mxlzyy7zwxq84c3jg8njy6m9-hello-flake-haskell-1.0.0.drv' failed to build</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We’d like to share this package with others, but first we should do some
|
||
cleanup. When the package was built (automatically by the <code>nix run</code>
|
||
command), it created a <code>flake.lock</code> file. We need to add this to the
|
||
repo, and commit all important files.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.lock
|
||
$ git commit -a -m 'initial commit'
|
||
[master (root-commit) 639cbc4] initial commit
|
||
4 files changed, 137 insertions(+)
|
||
create mode 100644 Main.hs
|
||
create mode 100644 flake.lock
|
||
create mode 100644 flake.nix
|
||
create mode 100644 hello-flake-haskell.cabal</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You can test that your package is properly configured by going to
|
||
another directory and running it from there.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cd ..
|
||
$ nix run ./hello-haskell
|
||
these 2 derivations will be built:
|
||
/nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv
|
||
/nix/store/czq5qmg6mxlzyy7zwxq84c3jg8njy6m9-hello-flake-haskell-1.0.0.drv
|
||
building '/nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv'...
|
||
error: builder for '/nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv' failed with exit code 1;
|
||
last 7 log lines:
|
||
> unpacking source archive /nix/store/hhgjzgy9ly522nl99y8h6m4kl6cknfin-source-hello-flake-haskell
|
||
> source root is source-hello-flake-haskell
|
||
> Config file path source is default config file.
|
||
> Config file not found: /build/source-hello-flake-haskell/.config/cabal/config
|
||
> Writing default configuration to
|
||
> /build/source-hello-flake-haskell/.config/cabal/config
|
||
> /build/source-hello-flake-haskell/./LICENSE: withBinaryFile: does not exist (No such file or directory)
|
||
For full logs, run 'nix log /nix/store/69ndw9rm52qas5wdmi60dhiavcv8xk0l-source-hello-flake-haskell-sdist.tar.gz.drv'.
|
||
error: 1 dependencies of derivation '/nix/store/czq5qmg6mxlzyy7zwxq84c3jg8njy6m9-hello-flake-haskell-1.0.0.drv' failed to build</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If you move the project to a public repo, anyone can run it. Recall from
|
||
the beginning of the tutorial that you were able to run <code>hello-flake</code>
|
||
directly from my repo with the following command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">nix run "git+https://codeberg.org/mhwombat/hello-flake"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Modify the URL accordingly and invite someone else to run your new
|
||
Haskell flake.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_python">8.2. Python</h3>
|
||
<div class="paragraph">
|
||
<p>Start with an empty directory and create a git repository.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ mkdir hello-python
|
||
$ cd hello-python
|
||
$ git init
|
||
Initialized empty Git repository in /home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python/.git/</pre>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_a_simple_python_program">8.2.1. A simple Python program</h4>
|
||
<div class="paragraph">
|
||
<p>Next, we’ll create a simple Python program.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">hello.py</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="python"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span>
|
||
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#!/usr/bin/env python</span>
|
||
|
||
<span class="tok-k">def</span> <span class="tok-nf">main</span><span class="tok-p">():</span>
|
||
<span class="tok-nb">print</span><span class="tok-p">(</span><span class="tok-s2">"Hello from inside a Python program built with a Nix flake!"</span><span class="tok-p">)</span>
|
||
|
||
<span class="tok-k">if</span> <span class="tok-vm">__name__</span> <span class="tok-o">==</span> <span class="tok-s2">"__main__"</span><span class="tok-p">:</span>
|
||
<span class="tok-n">main</span><span class="tok-p">()</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Before we package the program, let’s verify that it runs. We’re going to
|
||
need Python. By now you’ve probably figured out that we can write a
|
||
<code>flake.nix</code> and define a development shell that includes Python. We’ll
|
||
do that shortly, but first I want to show you a handy shortcut. We can
|
||
lauch a <em>temporary</em> shell with any Nix packages we want. This is
|
||
convenient when you just want to try out some new software and you’re
|
||
not sure if you’ll use it again. It’s also convenient when you’re not
|
||
ready to write <code>flake.nix</code> (perhaps you’re not sure what tools and
|
||
packages you need), and you want to experiment a bit first.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The command to enter a temporary shell is</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p><code>nix-shell -p <em>packages</em></code></p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If there are multiple packages, they should be separated by spaces.</p>
|
||
</div>
|
||
<div class="admonitionblock note">
|
||
<table>
|
||
<tr>
|
||
<td class="icon">
|
||
<i class="fa icon-note" title="Note"></i>
|
||
</td>
|
||
<td class="content">
|
||
<div class="paragraph">
|
||
<p>The command used here is <code>nix-shell</code> with a hyphen, not <code>nix shell</code>
|
||
with a space; those are two different commands. In fact there are
|
||
hyphenated and non-hyphenated versions of many Nix commands, and yes,
|
||
it’s confusing. The non-hyphenated commands were introduced when support
|
||
for flakes was added to Nix. I predict that eventually all hyphenated
|
||
commands will be replaced with non-hyphenated versions. Until then, a
|
||
useful rule of thumb is that non-hyphenated commands are for for working
|
||
directly with flakes; hyphenated commands are for everything else.</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s enter a shell with Python so we can test the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell -p python3
|
||
$ python hello.py
|
||
Hello from inside a Python program built with a Nix flake!</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_a_python_builder">8.2.2. A Python builder</h4>
|
||
<div class="paragraph">
|
||
<p>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
|
||
setuptools, see the
|
||
<a href="https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/">Python
|
||
Packaging User Guide</a>, especially the section on
|
||
<a href="https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#setup-args">setup
|
||
args</a>.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">setup.py</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="python"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#!/usr/bin/env python</span>
|
||
|
||
<span class="tok-kn">from</span> <span class="tok-nn">setuptools</span> <span class="tok-kn">import</span> <span class="tok-n">setup</span>
|
||
|
||
<span class="tok-n">setup</span><span class="tok-p">(</span>
|
||
<span class="tok-n">name</span><span class="tok-o">=</span><span class="tok-s1">'hello-flake-python'</span><span class="tok-p">,</span>
|
||
<span class="tok-n">version</span><span class="tok-o">=</span><span class="tok-s1">'0.1.0'</span><span class="tok-p">,</span>
|
||
<span class="tok-n">py_modules</span><span class="tok-o">=</span><span class="tok-p">[</span><span class="tok-s1">'hello'</span><span class="tok-p">],</span>
|
||
<span class="tok-n">entry_points</span><span class="tok-o">=</span><span class="tok-p">{</span>
|
||
<span class="tok-s1">'console_scripts'</span><span class="tok-p">:</span> <span class="tok-p">[</span><span class="tok-s1">'hello-flake-python = hello:main'</span><span class="tok-p">]</span>
|
||
<span class="tok-p">},</span>
|
||
<span class="tok-p">)</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We won’t write <code>flake.nix</code> just yet. First we’ll try building the
|
||
package manually.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ python -m build
|
||
/nix/store/qp5zys77biz7imbk6yy85q5pdv7qk84j-python3-3.11.6/bin/python: No module named build</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The missing module error happens because we don’t have <code>build</code> available
|
||
in the temporary shell. We can fix that by adding “build” to the
|
||
temporary shell. When you need support for both a language and some of
|
||
its packages, it’s best to use one of the Nix functions that are
|
||
specific to the programming language and build system. For Python, we
|
||
can use the <code>withPackages</code> function.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell -p "python3.withPackages (ps: with ps; [ build ])"
|
||
this derivation will be built:
|
||
/nix/store/xznwaaryp07z19xk658y8fckmsvawdlm-python3-3.11.6-env.drv
|
||
these 2 paths will be fetched (0.05 MiB download, 0.29 MiB unpacked):
|
||
/nix/store/q2rdk0ir8a809cqiklpawyfwmw738fcf-python3.11-build-1.0.3
|
||
/nix/store/04kcg3xgy0vfjjrm8ykvx3vcp6mrgzx9-python3.11-pyproject-hooks-1.0.0
|
||
copying path '/nix/store/04kcg3xgy0vfjjrm8ykvx3vcp6mrgzx9-python3.11-pyproject-hooks-1.0.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/q2rdk0ir8a809cqiklpawyfwmw738fcf-python3.11-build-1.0.3' from 'https://cache.nixos.org'...
|
||
building '/nix/store/xznwaaryp07z19xk658y8fckmsvawdlm-python3-3.11.6-env.drv'...
|
||
created 238 symlinks in user environment</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that we’re now inside a temporary shell inside the previous
|
||
temporary shell! To get back to the original shell, we have to <code>exit</code>
|
||
twice. Alternatively, we could have done <code>exit</code> followed by the
|
||
<code>nix-shell</code> command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ python -m build</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>After a lot of output messages, the build succeeds.</p>
|
||
</div>
|
||
</div>
|
||
<div class="sect3">
|
||
<h4 id="_the_nix_flake_2">8.2.3. The Nix flake</h4>
|
||
<div class="paragraph">
|
||
<p>Now we should write <code>flake.nix</code>. We already know how to write most of
|
||
the flake from the examples we did earlier. The two parts that will be
|
||
different are the development shell and the package builder.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s start with the development shell. It seems logical to write
|
||
something like the following.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap"> devShells = rec {
|
||
default = pkgs.mkShell {
|
||
packages = [ (python.withPackages (ps: with ps; [ build ])) ];
|
||
};
|
||
};</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Note that we need the parentheses to prevent <code>python.withPackages</code> and
|
||
the argument from being processed as two separate tokens. Suppose we
|
||
wanted to work with <code>virtualenv</code> and <code>pip</code> instead of <code>build</code>. We could
|
||
write something like the following.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap"> devShells = rec {
|
||
default = pkgs.mkShell {
|
||
packages = [
|
||
# Python plus helper tools
|
||
(python.withPackages (ps: with ps; [
|
||
virtualenv # Virtualenv
|
||
pip # The pip installer
|
||
]))
|
||
];
|
||
};
|
||
};</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>For the package builder, we can use the <code>buildPythonApplication</code>
|
||
function.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap"> packages = rec {
|
||
hello = python.pkgs.buildPythonApplication {
|
||
name = "hello-flake-python";
|
||
buildInputs = with python.pkgs; [ pip ];
|
||
src = ./.;
|
||
};
|
||
default = hello;
|
||
};</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If you put all the pieces together, your <code>flake.nix</code> should look
|
||
something like this.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">flake.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span>
|
||
<span class="normal">20</span>
|
||
<span class="normal">21</span>
|
||
<span class="normal">22</span>
|
||
<span class="normal">23</span>
|
||
<span class="normal">24</span>
|
||
<span class="normal">25</span>
|
||
<span class="normal">26</span>
|
||
<span class="normal">27</span>
|
||
<span class="normal">28</span>
|
||
<span class="normal">29</span>
|
||
<span class="normal">30</span>
|
||
<span class="normal">31</span>
|
||
<span class="normal">32</span>
|
||
<span class="normal">33</span>
|
||
<span class="normal">34</span>
|
||
<span class="normal">35</span>
|
||
<span class="normal">36</span>
|
||
<span class="normal">37</span>
|
||
<span class="normal">38</span>
|
||
<span class="normal">39</span>
|
||
<span class="normal">40</span>
|
||
<span class="normal">41</span>
|
||
<span class="normal">42</span>
|
||
<span class="normal">43</span>
|
||
<span class="normal">44</span>
|
||
<span class="normal">45</span>
|
||
<span class="normal">46</span>
|
||
<span class="normal">47</span>
|
||
<span class="normal">48</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-p">{</span>
|
||
<span class="tok-c1"># See https://github.com/mhwombat/nix-for-numbskulls/blob/main/flakes.md</span>
|
||
<span class="tok-c1"># for a brief overview of what each section in a flake should or can contain.</span>
|
||
|
||
<span class="tok-ss">description =</span> <span class="tok-s2">"a very simple and friendly flake written in Python"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">inputs =</span> <span class="tok-p">{</span>
|
||
nixpkgs<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:NixOS/nixpkgs"</span><span class="tok-p">;</span>
|
||
flake-utils<span class="tok-o">.</span><span class="tok-ss">url =</span> <span class="tok-s2">"github:numtide/flake-utils"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">outputs =</span> <span class="tok-p">{</span> self<span class="tok-p">,</span> nixpkgs<span class="tok-p">,</span> flake-utils <span class="tok-p">}:</span>
|
||
flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>eachDefaultSystem <span class="tok-p">(</span>system<span class="tok-p">:</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pkgs =</span> <span class="tok-nb">import</span> nixpkgs <span class="tok-p">{</span> <span class="tok-k">inherit</span> system<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">python =</span> pkgs<span class="tok-o">.</span>python3<span class="tok-p">;</span>
|
||
<span class="tok-k">in</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-ss">devShells =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">default =</span> pkgs<span class="tok-o">.</span>mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">packages =</span> <span class="tok-p">[</span>
|
||
<span class="tok-c1"># Python plus helper tools</span>
|
||
<span class="tok-p">(</span>python<span class="tok-o">.</span>withPackages <span class="tok-p">(</span>ps<span class="tok-p">:</span> <span class="tok-k">with</span> ps<span class="tok-p">;</span> <span class="tok-p">[</span>
|
||
virtualenv <span class="tok-c1"># Virtualenv</span>
|
||
pip <span class="tok-c1"># The pip installer</span>
|
||
<span class="tok-p">]))</span>
|
||
<span class="tok-p">];</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">packages =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello =</span> python<span class="tok-o">.</span>pkgs<span class="tok-o">.</span>buildPythonApplication <span class="tok-p">{</span>
|
||
<span class="tok-ss">name =</span> <span class="tok-s2">"hello-flake-python"</span><span class="tok-p">;</span>
|
||
|
||
<span class="tok-ss">buildInputs =</span> <span class="tok-k">with</span> python<span class="tok-o">.</span>pkgs<span class="tok-p">;</span> <span class="tok-p">[</span> pip <span class="tok-p">];</span>
|
||
|
||
<span class="tok-ss">src =</span> <span class="tok-o">.</span><span class="tok-l">/.</span><span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-ss">default =</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
|
||
<span class="tok-ss">apps =</span> <span class="tok-k">rec</span> <span class="tok-p">{</span>
|
||
<span class="tok-ss">hello =</span> flake-utils<span class="tok-o">.</span>lib<span class="tok-o">.</span>mkApp <span class="tok-p">{</span> <span class="tok-ss">drv =</span> self<span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-err">$</span><span class="tok-p">{</span>system<span class="tok-p">}</span><span class="tok-o">.</span>hello<span class="tok-p">;</span> <span class="tok-p">};</span>
|
||
<span class="tok-ss">default =</span> hello<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-p">}</span>
|
||
<span class="tok-p">);</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Let’s try out the new flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix run
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python' is dirty
|
||
error: getting status of '/nix/store/0ccnxa25whszw7mgbgyzdm4nqc0zwnm8-source/flake.nix': No such file or directory</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Why can’t it find <code>flake.nix</code>? Nix flakes only “see” files that are
|
||
part of the repository. We need to add all of the important files to the
|
||
repo before building or running the flake.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.nix setup.py hello.py
|
||
$ nix run
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python' is dirty
|
||
warning: creating lock file '/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python/flake.lock'
|
||
warning: Git tree '/home/amy/codeberg/nix-book/source/new-flake/python-flake/hello-python' is dirty
|
||
this derivation will be built:
|
||
/nix/store/3i7ypa818an6mqqmwz6jzrcsld1l15r0-hello-flake-python.drv
|
||
building '/nix/store/3i7ypa818an6mqqmwz6jzrcsld1l15r0-hello-flake-python.drv'...
|
||
Hello from inside a Python program built with a Nix flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>We’d like to share this package with others, but first we should do some
|
||
cleanup. When the package was built (automatically by the <code>nix run</code>
|
||
command), it created a <code>flake.lock</code> file. We need to add this to the
|
||
repo, and commit all important files.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ git add flake.lock
|
||
$ git commit -a -m 'initial commit'
|
||
[master (root-commit) 15ba3bc] initial commit
|
||
4 files changed, 127 insertions(+)
|
||
create mode 100644 flake.lock
|
||
create mode 100644 flake.nix
|
||
create mode 100644 hello.py
|
||
create mode 100644 setup.py</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>You can test that your package is properly configured by going to
|
||
another directory and running it from there.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ cd ..
|
||
$ nix run ./hello-python
|
||
Hello from inside a Python program built with a Nix flake!</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>If you move the project to a public repo, anyone can run it. Recall from
|
||
the beginning of the tutorial that you were able to run <code>hello-flake</code>
|
||
directly from my repo with the following command.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">nix run "git+https://codeberg.org/mhwombat/hello-flake"</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Modify the URL accordingly and invite someone else to run your new
|
||
Python flake.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_nix_shell_recipes">9. nix-shell recipes</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>There may be times where all you need is a shell.
|
||
Perhaps you’re doing a quick, one-off task.
|
||
In this situation, the older, non-flake way of using Nix
|
||
may be more convenient.
|
||
The examples in this chapter will illustrate the process.</p>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_shell_with_access_to_a_package_from_the_nixpkgsnixos_repo">9.1. Shell with access to a package from the Nixpkgs/NixOS repo</h3>
|
||
<div class="paragraph">
|
||
<p>This shell provides access to two packages from nixpkgs: hello and
|
||
cowsay.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span>
|
||
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">buildInputs =</span> <span class="tok-p">[</span>
|
||
hello
|
||
cowsay
|
||
<span class="tok-p">];</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell
|
||
these 2 paths will be fetched (0.06 MiB download, 0.27 MiB unpacked):
|
||
/nix/store/rc7kpqwb8z5ch37ysv5yk9yg5hl5bkdj-cowsay-3.7.0
|
||
/nix/store/sbldylj3clbkc0aqvjjzfa6slp4zdvlj-hello-2.12.1
|
||
copying path '/nix/store/rc7kpqwb8z5ch37ysv5yk9yg5hl5bkdj-cowsay-3.7.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/sbldylj3clbkc0aqvjjzfa6slp4zdvlj-hello-2.12.1' from 'https://cache.nixos.org'...
|
||
$ hello
|
||
Hello, world!
|
||
$ cowsay "moo"
|
||
_____
|
||
< moo >
|
||
-----
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The command-line equivalent would be <code>nix-shell -p hello cowsay</code></p>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_shell_with_access_to_a_package_defined_in_a_remote_git_repo">9.2. Shell with access to a package defined in a remote git repo</h3>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">hello =</span> <span class="tok-nb">import</span> <span class="tok-p">(</span><span class="tok-nb">builtins</span><span class="tok-o">.</span>fetchGit <span class="tok-p">{</span>
|
||
<span class="tok-ss">url =</span> <span class="tok-s2">"https://codeberg.org/mhwombat/hello-nix"</span><span class="tok-p">;</span>
|
||
<span class="tok-ss">rev =</span> <span class="tok-s2">"aa2c87f8b89578b069b09fdb2be30a0c9d8a77d8"</span><span class="tok-p">;</span>
|
||
<span class="tok-p">});</span>
|
||
<span class="tok-k">in</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">buildInputs =</span> <span class="tok-p">[</span> hello <span class="tok-p">];</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell
|
||
this derivation will be built:
|
||
/nix/store/jk6140wbn2xpayxbcrq5qy1b8k5175kd-hello-nix-1.0.0.drv
|
||
building '/nix/store/jk6140wbn2xpayxbcrq5qy1b8k5175kd-hello-nix-1.0.0.drv'...
|
||
unpacking sources
|
||
unpacking source archive /nix/store/3rag1cba3pldx04m5an67rkbcy3rq4db-zr9gki8f26247yzxrspcf4z7kv0vl5mf-source
|
||
source root is zr9gki8f26247yzxrspcf4z7kv0vl5mf-source
|
||
patching sources
|
||
updateAutotoolsGnuConfigScriptsPhase
|
||
configuring
|
||
no configure script, doing nothing
|
||
building
|
||
no Makefile or custom buildPhase, doing nothing
|
||
installing
|
||
post-installation fixup
|
||
shrinking RPATHs of ELF executables and libraries in /nix/store/9ysp78nycwzhzf4b2jmkz0qsc9w3mmp2-hello-nix-1.0.0
|
||
checking for references to /build/ in /nix/store/9ysp78nycwzhzf4b2jmkz0qsc9w3mmp2-hello-nix-1.0.0...
|
||
patching script interpreter paths in /nix/store/9ysp78nycwzhzf4b2jmkz0qsc9w3mmp2-hello-nix-1.0.0
|
||
/nix/store/9ysp78nycwzhzf4b2jmkz0qsc9w3mmp2-hello-nix-1.0.0/bin/hello-nix: interpreter directive changed from "#!/usr/bin/env sh" to "/nix/store/q1c2flcykgr4wwg5a6h450hxbk4ch589-bash-5.2-p15/bin/sh"
|
||
stripping (with command strip and flags -S -p) in /nix/store/9ysp78nycwzhzf4b2jmkz0qsc9w3mmp2-hello-nix-1.0.0/bin
|
||
$ hello
|
||
bash: line 2: hello: command not found</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_shell_with_access_to_a_specific_revision_of_a_flake">9.3. Shell with access to a specific revision of a flake</h3>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span>
|
||
<span class="normal">7</span>
|
||
<span class="normal">8</span>
|
||
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">hello =</span> <span class="tok-p">(</span><span class="tok-nb">builtins</span><span class="tok-o">.</span>getFlake <span class="tok-l">git+https://codeberg.org/mhwombat/hello-flake?ref=main&rev=3aa43dbe7be878dde7b2bdcbe992fe1705da3150</span><span class="tok-p">)</span><span class="tok-o">.</span>packages<span class="tok-o">.</span><span class="tok-err">$</span><span class="tok-p">{</span><span class="tok-nb">builtins</span><span class="tok-o">.</span>currentSystem<span class="tok-p">}</span><span class="tok-o">.</span>default<span class="tok-p">;</span>
|
||
<span class="tok-k">in</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">buildInputs =</span> <span class="tok-p">[</span>
|
||
hello
|
||
<span class="tok-p">];</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell
|
||
copying path '/nix/store/9zkfbyk0xjiyzkky8p01jc4hm7jrwz5w-source' from 'https://cache.nixos.org'...
|
||
this derivation will be built:
|
||
/nix/store/qspvnv4m9cz2rinvswagi8jfnclzx24k-hello-flake-20230218.drv
|
||
these 36 paths will be fetched (65.28 MiB download, 296.69 MiB unpacked):
|
||
/nix/store/218mzh306bw7rkhcgljlwqpvrdmcy13i-acl-2.3.1
|
||
/nix/store/ifs8pac5sv026ynk5gk5qg6ap7qdq1x1-attr-2.5.1
|
||
/nix/store/zcla0ljiwpg5w8pvfagfjq1y2vasfix5-bash-5.1-p16
|
||
/nix/store/c4j39cgj3cwxgb5fp3z1vsyjhav33bxs-binutils-2.39
|
||
/nix/store/4c302k97bbc33xgjzmkypkwrmqba9gqy-binutils-wrapper-2.39
|
||
/nix/store/61rpfcaxhyqfmnk5qp4z7hf20wh9zgrk-bzip2-1.0.8
|
||
/nix/store/7yhklbxbjivcqk5ql4rl660glgc3iba9-bzip2-1.0.8-bin
|
||
/nix/store/gn5515zj8skk23jvrrljirgxr10fw9az-coreutils-9.1
|
||
/nix/store/wjiawwzad72q2mm9515fpx6n4zn91xfg-diffutils-3.8
|
||
/nix/store/x056x7nsrzfxpzf61pfc6apajax7zd4h-ed-1.18
|
||
/nix/store/kny46nl4gq9415qqnhmwpfvn2376399m-expand-response-params
|
||
/nix/store/pdds64xdjvzddhcxlidna5xyphmjdxpg-file-5.43
|
||
/nix/store/3iwxvsnfx6kr7ga37kbmjz1df3nb95ri-findutils-4.9.0
|
||
/nix/store/n5x3p2n835bl0v6ampnqchdklwvr8szh-gawk-5.1.1
|
||
/nix/store/3cjvw93ly6cx2af13f2l3pw4yzbi8wp6-gcc-11.3.0
|
||
/nix/store/b13h86pg7lbf6vpc1vwzw6akmakyw1bs-gcc-11.3.0-lib
|
||
/nix/store/9yxrwp848f7msm6m2442yfpji8m3206b-gcc-wrapper-11.3.0
|
||
/nix/store/9xfad3b5z4y00mzmk2wnn4900q0qmxns-glibc-2.35-224
|
||
/nix/store/gfsg0n19r8q8v69kwwjvx4m2y77vi7i8-glibc-2.35-224-bin
|
||
/nix/store/bq928ff6m7lvcfyvcdvgvqxhqi5f3ijq-glibc-2.35-224-dev
|
||
/nix/store/askxicd00lc1jqshyh5lcwjpxfqygiiy-gmp-with-cxx-stage4-6.2.1
|
||
/nix/store/6l34p4ip6ib1q87cpd4g5yhg3j86zign-gnugrep-3.7
|
||
/nix/store/qnhmjdxh35whjqqya1sd6jh7jh2ld978-gnumake-4.3
|
||
/nix/store/687xxx92x0pg1yzvj8lv4xz5b9vs20qh-gnused-4.8
|
||
/nix/store/nybc3q7ksr0i226cvs7wgrfgzx3b60nw-gnutar-1.34
|
||
/nix/store/m8gycf587qfdkjc76bsf6c6w12pbzc35-gzip-1.12
|
||
/nix/store/5mh5019jigj0k14rdnjam1xwk5avn1id-libidn2-2.3.2
|
||
/nix/store/34xlpp3j3vy7ksn09zh44f1c04w77khf-libunistring-1.0
|
||
/nix/store/i38jcxrwa4fxk2b7acxircpi399kyixw-linux-headers-6.0
|
||
/nix/store/c4ssk8c0y9hxwjgv9i1qh26sas9as0hg-patch-2.7.6
|
||
/nix/store/d84xrx5n73fb0bc28gnsgwvj1rv2fywk-patchelf-0.15.0
|
||
/nix/store/sm5ch5nkhpj4dmhm8siia1kq8sia6jf5-pcre-8.45
|
||
/nix/store/7bc3vsg3laghwg0cin2il9iwd7ka820k-stdenv-linux
|
||
/nix/store/2gsz9a3v0fylbghzsljz2dnxfs9iidrn-xz-5.2.7
|
||
/nix/store/kvqhx6wxflyp780ggpd27dklwa28sban-xz-5.2.7-bin
|
||
/nix/store/fblaj5ywkgphzpp5kx41av32kls9256y-zlib-1.2.13
|
||
copying path '/nix/store/34xlpp3j3vy7ksn09zh44f1c04w77khf-libunistring-1.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/i38jcxrwa4fxk2b7acxircpi399kyixw-linux-headers-6.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/5mh5019jigj0k14rdnjam1xwk5avn1id-libidn2-2.3.2' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/9xfad3b5z4y00mzmk2wnn4900q0qmxns-glibc-2.35-224' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/ifs8pac5sv026ynk5gk5qg6ap7qdq1x1-attr-2.5.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/zcla0ljiwpg5w8pvfagfjq1y2vasfix5-bash-5.1-p16' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/kny46nl4gq9415qqnhmwpfvn2376399m-expand-response-params' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/n5x3p2n835bl0v6ampnqchdklwvr8szh-gawk-5.1.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/b13h86pg7lbf6vpc1vwzw6akmakyw1bs-gcc-11.3.0-lib' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/gfsg0n19r8q8v69kwwjvx4m2y77vi7i8-glibc-2.35-224-bin' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/687xxx92x0pg1yzvj8lv4xz5b9vs20qh-gnused-4.8' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/sm5ch5nkhpj4dmhm8siia1kq8sia6jf5-pcre-8.45' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/2gsz9a3v0fylbghzsljz2dnxfs9iidrn-xz-5.2.7' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/61rpfcaxhyqfmnk5qp4z7hf20wh9zgrk-bzip2-1.0.8' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/m8gycf587qfdkjc76bsf6c6w12pbzc35-gzip-1.12' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/x056x7nsrzfxpzf61pfc6apajax7zd4h-ed-1.18' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/qnhmjdxh35whjqqya1sd6jh7jh2ld978-gnumake-4.3' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/fblaj5ywkgphzpp5kx41av32kls9256y-zlib-1.2.13' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/c4ssk8c0y9hxwjgv9i1qh26sas9as0hg-patch-2.7.6' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/pdds64xdjvzddhcxlidna5xyphmjdxpg-file-5.43' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/7yhklbxbjivcqk5ql4rl660glgc3iba9-bzip2-1.0.8-bin' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/218mzh306bw7rkhcgljlwqpvrdmcy13i-acl-2.3.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/bq928ff6m7lvcfyvcdvgvqxhqi5f3ijq-glibc-2.35-224-dev' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/kvqhx6wxflyp780ggpd27dklwa28sban-xz-5.2.7-bin' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/6l34p4ip6ib1q87cpd4g5yhg3j86zign-gnugrep-3.7' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/nybc3q7ksr0i226cvs7wgrfgzx3b60nw-gnutar-1.34' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/c4j39cgj3cwxgb5fp3z1vsyjhav33bxs-binutils-2.39' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/3cjvw93ly6cx2af13f2l3pw4yzbi8wp6-gcc-11.3.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/askxicd00lc1jqshyh5lcwjpxfqygiiy-gmp-with-cxx-stage4-6.2.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/d84xrx5n73fb0bc28gnsgwvj1rv2fywk-patchelf-0.15.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/gn5515zj8skk23jvrrljirgxr10fw9az-coreutils-9.1' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/wjiawwzad72q2mm9515fpx6n4zn91xfg-diffutils-3.8' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/3iwxvsnfx6kr7ga37kbmjz1df3nb95ri-findutils-4.9.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/4c302k97bbc33xgjzmkypkwrmqba9gqy-binutils-wrapper-2.39' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/9yxrwp848f7msm6m2442yfpji8m3206b-gcc-wrapper-11.3.0' from 'https://cache.nixos.org'...
|
||
copying path '/nix/store/7bc3vsg3laghwg0cin2il9iwd7ka820k-stdenv-linux' from 'https://cache.nixos.org'...
|
||
building '/nix/store/qspvnv4m9cz2rinvswagi8jfnclzx24k-hello-flake-20230218.drv'...
|
||
unpacking sources
|
||
patching sources
|
||
configuring
|
||
no configure script, doing nothing
|
||
building
|
||
installing
|
||
post-installation fixup
|
||
shrinking RPATHs of ELF executables and libraries in /nix/store/h1064a2fs25vx6zwr0fmfrhfxhw6qm7z-hello-flake-20230218
|
||
strip is /nix/store/9yxrwp848f7msm6m2442yfpji8m3206b-gcc-wrapper-11.3.0/bin/strip
|
||
stripping (with command strip and flags -S) in /nix/store/h1064a2fs25vx6zwr0fmfrhfxhw6qm7z-hello-flake-20230218/bin
|
||
patching script interpreter paths in /nix/store/h1064a2fs25vx6zwr0fmfrhfxhw6qm7z-hello-flake-20230218
|
||
/nix/store/h1064a2fs25vx6zwr0fmfrhfxhw6qm7z-hello-flake-20230218/bin/hello-flake: interpreter directive changed from "#!/usr/bin/env sh" to "/nix/store/zcla0ljiwpg5w8pvfagfjq1y2vasfix5-bash-5.1-p16/bin/sh"
|
||
checking for references to /build/ in /nix/store/h1064a2fs25vx6zwr0fmfrhfxhw6qm7z-hello-flake-20230218...
|
||
$ hello
|
||
bash: line 2: hello: command not found</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_shell_with_access_to_a_haskell_package_on_your_local_computer">9.4. Shell with access to a Haskell package on your local computer</h3>
|
||
<div class="paragraph">
|
||
<p>This shell provides access to three Haskell packages that are on my hard
|
||
drive.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pandoc-linear-table =</span> haskellPackages<span class="tok-o">.</span>callCabal2nix <span class="tok-s2">"pandoc-linear-table"</span> <span class="tok-l">/home/amy/github/pandoc-linear-table</span> <span class="tok-p">{};</span>
|
||
<span class="tok-ss">pandoc-logic-proof =</span> haskellPackages<span class="tok-o">.</span>callCabal2nix <span class="tok-s2">"pandoc-logic-proof"</span> <span class="tok-l">/home/amy/github/pandoc-logic-proof</span> <span class="tok-p">{};</span>
|
||
<span class="tok-ss">pandoc-columns =</span> haskellPackages<span class="tok-o">.</span>callCabal2nix <span class="tok-s2">"pandoc-columns"</span> <span class="tok-l">/home/amy/github/pandoc-columns</span> <span class="tok-p">{};</span>
|
||
<span class="tok-k">in</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">buildInputs =</span> <span class="tok-p">[</span>
|
||
pandoc
|
||
pandoc-linear-table
|
||
pandoc-logic-proof
|
||
pandoc-columns
|
||
<span class="tok-p">];</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_shell_with_access_to_a_haskell_package_on_your_local_computer_with_interdependencies">9.5. Shell with access to a Haskell package on your local computer, with interdependencies</h3>
|
||
<div class="paragraph">
|
||
<p>This shell provides access to four Haskell packages that are on my hard
|
||
drive. The fourth package depends on the first three to build.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span>
|
||
<span class="normal">16</span>
|
||
<span class="normal">17</span>
|
||
<span class="normal">18</span>
|
||
<span class="normal">19</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">pandoc-linear-table =</span> haskellPackages<span class="tok-o">.</span>callCabal2nix <span class="tok-s2">"pandoc-linear-table"</span> <span class="tok-l">/home/amy/github/pandoc-linear-table</span> <span class="tok-p">{};</span>
|
||
<span class="tok-ss">pandoc-logic-proof =</span> haskellPackages<span class="tok-o">.</span>callCabal2nix <span class="tok-s2">"pandoc-logic-proof"</span> <span class="tok-l">/home/amy/github/pandoc-logic-proof</span> <span class="tok-p">{};</span>
|
||
<span class="tok-ss">pandoc-columns =</span> haskellPackages<span class="tok-o">.</span>callCabal2nix <span class="tok-s2">"pandoc-columns"</span> <span class="tok-l">/home/amy/github/pandoc-columns</span> <span class="tok-p">{};</span>
|
||
<span class="tok-ss">pandoc-maths-web =</span> haskellPackages<span class="tok-o">.</span>callCabal2nix <span class="tok-s2">"pandoc-maths-web"</span> <span class="tok-l">/home/amy/github/pandoc-maths-web</span>
|
||
<span class="tok-p">{</span>
|
||
<span class="tok-k">inherit</span> pandoc-linear-table pandoc-logic-proof pandoc-columns<span class="tok-p">;</span>
|
||
<span class="tok-p">};</span>
|
||
<span class="tok-k">in</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">buildInputs =</span> <span class="tok-p">[</span>
|
||
pandoc
|
||
pandoc-linear-table
|
||
pandoc-logic-proof
|
||
pandoc-columns
|
||
pandoc-maths-web
|
||
<span class="tok-p">];</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_shell_with_runtime_access_to_a_haskell_library_on_your_local_computer_no_cabal_file_required">9.6. Shell with runtime access to a Haskell library on your local computer (no <code>.cabal</code> file required)</h3>
|
||
<div class="paragraph">
|
||
<p>Occasionally you might want to run a short Haskell program that depends on a Haskell library,
|
||
but you don’t want to bother writing a cabal file.
|
||
This shell provides access to the Haskell <code>containers</code> library (package).</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span>
|
||
<span class="normal">7</span>
|
||
<span class="normal">8</span>
|
||
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
<span class="tok-k">let</span>
|
||
<span class="tok-ss">customGhc =</span> haskellPackages<span class="tok-o">.</span>ghcWithPackages <span class="tok-p">(</span>pkgs<span class="tok-p">:</span> <span class="tok-k">with</span> pkgs<span class="tok-p">;</span> <span class="tok-p">[</span> containers <span class="tok-p">]);</span>
|
||
<span class="tok-k">in</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">buildInputs =</span> <span class="tok-p">[</span>
|
||
customGhc
|
||
<span class="tok-p">];</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a short Haskell program that uses it.</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">Main.hs</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="haskell"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-kr">import</span><span class="tok-w"> </span><span class="tok-nn">Data.Map</span>
|
||
|
||
<span class="tok-nf">m</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">Map</span><span class="tok-w"> </span><span class="tok-kt">String</span><span class="tok-w"> </span><span class="tok-kt">Int</span>
|
||
<span class="tok-nf">m</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">fromList</span><span class="tok-w"> </span><span class="tok-p">[(</span><span class="tok-s">"cats"</span><span class="tok-p">,</span><span class="tok-w"> </span><span class="tok-mi">3</span><span class="tok-p">),</span><span class="tok-w"> </span><span class="tok-p">(</span><span class="tok-s">"dogs"</span><span class="tok-p">,</span><span class="tok-w"> </span><span class="tok-mi">2</span><span class="tok-p">)]</span>
|
||
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">IO</span><span class="tok-w"> </span><span class="tok-nb">()</span>
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-kr">do</span>
|
||
<span class="tok-w"> </span><span class="tok-kr">let</span><span class="tok-w"> </span><span class="tok-n">cats</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">findWithDefault</span><span class="tok-w"> </span><span class="tok-mi">0</span><span class="tok-w"> </span><span class="tok-s">"cats"</span><span class="tok-w"> </span><span class="tok-n">m</span>
|
||
<span class="tok-w"> </span><span class="tok-kr">let</span><span class="tok-w"> </span><span class="tok-n">dogs</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">findWithDefault</span><span class="tok-w"> </span><span class="tok-mi">0</span><span class="tok-w"> </span><span class="tok-s">"dogs"</span><span class="tok-w"> </span><span class="tok-n">m</span>
|
||
<span class="tok-w"> </span><span class="tok-kr">let</span><span class="tok-w"> </span><span class="tok-n">zebras</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">findWithDefault</span><span class="tok-w"> </span><span class="tok-mi">0</span><span class="tok-w"> </span><span class="tok-s">"zebras"</span><span class="tok-w"> </span><span class="tok-n">m</span>
|
||
<span class="tok-w"> </span><span class="tok-n">print</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-s">"I have "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">show</span><span class="tok-w"> </span><span class="tok-n">cats</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-s">" cats, "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">show</span><span class="tok-w"> </span><span class="tok-n">dogs</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-s">" dogs, and "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">show</span><span class="tok-w"> </span><span class="tok-n">zebras</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-s">" zebras."</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the program.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell
|
||
$ runghc Main.hs
|
||
"I have 3 cats, 2 dogs, and 0 zebras."</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_shell_with_an_environment_variable_set">9.7. Shell with an environment variable set</h3>
|
||
<div class="paragraph">
|
||
<p>This shell has the environment variable FOO set to “bar”</p>
|
||
</div>
|
||
<div class="listingblock">
|
||
<div class="title">shell.nix</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="nix"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span>
|
||
<span class="normal">4</span>
|
||
<span class="normal">5</span>
|
||
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-k">with</span> <span class="tok-p">(</span><span class="tok-nb">import</span> <span class="tok-l"><nixpkgs></span> <span class="tok-p">{});</span>
|
||
mkShell <span class="tok-p">{</span>
|
||
<span class="tok-ss">shellHook =</span> <span class="tok-s1">''</span>
|
||
<span class="tok-s1"> export FOO="bar"</span>
|
||
<span class="tok-s1"> ''</span><span class="tok-p">;</span>
|
||
<span class="tok-p">}</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>Here’s a demonstration using the shell.</p>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="content">
|
||
<pre class="nowrap">$ nix-shell
|
||
$ echo "FOO=$FOO"
|
||
FOO=</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect1">
|
||
<h2 id="_nix_shell_shebangs">10. Nix-shell shebangs</h2>
|
||
<div class="sectionbody">
|
||
<div class="paragraph">
|
||
<p>You can use <code>nix-shell</code> to run scripts in arbitrary languages, providing
|
||
the necessary dependencies. This is particularly convenient for
|
||
standalone scripts because you don’t need to create a repo and write a
|
||
separate <code>flake.nix</code>.</p>
|
||
</div>
|
||
<div class="paragraph">
|
||
<p>The script should start with two “shebang” (<code>#!</code>) commands. The first
|
||
should invoke <code>nix-shell</code>. The second should declares the script
|
||
interpreter and any dependencies. Here are some examples.</p>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_a_bash_script_depending_on_a_package_in_the_nixpkgs_repo">10.1. A Bash script depending on a package in the nixpkgs repo.</h3>
|
||
<div class="listingblock">
|
||
<div class="title">Script</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
|
||
<span class="normal">2</span>
|
||
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#! /usr/bin/env nix-shell</span>
|
||
<span class="tok-c1">#! nix-shell -i bash -p cowsay</span>
|
||
cowsay<span class="tok-w"> </span><span class="tok-s2">"Pretty cool, huh?"</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">Output</div>
|
||
<div class="content">
|
||
<pre class="nowrap"> ___________________
|
||
< Pretty cool, huh? >
|
||
-------------------
|
||
\ ^__^
|
||
\ (oo)\_______
|
||
(__)\ )\/\
|
||
||----w |
|
||
|| ||</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_a_haskell_script_depending_on_a_haskell_library_package_in_the_nixpkgs_repo">10.2. A Haskell script depending on a Haskell library package in the nixpkgs repo.</h3>
|
||
<div class="listingblock">
|
||
<div class="title">Script</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="haskell"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span>
|
||
<span class="normal">12</span>
|
||
<span class="normal">13</span>
|
||
<span class="normal">14</span>
|
||
<span class="normal">15</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-o">#!</span><span class="tok-w"> </span><span class="tok-o">/</span><span class="tok-n">usr</span><span class="tok-o">/</span><span class="tok-n">bin</span><span class="tok-o">/</span><span class="tok-n">env</span><span class="tok-w"> </span><span class="tok-n">nix</span><span class="tok-o">-</span><span class="tok-n">shell</span>
|
||
<span class="tok-o">#!</span><span class="tok-w"> </span><span class="tok-n">nix</span><span class="tok-o">-</span><span class="tok-n">shell</span><span class="tok-w"> </span><span class="tok-o">-</span><span class="tok-n">p</span><span class="tok-w"> </span><span class="tok-s">"haskellPackages.ghcWithPackages (p: [p.containers])"</span>
|
||
<span class="tok-o">#!</span><span class="tok-w"> </span><span class="tok-n">nix</span><span class="tok-o">-</span><span class="tok-n">shell</span><span class="tok-w"> </span><span class="tok-o">-</span><span class="tok-n">i</span><span class="tok-w"> </span><span class="tok-n">runghc</span>
|
||
|
||
<span class="tok-kr">import</span><span class="tok-w"> </span><span class="tok-nn">Data.Map</span>
|
||
|
||
<span class="tok-nf">m</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">Map</span><span class="tok-w"> </span><span class="tok-kt">String</span><span class="tok-w"> </span><span class="tok-kt">Int</span>
|
||
<span class="tok-nf">m</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">fromList</span><span class="tok-w"> </span><span class="tok-p">[(</span><span class="tok-s">"cats"</span><span class="tok-p">,</span><span class="tok-w"> </span><span class="tok-mi">3</span><span class="tok-p">),</span><span class="tok-w"> </span><span class="tok-p">(</span><span class="tok-s">"dogs"</span><span class="tok-p">,</span><span class="tok-w"> </span><span class="tok-mi">2</span><span class="tok-p">)]</span>
|
||
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">::</span><span class="tok-w"> </span><span class="tok-kt">IO</span><span class="tok-w"> </span><span class="tok-nb">()</span>
|
||
<span class="tok-nf">main</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-kr">do</span>
|
||
<span class="tok-w"> </span><span class="tok-kr">let</span><span class="tok-w"> </span><span class="tok-n">cats</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">findWithDefault</span><span class="tok-w"> </span><span class="tok-mi">0</span><span class="tok-w"> </span><span class="tok-s">"cats"</span><span class="tok-w"> </span><span class="tok-n">m</span>
|
||
<span class="tok-w"> </span><span class="tok-kr">let</span><span class="tok-w"> </span><span class="tok-n">dogs</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">findWithDefault</span><span class="tok-w"> </span><span class="tok-mi">0</span><span class="tok-w"> </span><span class="tok-s">"dogs"</span><span class="tok-w"> </span><span class="tok-n">m</span>
|
||
<span class="tok-w"> </span><span class="tok-kr">let</span><span class="tok-w"> </span><span class="tok-n">zebras</span><span class="tok-w"> </span><span class="tok-ow">=</span><span class="tok-w"> </span><span class="tok-n">findWithDefault</span><span class="tok-w"> </span><span class="tok-mi">0</span><span class="tok-w"> </span><span class="tok-s">"zebras"</span><span class="tok-w"> </span><span class="tok-n">m</span>
|
||
<span class="tok-w"> </span><span class="tok-n">print</span><span class="tok-w"> </span><span class="tok-o">$</span><span class="tok-w"> </span><span class="tok-s">"I have "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">show</span><span class="tok-w"> </span><span class="tok-n">cats</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-s">" cats, "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">show</span><span class="tok-w"> </span><span class="tok-n">dogs</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-s">" dogs, and "</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-n">show</span><span class="tok-w"> </span><span class="tok-n">zebras</span><span class="tok-w"> </span><span class="tok-o">++</span><span class="tok-w"> </span><span class="tok-s">" zebras."</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">Output</div>
|
||
<div class="content">
|
||
<pre class="nowrap">bash: line 11: 2184465 Segmentation fault (core dumped) ./my-script.sh</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sect2">
|
||
<h3 id="_a_python_script_depending_on_a_package_in_the_nixpkgs_repo">10.3. A Python script depending on a package in the nixpkgs repo.</h3>
|
||
<div class="listingblock">
|
||
<div class="title">Script</div>
|
||
<div class="content">
|
||
<pre class="pygments highlight nowrap"><code data-lang="bash"><div class="lineno"><table class="linenotable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||
<span class="normal"> 2</span>
|
||
<span class="normal"> 3</span>
|
||
<span class="normal"> 4</span>
|
||
<span class="normal"> 5</span>
|
||
<span class="normal"> 6</span>
|
||
<span class="normal"> 7</span>
|
||
<span class="normal"> 8</span>
|
||
<span class="normal"> 9</span>
|
||
<span class="normal">10</span>
|
||
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><span class="tok-ch">#! /usr/bin/env nix-shell</span>
|
||
<span class="tok-c1">#! nix-shell -i python3 -p python3Packages.html-sanitizer</span>
|
||
|
||
from<span class="tok-w"> </span>html_sanitizer<span class="tok-w"> </span>import<span class="tok-w"> </span>Sanitizer
|
||
<span class="tok-nv">sanitizer</span><span class="tok-w"> </span><span class="tok-o">=</span><span class="tok-w"> </span>Sanitizer<span class="tok-o">()</span><span class="tok-w"> </span><span class="tok-c1"># default configuration</span>
|
||
|
||
<span class="tok-nv">original</span><span class="tok-o">=</span><span class="tok-s1">'<span style="font-weight:bold">some text</span>'</span>
|
||
print<span class="tok-o">(</span><span class="tok-s1">'original: '</span>,<span class="tok-w"> </span>original<span class="tok-o">)</span>
|
||
|
||
<span class="tok-nv">sanitized</span><span class="tok-o">=</span>sanitizer.sanitize<span class="tok-o">(</span>original<span class="tok-o">)</span>
|
||
print<span class="tok-o">(</span><span class="tok-s1">'sanitized: '</span>,<span class="tok-w"> </span>sanitized<span class="tok-o">)</span>
|
||
</pre></div></td></tr></table></div></code></pre>
|
||
</div>
|
||
</div>
|
||
<div class="literalblock">
|
||
<div class="title">Output</div>
|
||
<div class="content">
|
||
<pre class="nowrap">this path will be fetched (0.02 MiB download, 0.13 MiB unpacked):
|
||
/nix/store/i4ixl9vzscm259g168ar4fvj3bm38ika-python3.11-html-sanitizer-2.2
|
||
copying path '/nix/store/i4ixl9vzscm259g168ar4fvj3bm38ika-python3.11-html-sanitizer-2.2' from 'https://cache.nixos.org'...
|
||
original: <span style="font-weight:bold">some text</span>
|
||
sanitized: <strong>some text</strong></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="footnotes">
|
||
<hr>
|
||
<div class="footnote" id="_footnotedef_1">
|
||
<a href="#_footnoteref_1">1</a>. For an introduction to the Nix language, see <a href="https://nixos.org/guides/nix-language.html">Nix language basics</a>.
|
||
</div>
|
||
<div class="footnote" id="_footnotedef_2">
|
||
<a href="#_footnoteref_2">2</a>. For more information on the standard environment, see the <a href="https://nixos.org/manual/nixpkgs/stable/#sec-tools-of-stdenv">Nixpkgs manual</a>
|
||
</div>
|
||
</div>
|
||
<div id="footer">
|
||
<div id="footer-text">
|
||
Last updated 1980-01-01 00:00:00 UTC
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html> |