91 lines
4.0 KiB
Markdown
91 lines
4.0 KiB
Markdown
|
|
# Packaging
|
||
|
|
|
||
|
|
This note covers `02-package/`, which builds a shell script into a Nix store path using `stdenv.mkDerivation`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. What `nix build` Does
|
||
|
|
|
||
|
|
When you run `nix build` inside `02-package/`:
|
||
|
|
|
||
|
|
1. Nix evaluates `flake.nix` and produces a `.drv` file (the build recipe).
|
||
|
|
2. Nix realises the `.drv`: it runs the install phase inside a sandbox with no network and no access to files outside the declared inputs.
|
||
|
|
3. The output lands in `/nix/store/<hash>-greet-0.1.0/`.
|
||
|
|
4. A `./result` symlink is created pointing to that store path.
|
||
|
|
|
||
|
|
You can then run `./result/bin/greet` directly, or use `nix run` which does step 1 through 3 and then executes the `apps.<system>.default.program` path.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. `stdenv.mkDerivation` in Detail
|
||
|
|
|
||
|
|
`stdenv.mkDerivation` is the main builder in nixpkgs. It wraps the low-level `derivation` builtin with a phased build system. The default phases, in order:
|
||
|
|
|
||
|
|
1. `unpackPhase`: extracts `src` (tarball, git checkout, or copied path).
|
||
|
|
2. `patchPhase`: applies patches from the `patches` list.
|
||
|
|
3. `configurePhase`: runs `./configure` or cmake or similar.
|
||
|
|
4. `buildPhase`: runs `make` or equivalent.
|
||
|
|
5. `installPhase`: copies outputs into `$out`.
|
||
|
|
6. `fixupPhase`: strips binaries, patches RPATHs, shrink-wraps references.
|
||
|
|
|
||
|
|
For a simple script, most of these are irrelevant. The `02-package` example disables unpack and build with `dontUnpack = true` and `dontBuild = true`, then writes a custom `installPhase`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Key Concepts in the Example
|
||
|
|
|
||
|
|
`$out`: every derivation has at least one output. `$out` is the default output path. The build must place files under `$out` or the derivation produces nothing.
|
||
|
|
|
||
|
|
`substituteInPlace`: a nixpkgs helper that does in-place string replacement. The example uses it to rewrite the shebang from `#!/usr/bin/env bash` to a store-path bash. This matters because `/usr/bin/env` may not exist on a pure NixOS system, and even where it does, it would pick up whichever `bash` happens to be on `$PATH` at runtime rather than the pinned one.
|
||
|
|
|
||
|
|
`src = ./.`: copies the entire flake directory into the store before the build starts. Changes to any file in the directory change the hash, which triggers a rebuild. For real projects you'd use `lib.fileset` or `lib.cleanSource` to exclude irrelevant files (editor backups, `.git/`, etc.).
|
||
|
|
|
||
|
|
`apps.<system>.default`: the `nix run` command looks for this attribute. Its `program` field must be an absolute store path to an executable.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. The Build Sandbox
|
||
|
|
|
||
|
|
By default, Nix builds run inside a sandbox:
|
||
|
|
|
||
|
|
- No network access (except fixed-output derivations).
|
||
|
|
- No access to the host filesystem beyond explicitly declared inputs.
|
||
|
|
- No access to environment variables from the host.
|
||
|
|
- A restricted `/tmp` for scratch space.
|
||
|
|
|
||
|
|
This is what guarantees reproducibility: the build can only use what it declared.
|
||
|
|
|
||
|
|
If a build needs to download something (a source tarball, a Go module cache), it must be a fixed-output derivation. You provide the expected hash, and Nix verifies the output matches. See `builtins.fetchurl`, `pkgs.fetchFromGitHub`, and similar.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Commands to Try
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd 02-package
|
||
|
|
|
||
|
|
nix build # build and create ./result symlink
|
||
|
|
./result/bin/greet # run directly
|
||
|
|
./result/bin/greet "nix learner" # pass an argument
|
||
|
|
|
||
|
|
nix run # build + run via apps.default
|
||
|
|
nix run . -- "nix learner" # pass arguments after --
|
||
|
|
|
||
|
|
nix path-info ./result # show the store path
|
||
|
|
nix path-info -rS ./result # show closure size (all transitive deps)
|
||
|
|
nix derivation show ./result # inspect the .drv (inputs, env, builder)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. Beyond Shell Scripts
|
||
|
|
|
||
|
|
The same `stdenv.mkDerivation` pattern scales to compiled languages. nixpkgs provides wrappers:
|
||
|
|
|
||
|
|
- `rustPlatform.buildRustPackage` for Rust (Cargo).
|
||
|
|
- `buildGoModule` for Go.
|
||
|
|
- `python3Packages.buildPythonPackage` for Python.
|
||
|
|
- `mkDerivation` directly for C/C++ (autotools, cmake, meson).
|
||
|
|
|
||
|
|
Each wrapper pre-configures the phases for its ecosystem. You supply `src`, a lock file hash, and metadata; the wrapper handles configure/build/install.
|