nix-super/doc/manual/src/contributing/hacking.md
2024-04-16 15:54:45 +02:00

12 KiB
Raw Blame History

Hacking

This section provides some notes on how to hack on Nix. To get the latest version of Nix from GitHub:

$ git clone https://github.com/NixOS/nix.git
$ cd nix

The following instructions assume you already have some version of Nix installed locally, so that you can use it to set up the development environment. If you don't have it installed, follow the installation instructions.

Building Nix with flakes

This section assumes you are using Nix with the flakes and nix-command experimental features enabled. See the Building Nix section for equivalent instructions using stable Nix interfaces.

To build all dependencies and start a shell in which all environment variables are set up so that those dependencies can be found:

$ nix develop

This shell also adds ./outputs/bin/nix to your $PATH so you can run nix immediately after building it.

To get a shell with one of the other supported compilation environments:

$ nix develop .#native-clangStdenvPackages

Note

Use ccacheStdenv to drastically improve rebuild time. By default, ccache keeps artifacts in ~/.cache/ccache/.

To build Nix itself in this shell:

[nix-shell]$ autoreconfPhase
[nix-shell]$ configurePhase
[nix-shell]$ make -j $NIX_BUILD_CORES OPTIMIZE=0

To install it in $(pwd)/outputs and test it:

[nix-shell]$ make install OPTIMIZE=0
[nix-shell]$ make installcheck check -j $NIX_BUILD_CORES
[nix-shell]$ nix --version
nix (Nix) 2.12

For more information on running and filtering tests, see testing.md.

To build a release version of Nix for the current operating system and CPU architecture:

$ nix build

You can also build Nix for one of the supported platforms.

Building Nix

To build all dependencies and start a shell in which all environment variables are set up so that those dependencies can be found:

$ nix-shell

To get a shell with one of the other supported compilation environments:

$ nix-shell --attr devShells.x86_64-linux.native-clangStdenvPackages

Note

You can use native-ccacheStdenvPackages to drastically improve rebuild time. By default, ccache keeps artifacts in ~/.cache/ccache/.

To build Nix itself in this shell:

[nix-shell]$ autoreconfPhase
[nix-shell]$ ./configure $configureFlags --prefix=$(pwd)/outputs/out
[nix-shell]$ make -j $NIX_BUILD_CORES

To install it in $(pwd)/outputs and test it:

[nix-shell]$ make install
[nix-shell]$ make installcheck -j $NIX_BUILD_CORES
[nix-shell]$ ./outputs/out/bin/nix --version
nix (Nix) 2.12

To build a release version of Nix for the current operating system and CPU architecture:

$ nix-build

You can also build Nix for one of the supported platforms.

Makefile variables

You may need profiledir=$out/etc/profile.d and sysconfdir=$out/etc to run make install.

Run make with -e / --environment-overrides to allow environment variables to override Makefile variables:

  • ENABLE_BUILD=yes to enable building the C++ code.

  • ENABLE_DOC_GEN=yes to enable building the documentation (manual, man pages, etc.).

    The docs can take a while to build, so you may want to disable this for local development.

  • ENABLE_FUNCTIONAL_TESTS=yes to enable building the functional tests.

  • ENABLE_UNIT_TESTS=yes to enable building the unit tests.

  • OPTIMIZE=1 to enable optimizations.

  • libraries=libutil programs= to only build a specific library.

    This will fail in the linking phase if the other libraries haven't been built, but is useful for checking types.

  • libraries= programs=nix to only build a specific program.

    This will not work in general, because the programs need the libraries.

Platforms

Nix can be built for various platforms, as specified in flake.nix:

  • x86_64-linux
  • x86_64-darwin
  • i686-linux
  • aarch64-linux
  • aarch64-darwin
  • armv6l-linux
  • armv7l-linux

In order to build Nix for a different platform than the one you're currently on, you need a way for your current Nix installation to build code for that platform. Common solutions include [remote build machines] and binary format emulation (only supported on NixOS).

Given such a setup, executing the build only requires selecting the respective attribute. For example, to compile for aarch64-linux:

$ nix-build --attr packages.aarch64-linux.default

or for Nix with the flakes and nix-command experimental features enabled:

$ nix build .#packages.aarch64-linux.default

Cross-compiled builds are available for ARMv6 (armv6l-linux) and ARMv7 (armv7l-linux). Add more system types to crossSystems in flake.nix to bootstrap Nix on unsupported platforms.

Building for multiple platforms at once

It is useful to perform multiple cross and native builds on the same source tree, for example to ensure that better support for one platform doesn't break the build for another. In order to facilitate this, Nix has some support for being built out of tree that is, placing build artefacts in a different directory than the source code:

  1. Create a directory for the build, e.g.

    mkdir build
    
  2. Run the configure script from that directory, e.g.

    cd build
    ../configure <configure flags>
    
  3. Run make from the source directory, but with the build directory specified, e.g.

    make builddir=build <make flags>
    

System type

Nix uses a string with the following format to identify the system type or platform it runs on:

<cpu>-<os>[-<abi>]

It is set when Nix is compiled for the given system, and based on the output of config.guess (upstream):

<cpu>-<vendor>-<os>[<version>][-<abi>]

When Nix is built such that ./configure is passed any of the --host, --build, --target options, the value is based on the output of config.sub (upstream):

<cpu>-<vendor>[-<kernel>]-<os>

For historic reasons and backward-compatibility, some CPU and OS identifiers are translated from the GNU Autotools naming convention in configure.ac as follows:

config.guess Nix
amd64 x86_64
i*86 i686
arm6 arm6l
arm7 arm7l
linux-gnu* linux
linux-musl* linux

Compilation environments

Nix can be compiled using multiple environments:

  • stdenv: default;
  • gccStdenv: force the use of gcc compiler;
  • clangStdenv: force the use of clang compiler;
  • ccacheStdenv: enable [ccache], a compiler cache to speed up compilation.

To build with one of those environments, you can use

$ nix build .#nix-ccacheStdenv

for flake-enabled Nix, or

$ nix-build --attr nix-ccacheStdenv

for classic Nix.

You can use any of the other supported environments in place of nix-ccacheStdenv.

Editor integration

The clangd LSP server is installed by default on the clang-based devShells. See supported compilation environments and instructions how to set up a shell with flakes or in classic Nix.

To use the LSP with your editor, you first need to set up clangd by running:

make compile_commands.json

Configure your editor to use the clangd from the .#native-clangStdenvPackages shell. You can do that either by running it inside the development shell, or by using nix-direnv and the appropriate editor plugin.

Note

For some editors (e.g. Visual Studio Code), you may need to install a special extension for the editor to interact with clangd. Some other editors (e.g. Emacs, Vim) need a plugin to support LSP servers in general (e.g. lsp-mode for Emacs and vim-lsp for vim). Editor-specific setup is typically opinionated, so we will not cover it here in more detail.

Add a release note

doc/manual/rl-next contains release notes entries for all unreleased changes.

User-visible changes should come with a release note.

Add an entry

Here's what a complete entry looks like. The file name is not incorporated in the document.

---
synopsis: Basically a title
issues: 1234
prs: 1238
---

Here's one or more paragraphs that describe the change.

- It's markdown
- Add references to the manual using @docroot@

Significant changes should add the following header, which moves them to the top.

significance: significant

See also the format documentation.

Build process

Releases have a precomputed rl-MAJOR.MINOR.md, and no rl-next.md.

Branches

Reverting

If a change turns out to be merged by mistake, or contain a regression, it may be reverted. A revert is not a rejection of the contribution, but merely part of an effective development process. It makes sure that development keeps running smoothly, with minimal uncertainty, and less overhead. If maintainers have to worry too much about avoiding reverts, they would not be able to merge as much. By embracing reverts as a good part of the development process, everyone wins.

However, taking a step back may be frustrating, so maintainers will be extra supportive on the next try.