mirror of
https://github.com/ryan4yin/nixos-and-flakes-book.git
synced 2025-08-20 17:10:26 +02:00
chore: automatically collapse all lines(max width = 100) (#126)
This commit is contained in:
@@ -1,21 +1,32 @@
|
||||
# Cross-platform Compilation
|
||||
|
||||
On any Linux platform, there are two ways to do cross-platform compilation. For example, to build an `aarch64-linux` program on an `x86_64-linux` host, you can use the following methods:
|
||||
On any Linux platform, there are two ways to do cross-platform compilation. For example,
|
||||
to build an `aarch64-linux` program on an `x86_64-linux` host, you can use the following
|
||||
methods:
|
||||
|
||||
1. Use the cross-compilation toolchain to compile the `aarch64` program.
|
||||
- The disadvantage is that you cannot use the NixOS binary cache, and you need to compile everything yourself (cross-compilation also has a cache, but there is basically nothing in it).
|
||||
- The advantages are that you don't need to emulate the instruction set, and the performance is high.
|
||||
2. Use QEMU to emulate the `aarch64` architecture and then compile the program in the emulator.
|
||||
- The disadvantage is that the instruction set is emulated, and the performance is poor.
|
||||
- The advantage is that you can use the NixOS binary cache, and you don't need to compile everything yourself.
|
||||
- The disadvantage is that you cannot use the NixOS binary cache, and you need to
|
||||
compile everything yourself (cross-compilation also has a cache, but there is
|
||||
basically nothing in it).
|
||||
- The advantages are that you don't need to emulate the instruction set, and the
|
||||
performance is high.
|
||||
2. Use QEMU to emulate the `aarch64` architecture and then compile the program in the
|
||||
emulator.
|
||||
- The disadvantage is that the instruction set is emulated, and the performance is
|
||||
poor.
|
||||
- The advantage is that you can use the NixOS binary cache, and you don't need to
|
||||
compile everything yourself.
|
||||
|
||||
If you use method one, you don't need to enable `binfmt_misc`, but you need to execute the compilation through the cross-compilation toolchain.
|
||||
If you use method one, you don't need to enable `binfmt_misc`, but you need to execute the
|
||||
compilation through the cross-compilation toolchain.
|
||||
|
||||
If you use method two, you need to enable the `binfmt_misc` of the `aarch64` architecture in the NixOS configuration of the building machine.
|
||||
If you use method two, you need to enable the `binfmt_misc` of the `aarch64` architecture
|
||||
in the NixOS configuration of the building machine.
|
||||
|
||||
## Cross Compilation
|
||||
|
||||
`nixpkgs` provides a set of predefined host platforms for cross-compilation called `pkgsCross`. You can explore them in `nix repl`.
|
||||
`nixpkgs` provides a set of predefined host platforms for cross-compilation called
|
||||
`pkgsCross`. You can explore them in `nix repl`.
|
||||
|
||||
```shell
|
||||
› nix repl '<nixpkgs>'
|
||||
@@ -60,7 +71,8 @@ pkgsCross.mipsel-linux-gnu
|
||||
pkgsCross.mmix
|
||||
```
|
||||
|
||||
If you want to set `pkgs` to a cross-compilation toolchain globally in a flake, you only need to add a Module in `flake.nix`, as shown below:
|
||||
If you want to set `pkgs` to a cross-compilation toolchain globally in a flake, you only
|
||||
need to add a Module in `flake.nix`, as shown below:
|
||||
|
||||
```nix{15-20}
|
||||
{
|
||||
@@ -91,13 +103,18 @@ If you want to set `pkgs` to a cross-compilation toolchain globally in a flake,
|
||||
}
|
||||
```
|
||||
|
||||
The `nixpkgs.crossSystem` option is used to set `pkgs` to a cross-compilation toolchain, so that all the contents built will be `riscv64-linux` architecture.
|
||||
The `nixpkgs.crossSystem` option is used to set `pkgs` to a cross-compilation toolchain,
|
||||
so that all the contents built will be `riscv64-linux` architecture.
|
||||
|
||||
## Compile through emulated system
|
||||
|
||||
The second method is to cross-compile through the emulated system. This method does not require a cross-compilation toolchain.
|
||||
The second method is to cross-compile through the emulated system. This method does not
|
||||
require a cross-compilation toolchain.
|
||||
|
||||
To use this method, first your building machine needs to enable the binfmt_misc module in the configuration. If your building machine is NixOS, add the following configuration to your NixOS Module to enable the simulated build system of `aarch64-linux` and `riscv64-linux` architectures:
|
||||
To use this method, first your building machine needs to enable the binfmt_misc module in
|
||||
the configuration. If your building machine is NixOS, add the following configuration to
|
||||
your NixOS Module to enable the simulated build system of `aarch64-linux` and
|
||||
`riscv64-linux` architectures:
|
||||
|
||||
```nix{6}
|
||||
{ ... }:
|
||||
@@ -111,7 +128,8 @@ To use this method, first your building machine needs to enable the binfmt_misc
|
||||
}
|
||||
```
|
||||
|
||||
As for `flake.nix`, its setting method is very simple, even simpler than the setting of cross-compilation, as shown below:
|
||||
As for `flake.nix`, its setting method is very simple, even simpler than the setting of
|
||||
cross-compilation, as shown below:
|
||||
|
||||
```nix{11}
|
||||
{
|
||||
@@ -134,19 +152,40 @@ As for `flake.nix`, its setting method is very simple, even simpler than the set
|
||||
```
|
||||
|
||||
You do not need to add any additional modules, just specify `system` as `riscv64-linux`.
|
||||
Nix will automatically detect whether the current system is `riscv64-linux` during the build. If not, it will automatically build through the emulated system(QEMU). For users, these underlying operations are completely transparent.
|
||||
Nix will automatically detect whether the current system is `riscv64-linux` during the
|
||||
build. If not, it will automatically build through the emulated system(QEMU). For users,
|
||||
these underlying operations are completely transparent.
|
||||
|
||||
## Linux binfmt_misc
|
||||
|
||||
The previous section only provided an introduction on how to use Nix's emulated system, but if you want to understand the underlying details, here's a brief introduction.
|
||||
The previous section only provided an introduction on how to use Nix's emulated system,
|
||||
but if you want to understand the underlying details, here's a brief introduction.
|
||||
|
||||
`binfmt_misc` is a feature of the Linux kernel, which stands for Kernel Support for miscellaneous Binary Formats. It enables Linux to run programs for almost any CPU architecture, including X86_64, ARM64, RISCV64, and more.
|
||||
`binfmt_misc` is a feature of the Linux kernel, which stands for Kernel Support for
|
||||
miscellaneous Binary Formats. It enables Linux to run programs for almost any CPU
|
||||
architecture, including X86_64, ARM64, RISCV64, and more.
|
||||
|
||||
To enable `binfmt_misc` to run programs in various formats, two things are required: a specific identification method for the binary format and the location of the corresponding interpreter. Although `binfmt_misc` sounds powerful, its implementation is surprisingly easy to understand. It works similarly to how the Bash interpreter determines the interpreter to use by reading the first line of a script file (e.g., `#!/usr/bin/env python3`). `binfmt_misc` defines a set of rules, such as reading the magic number at a specific location in the binary file or determining the executable file format based on the file extension (e.g., .exe, .py). It then invokes the corresponding interpreter to execute the program. The default executable file format in Linux is ELF, but `binfmt_misc` expands the execution possibilities by allowing a wide range of binary files to be executed using their respective interpreters.
|
||||
To enable `binfmt_misc` to run programs in various formats, two things are required: a
|
||||
specific identification method for the binary format and the location of the corresponding
|
||||
interpreter. Although `binfmt_misc` sounds powerful, its implementation is surprisingly
|
||||
easy to understand. It works similarly to how the Bash interpreter determines the
|
||||
interpreter to use by reading the first line of a script file (e.g.,
|
||||
`#!/usr/bin/env python3`). `binfmt_misc` defines a set of rules, such as reading the magic
|
||||
number at a specific location in the binary file or determining the executable file format
|
||||
based on the file extension (e.g., .exe, .py). It then invokes the corresponding
|
||||
interpreter to execute the program. The default executable file format in Linux is ELF,
|
||||
but `binfmt_misc` expands the execution possibilities by allowing a wide range of binary
|
||||
files to be executed using their respective interpreters.
|
||||
|
||||
To register a binary program format, you need to write a line in the format `:name:type:offset:magic:mask:interpreter:flags` to the `/proc/sys/fs/binfmt_misc/register` file. The detailed explanation of the format is beyond the scope of this discussion.
|
||||
To register a binary program format, you need to write a line in the format
|
||||
`:name:type:offset:magic:mask:interpreter:flags` to the
|
||||
`/proc/sys/fs/binfmt_misc/register` file. The detailed explanation of the format is beyond
|
||||
the scope of this discussion.
|
||||
|
||||
Since manually writing the registration information for `binfmt_misc` can be cumbersome, the community provides a container to assist with automatic registration. This container is called `binfmt` and running it will install various `binfmt_misc` emulators. Here's an example:
|
||||
Since manually writing the registration information for `binfmt_misc` can be cumbersome,
|
||||
the community provides a container to assist with automatic registration. This container
|
||||
is called `binfmt` and running it will install various `binfmt_misc` emulators. Here's an
|
||||
example:
|
||||
|
||||
```shell
|
||||
# Register all architectures
|
||||
@@ -156,13 +195,23 @@ podman run --privileged --rm tonistiigi/binfmt:latest --install all
|
||||
docker run --privileged --rm tonistiigi/binfmt --install arm64,riscv64,arm
|
||||
```
|
||||
|
||||
The `binfmt_misc` module was introduced in Linux version 2.6.12-rc2 and has undergone several minor changes in functionality since then. In Linux 4.8, the "F" (fix binary) flag was added, allowing the interpreter to be invoked correctly in mount namespaces and chroot environments. To work properly in containers where multiple architectures need to be built, the "F" flag is necessary. Therefore, the kernel version needs to be 4.8 or above.
|
||||
The `binfmt_misc` module was introduced in Linux version 2.6.12-rc2 and has undergone
|
||||
several minor changes in functionality since then. In Linux 4.8, the "F" (fix binary) flag
|
||||
was added, allowing the interpreter to be invoked correctly in mount namespaces and chroot
|
||||
environments. To work properly in containers where multiple architectures need to be
|
||||
built, the "F" flag is necessary. Therefore, the kernel version needs to be 4.8 or above.
|
||||
|
||||
In summary, `binfmt_misc` provides transparency compared to explicitly calling an interpreter to execute non-native architecture programs. With `binfmt_misc`, users no longer need to worry about which interpreter to use when running a program. It allows programs of any architecture to be executed directly. The configurable "F" flag is an added benefit, as it loads the interpreter program into memory during installation and remains unaffected by subsequent environment changes.
|
||||
In summary, `binfmt_misc` provides transparency compared to explicitly calling an
|
||||
interpreter to execute non-native architecture programs. With `binfmt_misc`, users no
|
||||
longer need to worry about which interpreter to use when running a program. It allows
|
||||
programs of any architecture to be executed directly. The configurable "F" flag is an
|
||||
added benefit, as it loads the interpreter program into memory during installation and
|
||||
remains unaffected by subsequent environment changes.
|
||||
|
||||
## Custom build toolchain
|
||||
|
||||
Sometimes we may need to use a custom toolchain for building, such as using our own gcc, or using our own musl libc, etc. This modification can be achieved through overlays.
|
||||
Sometimes we may need to use a custom toolchain for building, such as using our own gcc,
|
||||
or using our own musl libc, etc. This modification can be achieved through overlays.
|
||||
|
||||
For example, let's try to use a different version of gcc, and test it through `nix repl`:
|
||||
|
||||
@@ -218,9 +267,13 @@ So how to use this method in Flakes? The example `flake.nix` is as follows:
|
||||
}
|
||||
```
|
||||
|
||||
`nixpkgs.overlays` is used to modify the `pkgs` instance globally, and the modified `pkgs` instance will take effect to the whole flake. It will likely cause a large number of cache missing, and thus require building a large number of Nix packages locally.
|
||||
`nixpkgs.overlays` is used to modify the `pkgs` instance globally, and the modified `pkgs`
|
||||
instance will take effect to the whole flake. It will likely cause a large number of cache
|
||||
missing, and thus require building a large number of Nix packages locally.
|
||||
|
||||
To avoid this problem, a better way is to create a new `pkgs` instance, and only use this instance when building the packages we want to modify. The example `flake.nix` is as follows:
|
||||
To avoid this problem, a better way is to create a new `pkgs` instance, and only use this
|
||||
instance when building the packages we want to modify. The example `flake.nix` is as
|
||||
follows:
|
||||
|
||||
```nix{10-19,34-37}
|
||||
{
|
||||
@@ -268,7 +321,8 @@ To avoid this problem, a better way is to create a new `pkgs` instance, and only
|
||||
}
|
||||
```
|
||||
|
||||
Through the above method, we can easily customize the build toolchain of some packages without affecting the build of other packages.
|
||||
Through the above method, we can easily customize the build toolchain of some packages
|
||||
without affecting the build of other packages.
|
||||
|
||||
## References
|
||||
|
||||
|
@@ -1,30 +1,36 @@
|
||||
# Dev Environments
|
||||
|
||||
We have learned how to build development environments, but it's a bit tedious to write `flake.nix` for each project.
|
||||
We have learned how to build development environments, but it's a bit tedious to write
|
||||
`flake.nix` for each project.
|
||||
|
||||
Luckily, some people in the community have done this for us. The following repository contains development environment templates for most programming languages. Just copy and paste them:
|
||||
Luckily, some people in the community have done this for us. The following repository
|
||||
contains development environment templates for most programming languages. Just copy and
|
||||
paste them:
|
||||
|
||||
- [dev-templates](https://github.com/the-nix-way/dev-templates)
|
||||
- [MordragT/nix-templates](https://github.com/MordragT/nix-templates)
|
||||
|
||||
If you think the structure of `flake.nix` is still too complicated and want a simpler way,
|
||||
you can consider using the following project,
|
||||
which encapsulates Nix more thoroughly and provides users with a simpler definition:
|
||||
you can consider using the following project, which encapsulates Nix more thoroughly and
|
||||
provides users with a simpler definition:
|
||||
|
||||
- [cachix/devenv](https://github.com/cachix/devenv)
|
||||
|
||||
If you don't want to write a single line of nix code and just want to get a reproducible development environment with minimal cost,
|
||||
here's a tool that might meet your needs:
|
||||
If you don't want to write a single line of nix code and just want to get a reproducible
|
||||
development environment with minimal cost, here's a tool that might meet your needs:
|
||||
|
||||
- [jetpack-io/devbox](https://github.com/jetpack-io/devbox)
|
||||
|
||||
## Dev Environment for Python
|
||||
|
||||
The development environment for Python is much more cumbersome compared to languages like Java or Go because it defaults to installing software in the global environment.
|
||||
To install software for the current project, you must create a virtual environment first (unlike in languages such as JavaScript or Go,
|
||||
where virtual environments are not necessary). This behavior is very unfriendly for Nix.
|
||||
The development environment for Python is much more cumbersome compared to languages like
|
||||
Java or Go because it defaults to installing software in the global environment. To
|
||||
install software for the current project, you must create a virtual environment first
|
||||
(unlike in languages such as JavaScript or Go, where virtual environments are not
|
||||
necessary). This behavior is very unfriendly for Nix.
|
||||
|
||||
By default, when using pip in Python, it installs software globally. On NixOS, running `pip install` directly will result in an error:
|
||||
By default, when using pip in Python, it installs software globally. On NixOS, running
|
||||
`pip install` directly will result in an error:
|
||||
|
||||
```bash
|
||||
› pip install -r requirements.txt
|
||||
@@ -41,38 +47,47 @@ note: If you believe this is a mistake, please contact your Python installation
|
||||
hint: See PEP 668 for the detailed specification.
|
||||
```
|
||||
|
||||
Based on the error message, `pip install` is directly disabled by NixOS. Even when attempting `pip install --user`, it is similarly disabled.
|
||||
To improve the reproducibility of the environment, Nix eliminates these commands altogether.
|
||||
Even if we create a new environment using methods like `mkShell`,
|
||||
these commands still result in errors (presumably because the pip command in Nixpkgs itself has
|
||||
been modified to prevent any modification instructions like `install` from running).
|
||||
Based on the error message, `pip install` is directly disabled by NixOS. Even when
|
||||
attempting `pip install --user`, it is similarly disabled. To improve the reproducibility
|
||||
of the environment, Nix eliminates these commands altogether. Even if we create a new
|
||||
environment using methods like `mkShell`, these commands still result in errors
|
||||
(presumably because the pip command in Nixpkgs itself has been modified to prevent any
|
||||
modification instructions like `install` from running).
|
||||
|
||||
However, many project installation scripts are based on pip, which means these scripts cannot be used directly.
|
||||
Additionally, the content in nixpkgs is limited, and many packages from PyPI are missing.
|
||||
This requires users to package them themselves, adding a lot of complexity and mental burden.
|
||||
However, many project installation scripts are based on pip, which means these scripts
|
||||
cannot be used directly. Additionally, the content in nixpkgs is limited, and many
|
||||
packages from PyPI are missing. This requires users to package them themselves, adding a
|
||||
lot of complexity and mental burden.
|
||||
|
||||
One solution is to use the `venv` virtual environment. Within a virtual environment, you can use commands like pip normally:
|
||||
One solution is to use the `venv` virtual environment. Within a virtual environment, you
|
||||
can use commands like pip normally:
|
||||
|
||||
```shell
|
||||
python -m venv ./env
|
||||
source ./env/bin/activate
|
||||
```
|
||||
|
||||
Alternatively, you can use a third-party tool called `virtualenv`, but this requires additional installation.
|
||||
Alternatively, you can use a third-party tool called `virtualenv`, but this requires
|
||||
additional installation.
|
||||
|
||||
For those who still lack confidence in the venv created directly with Python, they may prefer to include the virtual environment in `/nix/store` to make it immutable.
|
||||
This can be achieved by directly installing the dependencies from `requirements.txt` or `poetry.toml` using Nix.
|
||||
There are existing Nix packaging tools available to assist with this:
|
||||
For those who still lack confidence in the venv created directly with Python, they may
|
||||
prefer to include the virtual environment in `/nix/store` to make it immutable. This can
|
||||
be achieved by directly installing the dependencies from `requirements.txt` or
|
||||
`poetry.toml` using Nix. There are existing Nix packaging tools available to assist with
|
||||
this:
|
||||
|
||||
> Note that even in these environments, running commands like `pip install` directly will still fail.
|
||||
> Python dependencies must be installed through `flake.nix` because the data is located in the `/nix/store` directory,
|
||||
> and these modification commands can only be executed during the Nix build phase.
|
||||
> Note that even in these environments, running commands like `pip install` directly will
|
||||
> still fail. Python dependencies must be installed through `flake.nix` because the data
|
||||
> is located in the `/nix/store` directory, and these modification commands can only be
|
||||
> executed during the Nix build phase.
|
||||
|
||||
- [DavHau/mach-nix](https://github.com/DavHau/mach-nix) (currently unmaintained)
|
||||
- [poetry2nix](https://github.com/nix-community/poetry2nix)
|
||||
|
||||
The advantage of these tools is that they utilize the lock mechanism of Nix Flakes to improve reproducibility.
|
||||
However, the downside is that they add an extra layer of abstraction, making the underlying system more complex.
|
||||
The advantage of these tools is that they utilize the lock mechanism of Nix Flakes to
|
||||
improve reproducibility. However, the downside is that they add an extra layer of
|
||||
abstraction, making the underlying system more complex.
|
||||
|
||||
Finally, in some more complex projects, neither of the above solutions may be feasible.
|
||||
In such cases, the best solution is to use containers such as Docker or Podman. Containers have fewer restrictions compared to Nix and can provide the best compatibility.
|
||||
Finally, in some more complex projects, neither of the above solutions may be feasible. In
|
||||
such cases, the best solution is to use containers such as Docker or Podman. Containers
|
||||
have fewer restrictions compared to Nix and can provide the best compatibility.
|
||||
|
@@ -1,15 +1,26 @@
|
||||
# Distributed Building
|
||||
|
||||
Distributed building can significantly speed up the build process by utilizing multiple machines. However, for ordinary NixOS users, distributed building may not be very useful since `cache.nixos.org` provides a vast majority of caches for the `x86_64` architecture.
|
||||
Distributed building can significantly speed up the build process by utilizing multiple
|
||||
machines. However, for ordinary NixOS users, distributed building may not be very useful
|
||||
since `cache.nixos.org` provides a vast majority of caches for the `x86_64` architecture.
|
||||
|
||||
Distributed building is particularly valuable in scenarios where no cache is available, such as:
|
||||
Distributed building is particularly valuable in scenarios where no cache is available,
|
||||
such as:
|
||||
|
||||
1. Users of `RISC-V` or `ARM64` architectures, especially `RISC-V`, as there are very few caches for these architectures in the official cache repository. Local compilation is often required.
|
||||
2. Users who heavily customize their systems. The packages in the official cache repository are built with default configurations. If you modify the build parameters, the official cache is not applicable, and local compilation is necessary. For example, in embedded scenarios, customization of the underlying kernel, drivers, etc., is often required, leading to the need for local compilation.
|
||||
1. Users of `RISC-V` or `ARM64` architectures, especially `RISC-V`, as there are very few
|
||||
caches for these architectures in the official cache repository. Local compilation is
|
||||
often required.
|
||||
2. Users who heavily customize their systems. The packages in the official cache
|
||||
repository are built with default configurations. If you modify the build parameters,
|
||||
the official cache is not applicable, and local compilation is necessary. For example,
|
||||
in embedded scenarios, customization of the underlying kernel, drivers, etc., is often
|
||||
required, leading to the need for local compilation.
|
||||
|
||||
## Configuring Distributed Building
|
||||
|
||||
Currently, there is no official documentation for distributed building. However, I have provided a sample distributed build configuration (a NixOS module) below, along with some recommended reference documents at the end of this section.
|
||||
Currently, there is no official documentation for distributed building. However, I have
|
||||
provided a sample distributed build configuration (a NixOS module) below, along with some
|
||||
recommended reference documents at the end of this section.
|
||||
|
||||
```nix
|
||||
{ ... }: {
|
||||
@@ -129,9 +140,14 @@ Currently, there is no official documentation for distributed building. However,
|
||||
|
||||
Here are some observed issues and limitations:
|
||||
|
||||
1. You cannot specify which hosts to use at build time. You can only specify a list of hosts in the configuration file, and Nix automatically selects available hosts.
|
||||
2. When choosing a host, Nix always prefers the remote host over the local host, even if the local host has better performance. This can result in underutilization of the local host's CPU.
|
||||
3. The smallest unit of distributed building is a derivation. When building large packages, other machines may remain idle for a long time, waiting for the large package to be built. This can lead to resource wastage.
|
||||
1. You cannot specify which hosts to use at build time. You can only specify a list of
|
||||
hosts in the configuration file, and Nix automatically selects available hosts.
|
||||
2. When choosing a host, Nix always prefers the remote host over the local host, even if
|
||||
the local host has better performance. This can result in underutilization of the local
|
||||
host's CPU.
|
||||
3. The smallest unit of distributed building is a derivation. When building large
|
||||
packages, other machines may remain idle for a long time, waiting for the large package
|
||||
to be built. This can lead to resource wastage.
|
||||
|
||||
## References
|
||||
|
||||
|
@@ -1,16 +1,23 @@
|
||||
# Development Environments on NixOS
|
||||
|
||||
NixOS's reproducibility makes it ideal for building development environments. However, if you're used to other distros, you may encounter problems because NixOS has its own logic. We'll briefly explain this below.
|
||||
NixOS's reproducibility makes it ideal for building development environments. However, if
|
||||
you're used to other distros, you may encounter problems because NixOS has its own logic.
|
||||
We'll briefly explain this below.
|
||||
|
||||
On NixOS, it's recommended to only install common tools in the global environment, such as `git`, `vim`, `emacs`, `tmux`, `zsh`, etc. The development environment of each language should be an independent environment for each project.
|
||||
On NixOS, it's recommended to only install common tools in the global environment, such as
|
||||
`git`, `vim`, `emacs`, `tmux`, `zsh`, etc. The development environment of each language
|
||||
should be an independent environment for each project.
|
||||
|
||||
You should NOT install the development environment of each language in the global environment. The project environment should be completely isolated from each other and will not affect each other.
|
||||
You should NOT install the development environment of each language in the global
|
||||
environment. The project environment should be completely isolated from each other and
|
||||
will not affect each other.
|
||||
|
||||
In the following sections, we'll introduce how the development environment works in NixOS.
|
||||
|
||||
## Creating a Custom Shell Environment with `nix shell`
|
||||
|
||||
The simplest way to create a development environment is to use `nix shell`. `nix shell` will create a shell environment with the specified Nix package installed.
|
||||
The simplest way to create a development environment is to use `nix shell`. `nix shell`
|
||||
will create a shell environment with the specified Nix package installed.
|
||||
|
||||
Here's an example:
|
||||
|
||||
@@ -38,15 +45,19 @@ Hello, world!
|
||||
|| ||
|
||||
```
|
||||
|
||||
`nix shell` is very useful when you just want to try out some packages or quickly create a clean environment.
|
||||
`nix shell` is very useful when you just want to try out some packages or quickly create a
|
||||
clean environment.
|
||||
|
||||
## Creating a Development Environment
|
||||
|
||||
`nix shell` is simple and easy to use, but it's not very flexible, for a more complex development environment, we need to use `pkgs.mkShell` and `nix develop`.
|
||||
`nix shell` is simple and easy to use, but it's not very flexible, for a more complex
|
||||
development environment, we need to use `pkgs.mkShell` and `nix develop`.
|
||||
|
||||
We can create a development environment using `pkgs.mkShell { ... }` and open an interactive Bash shell of this development environment using `nix develop`.
|
||||
We can create a development environment using `pkgs.mkShell { ... }` and open an
|
||||
interactive Bash shell of this development environment using `nix develop`.
|
||||
|
||||
To see how `pkgs.mkShell` works, let's take a look at [its source code](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/build-support/mkshell/default.nix).
|
||||
To see how `pkgs.mkShell` works, let's take a look at
|
||||
[its source code](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/build-support/mkshell/default.nix).
|
||||
|
||||
```nix
|
||||
{ lib, stdenv, buildEnv }:
|
||||
@@ -101,7 +112,9 @@ stdenv.mkDerivation ({
|
||||
} // rest)
|
||||
```
|
||||
|
||||
`pkgs.mkShell { ... }` is a special derivation (Nix package). Its `name`, `buildInputs`, and other parameters are customizable, and `shellHook` is a special parameter that will be executed when `nix develop` enters the environment.
|
||||
`pkgs.mkShell { ... }` is a special derivation (Nix package). Its `name`, `buildInputs`,
|
||||
and other parameters are customizable, and `shellHook` is a special parameter that will be
|
||||
executed when `nix develop` enters the environment.
|
||||
|
||||
Here is a `flake.nix` that defines a development environment with Node.js 18 installed:
|
||||
|
||||
@@ -138,11 +151,14 @@ Here is a `flake.nix` that defines a development environment with Node.js 18 ins
|
||||
}
|
||||
```
|
||||
|
||||
Create an empty folder, save the above configuration as `flake.nix`, and then execute `nix develop` (or more precisely, you can use `nix develop .#default`), the current version of nodejs will be outputted, and now you can use `node` `pnpm` `yarn` seamlessly.
|
||||
Create an empty folder, save the above configuration as `flake.nix`, and then execute
|
||||
`nix develop` (or more precisely, you can use `nix develop .#default`), the current
|
||||
version of nodejs will be outputted, and now you can use `node` `pnpm` `yarn` seamlessly.
|
||||
|
||||
## Using zsh/fish/... instead of bash
|
||||
|
||||
`pkgs.mkShell` uses `bash` by default, but you can also use `zsh` or `fish` by add `exec <your-shell>` into `shellHook`.
|
||||
`pkgs.mkShell` uses `bash` by default, but you can also use `zsh` or `fish` by add
|
||||
`exec <your-shell>` into `shellHook`.
|
||||
|
||||
Here is an example:
|
||||
|
||||
@@ -185,11 +201,15 @@ With the above configuration, `nix develop` will enter the REPL environment of n
|
||||
|
||||
## Creating a Development Environment with `pkgs.runCommand`
|
||||
|
||||
The derivation created by `pkgs.mkShell` cannot be used directly, but must be accessed via `nix develop`.
|
||||
The derivation created by `pkgs.mkShell` cannot be used directly, but must be accessed via
|
||||
`nix develop`.
|
||||
|
||||
It is actually possible to create a shell wrapper containing the required packages via `pkgs.stdenv.mkDerivation`, which can then be run directly into the environment by executing the wrapper.
|
||||
It is actually possible to create a shell wrapper containing the required packages via
|
||||
`pkgs.stdenv.mkDerivation`, which can then be run directly into the environment by
|
||||
executing the wrapper.
|
||||
|
||||
Using `mkDerivation` directly is a bit cumbersome, and Nixpkgs provides some simpler functions to help us create such wrappers, such as `pkgs.runCommand`.
|
||||
Using `mkDerivation` directly is a bit cumbersome, and Nixpkgs provides some simpler
|
||||
functions to help us create such wrappers, such as `pkgs.runCommand`.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -229,11 +249,15 @@ Example:
|
||||
}
|
||||
```
|
||||
|
||||
Then execute `nix run .#dev` or `nix shell .#dev --command 'dev-shell'`, you will enter a nushell session, where you can use the `node` `pnpm` command normally, and the node version is 20.
|
||||
Then execute `nix run .#dev` or `nix shell .#dev --command 'dev-shell'`, you will enter a
|
||||
nushell session, where you can use the `node` `pnpm` command normally, and the node
|
||||
version is 20.
|
||||
|
||||
The wrapper generated in this way is an executable file, which does not actually depend on the `nix run` or `nix shell` command.
|
||||
The wrapper generated in this way is an executable file, which does not actually depend on
|
||||
the `nix run` or `nix shell` command.
|
||||
|
||||
For example, we can directly install this wrapper through NixOS's `environment.systemPackages`, and then execute it directly:
|
||||
For example, we can directly install this wrapper through NixOS's
|
||||
`environment.systemPackages`, and then execute it directly:
|
||||
|
||||
```nix
|
||||
{pkgs, lib, ...}{
|
||||
@@ -260,7 +284,10 @@ For example, we can directly install this wrapper through NixOS's `environment.s
|
||||
}
|
||||
```
|
||||
|
||||
Add the above configuration to any NixOS Module, then deploy it with `sudo nixos-rebuild switch`, and you can enter the development environment directly with the `dev-shell` command, which is the special feature of `pkgs.runCommand` compared to `pkgs.mkShell`.
|
||||
Add the above configuration to any NixOS Module, then deploy it with
|
||||
`sudo nixos-rebuild switch`, and you can enter the development environment directly with
|
||||
the `dev-shell` command, which is the special feature of `pkgs.runCommand` compared to
|
||||
`pkgs.mkShell`.
|
||||
|
||||
Related source code:
|
||||
|
||||
@@ -269,7 +296,8 @@ Related source code:
|
||||
|
||||
## Enter the build environment of any Nix package
|
||||
|
||||
Now let's take a look at `nix develop`, first read the help document output by `nix develop --help`:
|
||||
Now let's take a look at `nix develop`, first read the help document output by
|
||||
`nix develop --help`:
|
||||
|
||||
```
|
||||
Name
|
||||
@@ -280,20 +308,25 @@ Synopsis
|
||||
# ......
|
||||
```
|
||||
|
||||
It tells us that `nix develop` accepts a parameter `installable`, which means that we can enter the development environment of any installable Nix package through it, not just the environment created by `pkgs.mkShell`.
|
||||
It tells us that `nix develop` accepts a parameter `installable`, which means that we can
|
||||
enter the development environment of any installable Nix package through it, not just the
|
||||
environment created by `pkgs.mkShell`.
|
||||
|
||||
By default, `nix develop` will try to use the following attributes in the flake outputs:
|
||||
|
||||
- `devShells.<system>.default`
|
||||
- `packages.<system>.default`
|
||||
|
||||
If we use `nix develop /path/to/flake#<name>` to specify the flake package address and flake output name, then `nix develop` will try the following attributes in the flake outputs:
|
||||
If we use `nix develop /path/to/flake#<name>` to specify the flake package address and
|
||||
flake output name, then `nix develop` will try the following attributes in the flake
|
||||
outputs:
|
||||
|
||||
- `devShells.<system>.<name>`
|
||||
- `packages.<system>.<name>`
|
||||
- `legacyPackages.<system>.<name>`
|
||||
|
||||
Now let's try it out. First, test it to confirm that We don't have `c++` `g++` and other compilation-related commands in the current environment:
|
||||
Now let's try it out. First, test it to confirm that We don't have `c++` `g++` and other
|
||||
compilation-related commands in the current environment:
|
||||
|
||||
```shell
|
||||
ryan in 🌐 aquamarine in ~
|
||||
@@ -331,11 +364,13 @@ This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
```
|
||||
|
||||
We can see that the `CXX` environment variable have been set, and the `c++` `g++` and other commands can be used normally now.
|
||||
We can see that the `CXX` environment variable have been set, and the `c++` `g++` and
|
||||
other commands can be used normally now.
|
||||
|
||||
In addition, we can also call every build phase of the `hello` package normally:
|
||||
|
||||
> The default execution order of all build phases of a Nix package is: `$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`
|
||||
> The default execution order of all build phases of a Nix package is:
|
||||
> `$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`
|
||||
|
||||
```shell
|
||||
# unpack source code
|
||||
@@ -393,11 +428,13 @@ ryan in 🌐 aquamarine in /tmp/xxx/hello-2.12.1 via C v12.3.0-gcc via ❄️ i
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
This usage is mainly used to debug the build process of a Nix package, or to execute some commands in the build environment of a Nix package.
|
||||
This usage is mainly used to debug the build process of a Nix package, or to execute some
|
||||
commands in the build environment of a Nix package.
|
||||
|
||||
## `nix build`
|
||||
|
||||
The `nix build` command is used to build a software package and creates a symbolic link named `result` in the current directory, which points to the build result.
|
||||
The `nix build` command is used to build a software package and creates a symbolic link
|
||||
named `result` in the current directory, which points to the build result.
|
||||
|
||||
Here's an example:
|
||||
|
||||
@@ -434,16 +471,21 @@ nix build "nixpkgs#ponysay"
|
||||
|
||||
## Using `nix profile` to manage development environments and entertainment environments
|
||||
|
||||
`nix develop` is a tool for creating and managing multiple user environments, and switch to different environments when needed.
|
||||
`nix develop` is a tool for creating and managing multiple user environments, and switch
|
||||
to different environments when needed.
|
||||
|
||||
Unlike `nix develop`, `nix profile` manages the user's system environment, instead of creating a temporary shell environment.
|
||||
So it's more compatible with Jetbrains IDE / VSCode and other IDEs, and won't have the problem of not being able to use the configured development environment in the IDE.
|
||||
Unlike `nix develop`, `nix profile` manages the user's system environment, instead of
|
||||
creating a temporary shell environment. So it's more compatible with Jetbrains IDE /
|
||||
VSCode and other IDEs, and won't have the problem of not being able to use the configured
|
||||
development environment in the IDE.
|
||||
|
||||
TODO
|
||||
|
||||
## Other Commands
|
||||
|
||||
There are other commands like `nix flake init`, which you can explore in [New Nix Commands][New Nix Commands]. For more detailed information, please refer to the documentation.
|
||||
There are other commands like `nix flake init`, which you can explore in [New Nix
|
||||
Commands][New Nix Commands]. For more detailed information, please refer to the
|
||||
documentation.
|
||||
|
||||
## References
|
||||
|
||||
|
@@ -105,10 +105,14 @@ An example of kernel development with `flake.nix`.
|
||||
}
|
||||
```
|
||||
|
||||
With the above `flake.nix`, I can enter the kernel build environment with `nix develop .#kernel`, and then use `unpackPhase` to unpack the kernel source code and cd into it.
|
||||
But I can't use `make menuconfig` to configure the kernel, because the `ncurses` package is missing in this environment.
|
||||
With the above `flake.nix`, I can enter the kernel build environment with
|
||||
`nix develop .#kernel`, and then use `unpackPhase` to unpack the kernel source code and cd
|
||||
into it. But I can't use `make menuconfig` to configure the kernel, because the `ncurses`
|
||||
package is missing in this environment.
|
||||
|
||||
To solve this problem, I add a `fhs` environment to install the `ncurses` package and other necessary packages, and then I can use `nix develop .#fhs` to enter this environment and use `make menuconfig` to configure the kernel.
|
||||
To solve this problem, I add a `fhs` environment to install the `ncurses` package and
|
||||
other necessary packages, and then I can use `nix develop .#fhs` to enter this environment
|
||||
and use `make menuconfig` to configure the kernel.
|
||||
|
||||
## References
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# Packging 101
|
||||
|
||||
WIP work in progress, please refer to the following reference documents to learn Nix packaging.
|
||||
WIP work in progress, please refer to the following reference documents to learn Nix
|
||||
packaging.
|
||||
|
||||
## 参考文档
|
||||
|
||||
@@ -10,11 +11,15 @@ WIP work in progress, please refer to the following reference documents to learn
|
||||
- [languages-frameworks - Nixpkgs Manual](https://github.com/NixOS/nixpkgs/tree/nixos-unstable/doc/languages-frameworks)
|
||||
- [Wrapping packages - NixOS Cookbook](https://nixos.wiki/wiki/Nix_Cookbook#Wrapping_packages)
|
||||
- Useful tools:
|
||||
- [nurl](https://github.com/nix-community/nurl): Generate Nix fetcher calls from repository URLs
|
||||
- [nix-init](https://github.com/nix-community/nix-init): Generate Nix packages from URLs with hash prefetching, dependency inference, license detection, and more
|
||||
- [nurl](https://github.com/nix-community/nurl): Generate Nix fetcher calls from
|
||||
repository URLs
|
||||
- [nix-init](https://github.com/nix-community/nix-init): Generate Nix packages from URLs
|
||||
with hash prefetching, dependency inference, license detection, and more
|
||||
- Source Code:
|
||||
- [pkgs/build-support/trivial-builders/default.nix - runCommand](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/trivial-builders/default.nix#L21-L49)
|
||||
- [pkgs/build-support/setup-hooks/make-wrapper.sh](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/setup-hooks/make-wrapper.sh)
|
||||
- FHS related
|
||||
- [pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix): `pkgs.buildFHSEnvBubblewrap`
|
||||
- [pkgs/build-support/build-fhsenv-chroot/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix): `pkgs.buildFHSEnvChroot`
|
||||
- [pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix):
|
||||
`pkgs.buildFHSEnvBubblewrap`
|
||||
- [pkgs/build-support/build-fhsenv-chroot/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix):
|
||||
`pkgs.buildFHSEnvChroot`
|
||||
|
Reference in New Issue
Block a user