Skip to content

Commit

Permalink
mkShell: make it buildable (#153194)
Browse files Browse the repository at this point in the history
When I designed `mkShell`, I didn't have a good idea of what the output
should look like and so decided to make the build fail. In practice,
this causes quite a bit of confusion and complications because now the
shell cannot be part of a normal package set without failing the CI as
well.

This commit changes that build phase to record all the build inputs in a
file. That way it becomes possible to build it, makes sure that all the
build inputs get built as well, and also can be used as a GC root.
(by applying the same trick as #95536).

The documentation has also been improved to better describe what mkShell
does and how to use it.
  • Loading branch information
zimbatm authored Jan 8, 2022
1 parent cacab72 commit 1e91020
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 17 deletions.
32 changes: 26 additions & 6 deletions doc/builders/special/mkshell.section.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
# pkgs.mkShell {#sec-pkgs-mkShell}

`pkgs.mkShell` is a special kind of derivation that is only useful when using
it combined with `nix-shell`. It will in fact fail to instantiate when invoked
with `nix-build`.
`pkgs.mkShell` is a specialized `stdenv.mkDerivation` that removes some
repetition when using it with `nix-shell` (or `nix develop`).

## Usage {#sec-pkgs-mkShell-usage}

Here is a common usage example:

```nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
# specify which packages to add to the shell environment
packages = [ pkgs.gnumake ];
# add all the dependencies, of the given packages, to the shell environment
inputsFrom = with pkgs; [ hello gnutar ];
inputsFrom = [ pkgs.hello pkgs.gnutar ];
shellHook = ''
export DEBUG=1
'';
}
```

## Attributes

* `name` (default: `nix-shell`). Set the name of the derivation.
* `packages` (default: `[]`). Add executable packages to the `nix-shell` environment.
* `inputsFrom` (default: `[]`). Add build dependencies of the listed derivations to the `nix-shell` environment.
* `shellHook` (default: `""`). Bash statements that are executed by `nix-shell`.

... all the attributes of `stdenv.mkDerivation`.

## Building the shell

This derivation output will contain a text file that contains a reference to
all the build inputs. This is useful in CI where we want to make sure that
every derivation, and its dependencies, build properly. Or when creating a GC
root so that the build dependencies don't get garbage-collected.
27 changes: 16 additions & 11 deletions pkgs/build-support/mkshell/default.nix
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{ lib, stdenv }:
{ lib, stdenv, buildEnv }:

# A special kind of derivation that is only meant to be consumed by the
# nix-shell.
{
# a list of packages to add to the shell environment
{ name ? "nix-shell"
, # a list of packages to add to the shell environment
packages ? [ ]
, # propagate all the inputs from the given derivations
inputsFrom ? [ ]
Expand All @@ -15,10 +15,11 @@
}@attrs:
let
mergeInputs = name:
(attrs.${name} or []) ++
(attrs.${name} or [ ]) ++
(lib.subtractLists inputsFrom (lib.flatten (lib.catAttrs name inputsFrom)));

rest = builtins.removeAttrs attrs [
"name"
"packages"
"inputsFrom"
"buildInputs"
Expand All @@ -30,8 +31,7 @@ let
in

stdenv.mkDerivation ({
name = "nix-shell";
phases = [ "nobuildPhase" ];
inherit name;

buildInputs = mergeInputs "buildInputs";
nativeBuildInputs = packages ++ (mergeInputs "nativeBuildInputs");
Expand All @@ -41,10 +41,15 @@ stdenv.mkDerivation ({
shellHook = lib.concatStringsSep "\n" (lib.catAttrs "shellHook"
(lib.reverseList inputsFrom ++ [ attrs ]));

nobuildPhase = ''
echo
echo "This derivation is not meant to be built, aborting";
echo
exit 1
phases = [ "buildPhase" ];

buildPhase = ''
echo "------------------------------------------------------------" >>$out
echo " WARNING: the existence of this path is not guaranteed." >>$out
echo " It is an internal implementation detail for pkgs.mkShell." >>$out
echo "------------------------------------------------------------" >>$out
echo >> $out
# Record all build inputs as runtime dependencies
export >> $out
'';
} // rest)

0 comments on commit 1e91020

Please sign in to comment.