2017-08-11 21:41:14 -04:00
|
|
|
<chapter xmlns="http://docbook.org/ns/docbook"
|
2017-08-11 18:22:51 -04:00
|
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
|
|
version="5.0"
|
2017-08-11 21:41:14 -04:00
|
|
|
xml:id="developing-with-nix-shell">
|
2017-08-11 18:22:51 -04:00
|
|
|
|
2017-08-22 08:19:43 -04:00
|
|
|
<title>Developing with <command>nix-shell</command></title>
|
2017-08-17 08:51:11 -04:00
|
|
|
|
|
|
|
<para>
|
|
|
|
Welcome to the 10th Nix pill. In the previous
|
2020-02-26 02:56:29 -05:00
|
|
|
<link linkend="automatic-runtime-dependencies">9th pill</link> we saw
|
2024-02-09 06:47:48 -05:00
|
|
|
one of the powerful features of Nix: automatic discovery of runtime
|
|
|
|
dependencies. We also finalized the GNU <code>hello</code> package.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
In this pill, we will introduce the <command>nix-shell</command> tool
|
|
|
|
and use it to hack on the GNU <code>hello</code> program. We will
|
|
|
|
see how <command>nix-shell</command> gives us an isolated environment
|
|
|
|
while we modify the source files of the project, similar to how
|
|
|
|
<command>nix-build</command> gave us an isolated environment while building
|
|
|
|
the derivation.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Finally, we will modify our builder to work more ergonomically
|
|
|
|
with a <command>nix-shell</command>-focused workflow.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<section>
|
2024-02-09 06:47:48 -05:00
|
|
|
<title>What is <command>nix-shell</command>?</title>
|
2017-08-17 08:51:11 -04:00
|
|
|
|
|
|
|
<para>
|
|
|
|
The <link
|
2021-11-14 10:54:12 -05:00
|
|
|
xlink:href="https://nixos.org/manual/nix/stable/command-ref/nix-shell.html">nix-shell</link>
|
2024-02-09 06:47:48 -05:00
|
|
|
tool drops us in a shell after setting up the environment variables necessary
|
|
|
|
to hack on a derivation. It does not build the derivation; it
|
2017-08-17 08:51:11 -04:00
|
|
|
only serves as a preparation so that we can run the build steps manually.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
Recall that in a nix environment, we don't have access to libraries or
|
|
|
|
programs unless they have been installed with <command>nix-env</command>.
|
|
|
|
However, installing libraries with <command>nix-env</command> is not
|
|
|
|
good practice. We prefer to have isolated environments for development, which
|
|
|
|
<command>nix-shell</command> provides for us.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
We can call <command>nix-shell</command> on any Nix expression which
|
|
|
|
returns a derivation, but the resulting <code>bash</code> shell's
|
|
|
|
<code>PATH</code> does not have the utilities we want:
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<screen><xi:include href="./10/nix-shell-hello.txt" parse="text" /></screen>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
This shell is rather useless. It would be reasonable to expect that the GNU
|
|
|
|
<code>hello</code> build inputs are available in <code>PATH</code>, including
|
|
|
|
GNU <code>make</code>, but this is not the case.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
However, we do have the environment variables that we set in the derivation,
|
2017-08-17 08:51:11 -04:00
|
|
|
like <code>$baseInputs</code>, <code>$buildInputs</code>,
|
2024-02-09 06:47:48 -05:00
|
|
|
<code>$src</code>, and so on.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
This means the we can <command>source</command> our
|
|
|
|
<filename>builder.sh</filename>, and it will build the derivation.
|
|
|
|
You may get an error in the installation phase, because your user may
|
|
|
|
not have the permission to write to <filename>/nix/store</filename>:
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<screen><xi:include href="./10/source-builder.txt" parse="text" /></screen>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
The derivation didn't install, but it did build. Note the following:
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
We sourced <filename>builder.sh</filename> and it ran all of the build
|
|
|
|
steps, including setting up the <code>PATH</code> for us.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
The working directory is no longer a temp directory created by
|
|
|
|
<command>nix-build</command>, but is instead the directory in which
|
|
|
|
we entered the shell. Therefore, <filename>hello-2.10</filename> has
|
|
|
|
been unpacked in the current directory.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
We are able to <command>cd</command> into <filename>hello-2.10</filename> and type
|
|
|
|
<command>make</command>, because <command>make</command> is now available.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
The take-away is that <command>nix-shell</command> drops us in a shell with the
|
|
|
|
same (or very similar) environment used to run the builder.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>A builder for nix-shell</title>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
The previous steps require some manual commands to be run and are not
|
|
|
|
optimized for a workflow centered on <command>nix-shell</command>. We
|
|
|
|
will now improve our builder to be more <command>nix-shell</command> friendly.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
There are a few things that we would like to change.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
First, when we <command>source</command>d the <filename>builder.sh</filename>
|
|
|
|
file, we obtained the file in the currenty directory. What we really wanted
|
|
|
|
was the <filename>builder.sh</filename> that is stored in the nix store,
|
|
|
|
as this is the file that would be used by <command>nix-build</command>.
|
|
|
|
To achieve this, the correct technique is to pass an environment variable
|
|
|
|
through the derivation. (Note that <code>$builder</code> is
|
|
|
|
already defined, but it points to the bash executable rather than our
|
2017-08-17 08:51:11 -04:00
|
|
|
<filename>builder.sh</filename>. Our <filename>builder.sh</filename> is
|
2024-02-09 06:47:48 -05:00
|
|
|
passed as an argument to bash.)
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
Second, we don't want to run the whole builder: we only want to setup
|
|
|
|
the necessary environment for manually building the project. Thus, we
|
|
|
|
can break <filename>builder.sh</filename> into two files: a
|
|
|
|
<filename>setup.sh</filename> for setting up the environment, and
|
|
|
|
the real <filename>builder.sh</filename> that <command>nix-build</command>
|
|
|
|
expects.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
During our refactoring, we ill wrap the build phases in functions to
|
|
|
|
give more structure to our design. Additionally, we'll move the
|
|
|
|
<code>set -e</code> to the builder file instead of the setup file.
|
|
|
|
The <code>set -e</code> is annoying in <command>nix-shell</command>,
|
|
|
|
as it will terminate the shell if an error is encountered (such as
|
|
|
|
a mistyped command.)
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2018-12-24 19:39:42 -05:00
|
|
|
Here is our modified <filename>autotools.nix</filename>.
|
2017-08-17 08:51:11 -04:00
|
|
|
Noteworthy is the <code>setup = ./setup.sh;</code> attribute in the
|
|
|
|
derivation, which adds <filename>setup.sh</filename> to the nix store and
|
2024-02-09 06:47:48 -05:00
|
|
|
correspondingly adds a <code>$setup</code> environment variable in the builder.
|
2018-12-24 19:39:42 -05:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<programlisting><xi:include href="./10/autotools-nix.txt" parse="text" /></programlisting>
|
|
|
|
|
|
|
|
<para>
|
2017-08-17 08:51:11 -04:00
|
|
|
Thanks to that, we can split <filename>builder.sh</filename> into
|
|
|
|
<filename>setup.sh</filename> and <filename>builder.sh</filename>. What
|
2024-02-09 06:47:48 -05:00
|
|
|
<filename>builder.sh</filename> does is <command>source</command>
|
|
|
|
<code>$setup</code> and call the <code>genericBuild</code> function.
|
|
|
|
Everything else is just some changes to the bash script.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
|
2018-12-24 19:39:42 -05:00
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
Here is the modified <filename>builder.sh</filename>:
|
2018-12-24 19:39:42 -05:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<programlisting><xi:include href="./10/builder-sh.txt" parse="text" /></programlisting>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
Here is the newly added <filename>setup.sh</filename>:
|
2018-12-24 19:39:42 -05:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<programlisting><xi:include href="./10/setup-sh.txt" parse="text" /></programlisting>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
Finally, here is <filename>hello.nix</filename>:
|
2018-12-24 19:39:42 -05:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<programlisting><xi:include href="./10/hello-nix.txt" parse="text" /></programlisting>
|
|
|
|
|
2017-08-17 08:51:11 -04:00
|
|
|
<para>
|
|
|
|
Now back to nix-shell:
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<screen><xi:include href="./10/nix-shell-source.txt" parse="text" /></screen>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
Now, for example, you can run <code>unpackPhase</code> which unpacks
|
2017-08-17 08:51:11 -04:00
|
|
|
<code>$src</code> and enters the directory. And you can run commands
|
2024-02-09 06:47:48 -05:00
|
|
|
like <command>./configure</command>, <command>make</command>, and so forth
|
2017-08-17 08:51:11 -04:00
|
|
|
manually, or run phases with their respective functions.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
The process is that straightforward. <command>nix-shell</command> builds the
|
|
|
|
<code>.drv</code> file and its input dependencies, then drops into a shell
|
|
|
|
by setting up the environment variables necessary to build the <code>.drv</code>.
|
|
|
|
In particular, the environment variables in the shell match those passed
|
|
|
|
to the <code>derivation</code> function.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Conclusion</title>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
With <command>nix-shell</command> we are able to drop into an isolated
|
|
|
|
environment suitable for developing a project. This environment provides the necessary
|
|
|
|
dependencies for the development shell, similar to how
|
|
|
|
<command>nix-build</command> providesthe necessary dependencies to a builder.
|
|
|
|
Additionally, we can build and debug the project manually, executing step-by-step
|
|
|
|
like we would in any other operating system. Note that we never installed tools
|
|
|
|
such <command>gcc</command> or <command>make</command> system-wide; these tools
|
|
|
|
and libraries are isolated and available per-build.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
</section>
|
|
|
|
|
|
|
|
<section>
|
|
|
|
<title>Next pill</title>
|
|
|
|
|
|
|
|
<para>
|
2024-02-09 06:47:48 -05:00
|
|
|
In the next pill, we will clean up the nix store. We have written and built
|
|
|
|
derivations which add to the nix store, but until now we haven't worried
|
|
|
|
about cleaning up the used space in the store.
|
2017-08-17 08:51:11 -04:00
|
|
|
</para>
|
|
|
|
</section>
|
2017-08-11 21:41:14 -04:00
|
|
|
</chapter>
|