nixos-and-flakes-book/docs/nixpkgs/overlays.md
2024-01-11 11:40:44 +08:00

172 lines
5.9 KiB
Markdown

# Overlays
In the previous section, we learned about overriding derivations using the `override` keyword. However, this approach only affects the local derivation and doesn't modify the original derivation in `pkgs`. To globally modify derivations in `pkgs`, Nix provides a feature called "overlays".
In traditional Nix environments, overlays can be configured globally using the `~/.config/nixpkgs/overlays.nix` or `~/.config/nixpkgs/overlays/*.nix` files. However, in Flakes, to ensure system reproducibility, overlays cannot rely on configurations outside of the Git repository.
When using Flakes to configure NixOS, both Home Manager and NixOS provide the `nixpkgs.overlays` option to define overlays. You can refer to the following documentation for more details:
- [Home Manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.xhtml#opt-nixpkgs.overlays)
- [Nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169)
Let's take a look at an example module that loads overlays. This module can be used as a Home Manager module or a NixOS module, as the definitions are the same:
```nix
{ config, pkgs, lib, ... }:
{
nixpkgs.overlays = [
# Overlay 1: Use `self` and `super` to express
# the inheritance relationship
(self: super: {
google-chrome = super.google-chrome.override {
commandLineArgs =
"--proxy-server='https=127.0.0.1:3128;http=127.0.0.1:3128'";
};
})
# Overlay 2: Use `final` and `prev` to express
# the relationship between the new and the old
(final: prev: {
steam = prev.steam.override {
extraPkgs = pkgs: with pkgs; [
keyutils
libkrb5
libpng
libpulseaudio
libvorbis
stdenv.cc.cc.lib
xorg.libXcursor
xorg.libXi
xorg.libXinerama
xorg.libXScrnSaver
];
extraProfile = "export GDK_SCALE=2";
};
})
# Overlay 3: Define overlays in other files
# The content of overlay3.nix is the same as above:
# `(final: prev: { xxx = prev.xxx.override { ... }; })`
(import ./overlays/overlay3.nix)
];
}
```
In the above example, we define three overlays. Overlay 1 modifies the `google-chrome` derivation by adding a command-line argument for a proxy server. Overlay 2 modifies the `steam` derivation by adding extra packages and an environment variable. Overlay 3 is defined in a separate file `overlay3.nix`.
You can write your own overlays following this example. Import the configuration as a NixOS module or a Home Manager module, and then deploy it to see the effect.
## Modular overlays
In the previous example, all overlays were written in a single Nix file, which can become difficult to maintain over time. To address this, we can manage overlays in a modular way.
Start by creating an `overlays` folder in your Git repository to store all overlay configurations. Inside this folder, create a `default.nix` file with the following content:
```nix
# import all nix files in the current folder,
# and execute them with args as parameters
# The return value is a list of all execution results,
# which is the list of overlays
args:
# execute and import all overlay files in the current
# directory with the given args
builtins.map
# execute and import the overlay file
(f: (import (./. + "/${f}") args))
# find all overlay files in the current directory
(builtins.filter
(f: f != "default.nix")
(builtins.attrNames (builtins.readDir ./.)))
```
The `default.nix` file imports and executes all Nix files in the current folder (excluding `default.nix`) with the provided arguments. It returns a list of all overlay results.
Next, write your overlay configurations in the `overlays` folder. For example, you can create `overlays/fcitx5/default.nix` with the following content:
```nix
{ pkgs, config, lib, ... }:
(self: super: {
# Customized rime-data package
rime-data = ./rime-data-flypy;
fcitx5-rime = super.fcitx5-rime.override {
rimeDataPkgs = [ ./rime-data-flypy ];
};
})
```
In the above example, we override the `rime-data` package with a custom version and modify the `fcitx5-rime` derivation to use the custom `rime-data` package.
To load all overlays returned by `overlays/default.nix`, add the following parameter to any NixOS module:
```nix
{ config, pkgs, lib, ... } @ args:
{
# ...
nixpkgs.overlays = import /path/to/overlays/dir;
# ...
}
```
For instance, you can add it directly in `flake.nix`:
```nix
{
description = "NixOS configuration of Ryan Yin";
# ...
inputs = {
# ...
};
outputs = inputs@{ self, nixpkgs, ... }:
{
nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = inputs;
modules = [
./hosts/nixos-test
# add the following inline module definition
# here, all parameters of modules are passed to overlays
(args: { nixpkgs.overlays = import ./overlays args; })
# ...
];
};
};
};
}
```
By using this modular approach, you can conveniently organize and manage your overlays. In this example, the structure of the `overlays` folder would look like this:
```txt
.
├── flake.lock
├── flake.nix
├── home
├── hosts
├── modules
├── ...
├── overlays
│ ├── default.nix # return a list of all overlays.
│ └── fcitx5 # fcitx5 overlay
│ ├── default.nix
│ ├── README.md
│ └── rime-data-flypy # my custom rime-data
│ └── share
│ └── rime-data
│ ├── ...
└── README.md
```
This modular approach simplifies the management of overlays and allows you to easily add, modify, or remove overlays as needed.