Merge pull request #84 from ryan4yin/fix-overlays

fix: https://github.com/ryan4yin/nixos-and-flakes-book/issues/83
This commit is contained in:
Ryan Yin 2024-02-12 17:29:32 +08:00 committed by GitHub
commit ea5cf90ff1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 69 additions and 206 deletions

View file

@ -5,7 +5,7 @@ In the section [Downgrade or Upgrade Packages](/nixos-with-flakes/downgrade-or-u
1. Instantiate nixpkgs instances with different commit IDs to install various versions of software packages. This approach was used in the previous section [Downgrade or Upgrade Packages](/nixos-with-flakes/downgrade-or-upgrade-packages.md).
2. If you wish to utilize overlays without affecting the default nixpkgs instance, you can instantiate a new nixpkgs instance and apply overlays to it.
- The `nixpkgs.overlays = [...];` mentioned in the previous section on Overlays directly modifies the global nixpkgs instance. If your overlays make changes to fundamental packages, it might impact other modules. One downside is an increase in local compilation (due to cache invalidation), and there might also be functionality issues with the affected packages.
- The `nixpkgs.overlays = [...];` mentioned in the previous section on Overlays directly modifies the global nixpkgs instance. If your overlays make changes to some low-level packages, it might impact other modules. One downside is an increase in local compilation (due to cache invalidation), and there might also be functionality issues with the affected packages.
3. In cross-system architecture compilation, you can instantiate multiple nixpkgs instances to selectively use QEMU simulation for compilation and cross-compilation in different locations, or to add various GCC compilation parameters.

View file

@ -1,10 +1,13 @@
# 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 the previous section, we learned about overriding derivations using the `override` function.
However, this approach will generate a new derivation and doesn't modify the original derivation in `pkgs` instance.
To globally modify derivations in the detault `pkgs` instance, 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.
In traditional Nix environments, overlays can be configured globally using the `~/.config/nixpkgs/overlays.nix` or `~/.config/nixpkgs/overlays/*.nix` files.
However, with Flakes feature, 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:
When using `flake.nix` 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)
@ -12,6 +15,7 @@ When using Flakes to configure NixOS, both Home Manager and NixOS provide the `n
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
# ./overlays/default.nix
{ config, pkgs, lib, ... }:
{
@ -46,126 +50,56 @@ Let's take a look at an example module that loads overlays. This module can be u
})
# Overlay 3: Define overlays in other files
# The content of overlay3.nix is the same as above:
# The content of ./overlay3/default.nix is the same as above:
# `(final: prev: { xxx = prev.xxx.override { ... }; })`
(import ./overlays/overlay3.nix)
(import ./overlay3)
];
}
```
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`.
In the above example, we define three overlays.
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.
1. Overlay 1 modifies the `google-chrome` derivation by adding a command-line argument for a proxy server.
2. Overlay 2 modifies the `steam` derivation by adding extra packages and environment variables.
3. Overlay 3 is defined in a separate file `./overlay3/default.nix`.
## 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:
One example of importing the above configuration as a NixOS module is as follows:
```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:
# ./flake.nix
{
# ...
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; })
# ...
];
};
outputs = inputs@{ nixpkgs, ... }: {
nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
# import the module that contains our overlays
(import ./overlays)
];
};
};
};
}
```
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:
This is just an example. Please write your own overlays according to your needs.
```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.
## Multiple `nixpkgs` Instances with different Overlays
The `nixpkgs.overlays = [...];` mentioned above directly modifies the global nixpkgs instance `pkgs`. If your overlays make changes to some low-level packages, it might impact other modules.
One downside is an increase in local compilation (due to cache invalidation),
and there might also be functionality issues with the affected packages.
If you wish to utilize overlays only in a specific location without affecting the default nixpkgs instance, you can instantiate a new nixpkgs instance and apply your overlays to it.
We will discuss how to do this in the next section [The Ingenious Uses of Multiple nixpkgs Instances](./multiple-nixpkgs.md).
## References
- [Chapter 3. Overlays - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays)

View file

@ -1,15 +1,16 @@
# Overlays
前面介绍的 override 函数都会生成新的 Derivation不影响 pkgs 中原有的 Derivation只适合作为局部参数使用。
但如果你需要覆写的 Derivation 还被其他 Nix 包所依赖,那其他 Nix 包使用的仍然会是原有的 Derivation.
前面介绍的 override 函数会生成一个新的 Derivation因此它不会修改 pkgs 实例中原有的 Derivation只适合作为局部参数使用。
但如果你需要覆写的 Derivation 还被其他 Nix 包所依赖,那其他 Nix 包使用的仍然会是未被修改的 Derivation.
为了解决这个问题Nix 提供了 overlays 能力。简单的说Overlays 可以全局修改 pkgs 中的 Derivation。
为了解决这个问题Nix 提供了 overlays 这个功能。
简单的说Overlays 可以全局修改 pkgs 中的 Derivation.
旧的 Nix 环境中Nix 默认会自动应`~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix` 这类路径下的所有 overlays 配置。
传统的 Nix 环境中Nix 默认会自动使`~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix` 这类路径下的所有 overlays 配置。
但是在 Flakes 中,为了确保系统的可复现性,它不能依赖任何 Git 仓库之外的配置,所以这种旧的方法就不能用了。
但是在使用了 Flakes 特性后为了确保系统的可复现性Flake 不能依赖任何 Git 仓库之外的配置,所以这种旧的配置方式就不再适用了。
在使用 Nix Flakes 编写 NixOS 配置Home Manager 与 NixOS 都提供了 `nixpkgs.overlays` 这个 option 来引入 overlays, 相关文档:
在使用 `flake.nix` 配置你的 NixOS Home Manager 与 NixOS 都提供了 `nixpkgs.overlays` 这个 option 来引入 overlays, 相关文档:
- [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)
@ -19,6 +20,7 @@
> 不过我使用发现Home Manager 毕竟是个外部组件,而且现在全都用的 unstable 分支,这导致 Home Manager Module 有时候会有点小毛病,因此更建议以 NixOS Module 的形式引入 overlays
```nix
# ./overlays/default.nix
{ config, pkgs, lib, ... }:
{
@ -53,96 +55,37 @@
})
# overlay3 - 也可以将 overlay 定义在其他文件中
# 这里 overlay3.nix 中的内容格式与上面的一致
# 这里 ./overlay3/default.nix 中的内容格式与上面的一致
# 都是 `final: prev: { xxx = prev.xxx.override { ... }; }`
(import ./overlays/overlay3.nix)
(import ./overlay3)
];
}
```
这里只是个示例配置,参照此格式编写你自己的 overlays 配置,将该配置作为 NixOS Module 或者 Home Manager Module 引入,然后部署就可以看到效果了。
上面的例子中,我们定义了三个 overlays:
## 模块化 overlays 配置
1. Overlay 1 修改了 `google-chrome` 的 Derivation增加了一个代理服务器的命令行参数。
2. Overlay 2 修改了 `steam` 的 Derivation增加了额外的包和环境变量。
3. Overlay 3 被定义在一个单独的文件 `./overlay3/default.nix` 中。
上面的例子说明了如何编写 overlays但是所有 overlays 都一股脑儿写在一起,就有点难以维护了,写得多了自然就希望模块化管理这些 overlays.
这里介绍下我找到的一个 overlays 模块化管理的最佳实践。
首先在 Git 仓库中创建 `overlays` 文件夹用于存放所有 overlays 配置,然后创建 `overlays/default.nix`,其内容如下:
一个将上述配置作为 NixOS Module 引入的 `flake.nix` 示例如下:
```nix
args:
# import 当前文件夹下所有的 nix 文件,并以 args 为参数执行它们
# 返回值是一个所有执行结果的列表,也就是 overlays 的列表
builtins.map
# map 的第一个参数,是一个 import 并执行 nix 文件的函数
(f: (import (./. + "/${f}") args))
# map 的第二个参数,它返回一个当前文件夹下除 default.nix 外所有 nix 文件的列表
(builtins.filter
(f: f != "default.nix")
(builtins.attrNames (builtins.readDir ./.)))
```
后续所有 overlays 配置都添加到 `overlays` 文件夹中,一个示例配置 `overlays/fcitx5/default.nix` 内容如下:
> 这里参考了 https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix
```nix
# 为了不使用默认的 rime-data改用我自定义的小鹤音形数据这里需要 override
{pkgs, config, lib, ...}:
(self: super: {
# 小鹤音形配置,配置来自 flypy.com 官方网盘的
# 鼠须管配置压缩包「小鹤音形“鼠须管”for macOS.zip」
rime-data = ./rime-data-flypy;
fcitx5-rime = super.fcitx5-rime.override {
rimeDataPkgs = [ ./rime-data-flypy ];
};
})
```
我通过上面这个 overlays 修改了 fcitx5-rime 输入法的默认数据,加载了我自定义的小鹤音形输入法。
最后,还需要通过 `nixpkgs.overlays` 这个 option 加载 `overlays/default.nix` 返回的所有 overlays 配置,在任一 NixOS Module 中添加如下参数即可:
```nix
{ config, pkgs, lib, ... } @ args:
# ./flake.nix
{
# ......
# 添加此参数
nixpkgs.overlays = import /path/to/overlays/dir;
# ......
}
```
比如说直接写 `flake.nix` 里:
```nix
{
description = "NixOS configuration of Ryan Yin";
# ......
inputs = {
# ......
# ...
};
outputs = inputs@{ self, nixpkgs, ... }: {
outputs = inputs@{ nixpkgs ... }: {
nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = inputs;
modules = [
./hosts/nixos-test
# 添加如下内嵌 module 定义
# 这里将 modules 的所有参数 args 都传递到了 overlays 中
(args: { nixpkgs.overlays = import ./overlays args; })
# ......
./configuration.nix
# 引入 overlays Module
(import ./overlays)
];
};
};
@ -150,29 +93,15 @@ args:
}
```
按照上述方法进行配置,就可以很方便地模块化管理所有 overlays 配置了以我的配置为例overlays 文件夹的结构大致如下:
这里只是个示例配置,实际使用时,请根据你自己的需求来编写 overlays 配置。
```nix
.
├── flake.lock
├── flake.nix
├── home
├── hosts
├── modules
├── ......
├── overlays
│ ├── default.nix # 它返回一个所有 overlays 的列表
│ └── fcitx5 # fcitx5 overlay
│ ├── default.nix
│ ├── README.md
│ └── rime-data-flypy # 自定义的 rime-data需要遵循它的文件夹格式
│ └── share
│ └── rime-data
│ ├── ...... # rime-data 文件
└── README.md
```
## 多个使用不同 overlays 的 Nixpkgs 实例
上面介绍的 `nixpkgs.overlays = [...];` 是直接修改全局的默认 nixpkgs 实例,如果你的 overlays 改了比较底层的包,可能会影响到其他模块。坏处之一是会导致大量的本地编译(因为二进制缓存失效了),二是被影响的包功能可能也会出问题。
如果你只是想在某个地方使用 overlays而不想影响到全局的 nixpkgs 实例,可以通过实例化多个 nixpkgs 实例来实现。
下一节 [多 nixpkgs 实例的妙用](./multiple-nixpkgs.md) 将会介绍如何做到这一点。
你可以在我的配置仓库 [ryan4yin/nix-config/v0.0.4](https://github.com/ryan4yin/nix-config/tree/v0.0.4) 查看更详细的内容,获取些灵感。
## 参考