feat: finish 'nixpkgs's advanced usage'

This commit is contained in:
Ryan Yin 2023-06-23 22:19:10 +08:00
parent 6187bbd9b7
commit 9db31c0d59
11 changed files with 595 additions and 605 deletions

View file

@ -74,6 +74,15 @@ export default defineConfig({
},
],
},
{
text: "Nixpkgs's Advanced Usage",
items: [
{ text: "Introduction", link: "/nixpkgs/intro.md" },
{ text: "callPackage", link: "/nixpkgs/callpackage.md" },
{ text: "Overridding", link: "/nixpkgs/override.md" },
{ text: "Overlays", link: "/nixpkgs/overlays.md" },
],
},
],
socialLinks: [
@ -160,7 +169,12 @@ export default defineConfig({
},
{
text: "Nixpkgs 高级用法",
items: [{ text: "快速入门", link: "/zh/nixpkgs/index.md" }],
items: [
{ text: "Introduction", link: "/zh/nixpkgs/intro.md" },
{ text: "callPackage", link: "/zh/nixpkgs/callpackage.md" },
{ text: "Overridding", link: "/zh/nixpkgs/override.md" },
{ text: "Overlays", link: "/zh/nixpkgs/overlays.md" },
],
},
{
text: "NixOS 最佳实践",

View file

@ -0,0 +1,16 @@
In the previous content, We have used `import xxx.nix` to import Nix files many times, this syntax simply returns the execution result of the file, without any further processing of the it.
`pkgs.callPackage` is also used to import Nix files, its syntax is `pkgs.callPackage xxx.nix { ... }`, but unlike `import`, the Nix file imported by it must be a Derivation or a function that returns a Derivation. Its result is a Derivation(a software package) too.
So what does the Nix file that can be used as a parameter of `pkgs.callPackge` look like? You can take a look at the `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix` we mentioned earlier, they can all be imported by `pkgs.callPackage`.
When the `xxx.nix` used in `pkgs.callPackge xxx.nix {...}` is a function (most Nix packages are like this), the execution flow is as follows:
1. `pkgs.callPackge xxx.nix {...}` will first `import xxx.nix` to get the function defined in it. The parameters of this function usually have `lib`, `stdenv`, `fetchurl` and other parameters, as well as some custom parameters, which usually have default values.
2. Then `pkgs.callPackge` will first look up the value matching the name from the current environment as the parameter to be passed to the function. parameters like `lib` `stdenv` `fetchurl` are defined in nixpkgs, and they will be found in this step.
3. Then `pkgs.callPackge` will merge its second parameter `{...}` with the attribute set obtained in the previous step, and then pass it to the function imported from `xxx.nix` and execute it.
4. Finally we get a Derivation as the result of the function execution.
So the common usage of `pkgs.callPackage` is to import custom Nix packages and used it in Nix Module.
For example, we wrote a `hello.nix` ourselves, and then we can use `pkgs.callPackage ./hello.nix {}` in any Nix Module to import and use it.

View file

@ -1,309 +0,0 @@
## VIII. Nixpkgs's Advanced Usage
`callPackage`, `Overriding`, and `Overlays` are the techniques occasionally used when using Nix to customize the build method of Nix packages.
We know that many programs have a large number of build parameters that need to be configured, and different users may want to use different build parameters. This is where `Overriding` and `Overlays` come in handy. Let me give you a few examples I have encountered:
1. [`fcitx5-rime.nix`](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): By default, `fcitx5-rime` use `rime-data` as the value of `rimeDataPkgs`, but this parameter can be customized by `override`.
2. [`vscode/with-extensions.nix`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vscode/with-extensions.nix): This package for VS Code can also be customized by overriding the value of `vscodeExtensions`, thus we can install some custom plugins into VS Code.
- [`nix-vscode-extensions`](https://github.com/nix-community/nix-vscode-extensions): This is a vscode plugin manager implemented by overriding `vscodeExtensions`.
3. [`firefox/common.nix`](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): Firefox has many customizable parameters too.
4. ...
In short, `Overriding` or `Overlays` can be used to customize the build parameters of Nix packages.
### 1. pkgs.callPackage {#callpackage}
> [Chapter 13. Callpackage Design Pattern - Nix Pills](https://nixos.org/guides/nix-pills/callpackage-design-pattern.html)
In the previous content, We have used `import xxx.nix` to import Nix files many times, this syntax simply returns the execution result of the file, without any further processing of the it.
`pkgs.callPackage` is also used to import Nix files, its syntax is `pkgs.callPackage xxx.nix { ... }`, but unlike `import`, the Nix file imported by it must be a Derivation or a function that returns a Derivation. Its result is a Derivation(a software package) too.
So what does the Nix file that can be used as a parameter of `pkgs.callPackge` look like? You can take a look at the `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix` we mentioned earlier, they can all be imported by `pkgs.callPackage`.
When the `xxx.nix` used in `pkgs.callPackge xxx.nix {...}` is a function (most Nix packages are like this), the execution flow is as follows:
1. `pkgs.callPackge xxx.nix {...}` will first `import xxx.nix` to get the function defined in it. The parameters of this function usually have `lib`, `stdenv`, `fetchurl` and other parameters, as well as some custom parameters, which usually have default values.
2. Then `pkgs.callPackge` will first look up the value matching the name from the current environment as the parameter to be passed to the function. parameters like `lib` `stdenv` `fetchurl` are defined in nixpkgs, and they will be found in this step.
3. Then `pkgs.callPackge` will merge its second parameter `{...}` with the attribute set obtained in the previous step, and then pass it to the function imported from `xxx.nix` and execute it.
4. Finally we get a Derivation as the result of the function execution.
So the common usage of `pkgs.callPackage` is to import custom Nix packages and used it in Nix Module.
For example, we wrote a `hello.nix` ourselves, and then we can use `pkgs.callPackage ./hello.nix {}` in any Nix Module to import and use it.
### 2. Overriding {#overriding}
> [Chapter 4. Overriding - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overrides)
Simply put, all Nix packages in nixpkgs can be customized with `<pkg>.override {}` to define some build parameters, which returns a new Derivation that uses custom parameters. For example:
```nix
pkgs.fcitx5-rime.override {rimeDataPkgs = [
./rime-data-flypy
];}
```
The result of this Nix expression is a new Derivation, where `rimeDataPkgs` is overridden as `[./rime-data-flypy]`, while other parameters remain their original values.
How to know which parameters of `fcitx5-rime` can be overridden? There are several ways:
1. Try to find the source code of the package in the nixpkgs repository on GitHub, such as [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix)
1. Note: Be sure to select the correct branch, for example, if you are using the nixos-unstable branch, you need to find it in the nixos-unstable branch.
2. Check by using `nix repl '<nixpkgs>'`, then enter `:e pkgs.fcitx5-rime`, which will open the source code of this package through the default editor, and then you can see all the parameters of this package.
1. Note: To learn the basic usage of `nix repl`, just type `:?` to see the help information
Through these two methods, you can see that the `fcitx5-rime` package has the following input parameters, which can all be modified by `override`:
```nix
{ lib, stdenv
, fetchFromGitHub
, pkg-config
, cmake
, extra-cmake-modules
, gettext
, fcitx5
, librime
, rime-data
, symlinkJoin
, rimeDataPkgs ? [ rime-data ]
}:
stdenv.mkDerivation rec {
...
}
```
Instead of override the function's parameters, we can also override the attributes of the Derivation created by `stdenv.mkDerivation`.
Take `pkgs.hello` as an example, first check the source code of this package through the method we mentioned earlier:
```nix
# https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/applications/misc/hello/default.nix
{ callPackage
, lib
, stdenv
, fetchurl
, nixos
, testers
, hello
}:
stdenv.mkDerivation (finalAttrs: {
pname = "hello";
version = "2.12.1";
src = fetchurl {
url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
sha256 = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
};
doCheck = true;
# ......
})
```
The attributes showed above, such as `pname` `version` `src` `doCheck`, can all be overridden by `overrideAttrs`, for example:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
doCheck = false;
});
```
Here we use `overrideAttrs` to override `doCheck`, while other attributes remain their original values.
Some default attributes defined in `stdenv.mkDerivation` can also be overridden by `overrideAttrs`, for example:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
separateDebugInfo = true;
});
```
The attribute we override here, `separateDebugInfo`, is defined in `stdenv.mkDerivation`, not in the source code of `hello`.
We can check the source code of `stdenv.mkDerivation` to see all the attributes defined in it by using `nix repl '<nixpkgs>'` and then enter `:e stdenv.mkDerivation`(To learn the basic usage of `nix repl`, just type `:?` to see the help information).
### 3. Overlays
> [Chapter 3. Overlays - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays)
The `override` we introduced previously will generate a new Derivation, which does not affect the original Derivation in `pkgs`, and is only suitable for use as a local parameter,
if you need to override a Derivation that is also depended on by other Nix packages, then other Nix packages will still use the original Derivation.
To solve this problem, Nix provides the ability to use `overlays`. Simply put, `overlays` can globally modify the Derivation in `pkgs`.
In the classic Nix environment, Nix automatically applies all `overlays` configuration under the paths `~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix`,
but in Flakes, in order to ensure the reproducibility of the system, it cannot depend on any configuration outside the Git repository, so this classic method cannot be used now.
When using Flakes to write configuration for NixOS, home Manager and NixOS both provide the `nixpkgs.overlays` option to define `overlays`, related documentation:
- [home-manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.html#opt-nixpkgs.overlays)
- [nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169)
For example, the following content is a Module that loads Overlays, which can be used as either a home Manager Module or a NixOS Module, because the two definitions are exactly the same:
> home Manager is an external component after all, and most people use the unstable branch of home Manager & nixpkgs, which sometimes causes problems with home Manager Module, so it is recommended to import `overlays` in a NixOS Module.
```nix
{ config, pkgs, lib, ... }:
{
nixpkgs.overlays = [
# overlayer1 - 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'";
};
})
# overlayer2 - you can also use `extend` to inherit other overlays
# 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";
};
})
# overlay3 - define overlays in other files
# here the content of overlay3.nix is the same as above:
# `final: prev: { xxx = prev.xxx.override { ... }; }`
(import ./overlays/overlay3.nix)
];
}
```
refer to this example to write your own overlays, import the configuration as a NixOS Module or a home Manager Module, and then deploy it to see the effect.
#### Modular overlays
The previous example shows how to write overlays, but all overlays are written in a single nix file, which is a bit difficult to maintain.
To resolve this problem,here is a best practice of how to manage overlays in a modular way.
First, create an `overlays` folder in the Git repository to store all overlays configuration, and then create `overlays/default.nix`, whose content is as follows:
```nix
args:
# 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
builtins.map
(f: (import (./. + "/${f}") args)) # the first parameter of map, a function that import and execute a nix file
(builtins.filter # the second parameter of map, a list of all nix files in the current folder except default.nix
(f: f != "default.nix")
(builtins.attrNames (builtins.readDir ./.)))
```
Then you can write all overlays configuration in the `overlays` folder, an example configuration `overlays/fcitx5/default.nix` is as follows:
```nix
# to add my custom input method, I override the default rime-data here
# refer to https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix
{pkgs, config, lib, ...}:
(self: super: {
# my custom input method's rime-data, downloaded from https://flypy.com
rime-data = ./rime-data-flypy;
fcitx5-rime = super.fcitx5-rime.override { rimeDataPkgs = [ ./rime-data-flypy ]; };
})
```
I custom the `rime-data` package through the overlay shown above.
At last, you need to load all overlays returned by `overlays/default.nix` through the `nixpkgs.overlays` option, add the following parameter to any NixOS Module to achieve this:
```nix
{ config, pkgs, lib, ... } @ args:
{
# ......
# add this parameter
nixpkgs.overlays = import /path/to/overlays/dir;
# ......
}
```
For example, you can just 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, it is very convenient to modularize all your overlays. Taking my configuration as an example, the structure of the `overlays` folder is roughly as follows:
```nix
.
├── flake.lock
├── flake.nix
├── home
├── hosts
├── modules
├── ......
├── overlays
│ ├── default.nix # it returns a list of all overlays.
│ └── fcitx5 # fcitx5 overlay
│ ├── default.nix
│ ├── README.md
│ └── rime-data-flypy # my custom rime-data
│ └── share
│ └── rime-data
│ ├── ...... # rime-data files
└── README.md
```
## IV. Package Repositories of Nix
Similar to Arch Linux, Nix also has official and community software package repositories:
1. [nixpkgs](https://github.com/NixOS/nixpkgs) is a Git repository containing all Nix packages and NixOS modules.
1. Its `master` branch contains the latest Nix packages and modules.
2. The `nixos-unstable` branch contains the latest tested modules, but some bugs may still exist.
3. And the `nixos-XX.YY` branch(the stable branch) contains the latest stable Nix packages and modules.
2. [NUR](https://github.com/nix-community/NUR) is similar to Arch Linux's AUR.
1. NUR is a third-party Nix package repository and serves as a supplement to nixpkgs, use it at your own risk.
3. Flakes can also install software packages directly from Git repositories, which can be used to install Flakes provided by anyone, we will talk about this later.

12
docs/nixpkgs/intro.md Normal file
View file

@ -0,0 +1,12 @@
`callPackage`, `Overriding`, and `Overlays` are the techniques occasionally used when using Nix to customize the build method of Nix packages.
We know that many programs have a large number of build parameters that need to be configured, and different users may want to use different build parameters. This is where `Overriding` and `Overlays` come in handy. Let me give you a few examples I have encountered:
1. [`fcitx5-rime.nix`](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): By default, `fcitx5-rime` use `rime-data` as the value of `rimeDataPkgs`, but this parameter can be customized by `override`.
2. [`vscode/with-extensions.nix`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vscode/with-extensions.nix): This package for VS Code can also be customized by overriding the value of `vscodeExtensions`, thus we can install some custom plugins into VS Code.
- [`nix-vscode-extensions`](https://github.com/nix-community/nix-vscode-extensions): This is a vscode plugin manager implemented by overriding `vscodeExtensions`.
3. [`firefox/common.nix`](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): Firefox has many customizable parameters too.
4. ...
In short, `callPackage`, `Overriding` and `Overlays` can be used to customize the build parameters of Nix packages.

165
docs/nixpkgs/overlays.md Normal file
View file

@ -0,0 +1,165 @@
The `override` we introduced previously will generate a new Derivation, which does not affect the original Derivation in `pkgs`, and is only suitable for use as a local parameter,
if you need to override a Derivation that is also depended on by other Nix packages, then other Nix packages will still use the original Derivation.
To solve this problem, Nix provides the ability to use `overlays`. Simply put, `overlays` can globally modify the Derivation in `pkgs`.
In the classic Nix environment, Nix automatically applies all `overlays` configuration under the paths `~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix`,
but in Flakes, in order to ensure the reproducibility of the system, it cannot depend on any configuration outside the Git repository, so this classic method cannot be used now.
When using Flakes to write configuration for NixOS, home Manager and NixOS both provide the `nixpkgs.overlays` option to define `overlays`, related documentation:
- [home-manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.html#opt-nixpkgs.overlays)
- [nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169)
For example, the following content is a Module that loads Overlays, which can be used as either a home Manager Module or a NixOS Module, because the two definitions are exactly the same:
> home Manager is an external component after all, and most people use the unstable branch of home Manager & nixpkgs, which sometimes causes problems with home Manager Module, so it is recommended to import `overlays` in a NixOS Module.
```nix
{ config, pkgs, lib, ... }:
{
nixpkgs.overlays = [
# overlayer1 - 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'";
};
})
# overlayer2 - you can also use `extend` to inherit other overlays
# 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";
};
})
# overlay3 - define overlays in other files
# here the content of overlay3.nix is the same as above:
# `final: prev: { xxx = prev.xxx.override { ... }; }`
(import ./overlays/overlay3.nix)
];
}
```
refer to this example to write your own overlays, import the configuration as a NixOS Module or a home Manager Module, and then deploy it to see the effect.
## Modular overlays
The previous example shows how to write overlays, but all overlays are written in a single nix file, which is a bit difficult to maintain.
To resolve this problem,here is a best practice of how to manage overlays in a modular way.
First, create an `overlays` folder in the Git repository to store all overlays configuration, and then create `overlays/default.nix`, whose content is as follows:
```nix
args:
# 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
builtins.map
(f: (import (./. + "/${f}") args)) # the first parameter of map, a function that import and execute a nix file
(builtins.filter # the second parameter of map, a list of all nix files in the current folder except default.nix
(f: f != "default.nix")
(builtins.attrNames (builtins.readDir ./.)))
```
Then you can write all overlays configuration in the `overlays` folder, an example configuration `overlays/fcitx5/default.nix` is as follows:
```nix
# to add my custom input method, I override the default rime-data here
# refer to https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix
{pkgs, config, lib, ...}:
(self: super: {
# my custom input method's rime-data, downloaded from https://flypy.com
rime-data = ./rime-data-flypy;
fcitx5-rime = super.fcitx5-rime.override { rimeDataPkgs = [ ./rime-data-flypy ]; };
})
```
I custom the `rime-data` package through the overlay shown above.
At last, you need to load all overlays returned by `overlays/default.nix` through the `nixpkgs.overlays` option, add the following parameter to any NixOS Module to achieve this:
```nix
{ config, pkgs, lib, ... } @ args:
{
# ......
# add this parameter
nixpkgs.overlays = import /path/to/overlays/dir;
# ......
}
```
For example, you can just 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, it is very convenient to modularize all your overlays. Taking my configuration as an example, the structure of the `overlays` folder is roughly as follows:
```nix
.
├── flake.lock
├── flake.nix
├── home
├── hosts
├── modules
├── ......
├── overlays
│ ├── default.nix # it returns a list of all overlays.
│ └── fcitx5 # fcitx5 overlay
│ ├── default.nix
│ ├── README.md
│ └── rime-data-flypy # my custom rime-data
│ └── share
│ └── rime-data
│ ├── ...... # rime-data files
└── README.md
```

View file

@ -0,0 +1,89 @@
Simply put, all Nix packages in nixpkgs can be customized with `<pkg>.override {}` to define some build parameters, which returns a new Derivation that uses custom parameters. For example:
```nix
pkgs.fcitx5-rime.override {rimeDataPkgs = [
./rime-data-flypy
];}
```
The result of this Nix expression is a new Derivation, where `rimeDataPkgs` is overridden as `[./rime-data-flypy]`, while other parameters remain their original values.
How to know which parameters of `fcitx5-rime` can be overridden? There are several ways:
1. Try to find the source code of the package in the nixpkgs repository on GitHub, such as [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix)
1. Note: Be sure to select the correct branch, for example, if you are using the nixos-unstable branch, you need to find it in the nixos-unstable branch.
2. Check by using `nix repl '<nixpkgs>'`, then enter `:e pkgs.fcitx5-rime`, which will open the source code of this package through the default editor, and then you can see all the parameters of this package.
1. Note: To learn the basic usage of `nix repl`, just type `:?` to see the help information
Through these two methods, you can see that the `fcitx5-rime` package has the following input parameters, which can all be modified by `override`:
```nix
{ lib, stdenv
, fetchFromGitHub
, pkg-config
, cmake
, extra-cmake-modules
, gettext
, fcitx5
, librime
, rime-data
, symlinkJoin
, rimeDataPkgs ? [ rime-data ]
}:
stdenv.mkDerivation rec {
...
}
```
Instead of override the function's parameters, we can also override the attributes of the Derivation created by `stdenv.mkDerivation`.
Take `pkgs.hello` as an example, first check the source code of this package through the method we mentioned earlier:
```nix
# https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/applications/misc/hello/default.nix
{ callPackage
, lib
, stdenv
, fetchurl
, nixos
, testers
, hello
}:
stdenv.mkDerivation (finalAttrs: {
pname = "hello";
version = "2.12.1";
src = fetchurl {
url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
sha256 = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
};
doCheck = true;
# ......
})
```
The attributes showed above, such as `pname` `version` `src` `doCheck`, can all be overridden by `overrideAttrs`, for example:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
doCheck = false;
});
```
Here we use `overrideAttrs` to override `doCheck`, while other attributes remain their original values.
Some default attributes defined in `stdenv.mkDerivation` can also be overridden by `overrideAttrs`, for example:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
separateDebugInfo = true;
});
```
The attribute we override here, `separateDebugInfo`, is defined in `stdenv.mkDerivation`, not in the source code of `hello`.
We can check the source code of `stdenv.mkDerivation` to see all the attributes defined in it by using `nix repl '<nixpkgs>'` and then enter `:e stdenv.mkDerivation`(To learn the basic usage of `nix repl`, just type `:?` to see the help information).

View file

@ -0,0 +1,21 @@
前面我们介绍并大量使用了 `import xxx.nix` 来导入 Nix 文件,这种语法只是单纯地返回该文件的执行结果,不会对该结果进行进一步处理。
比如说 `xxx.nix` 的内容是形如 `{...}: {...}`,那么 `import xxx.nix` 的结果就是该文件中定义的这个函数。
`pkgs.callPackage` 也是用来导入 Nix 文件的,它的语法是 `pkgs.callPackage xxx.nix { ... }`. 但跟 `import` 不同的是,它导入的 nix 文件内容必须是一个 Derivation 或者返回 Derivation 的函数,它的执行结果一定是一个 Derivation也就是一个软件包。
那可以作为 `pkgs.callPackge` 参数的 nix 文件具体长啥样呢,可以去看看我们前面举例过的 `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix`,它们都可以被 `pkgs.callPackage` 导入。
`pkgs.callPackge xxx.nix {...}` 中的 `xxx.nix`,其内容为一个函数时(绝大多数 nix 包都是如此),执行流程如下:
1. `pkgs.callPackge xxx.nix {...}` 会先 `import xxx.nix`,得到其中定义的函数,该函数的参数通常会有 `lib`, `stdenv`, `fetchurl` 等参数,以及一些自定义参数,自定义参数通常都有默认值。
2. 接着 `pkgs.callPackge` 会首先从当前环境中查找名称匹配的值,作为将要传递给前述函数的参数。像 `lib` `stdenv` `fetchurl` 这些都是 nixpkgs 中的函数,在这一步就会查找到它们。
3. 接着 `pkgs.callPackge` 会将其第二个参数 `{...}` 与前一步得到的参数集attribute set进行合并得到一个新的参数列表然后将其传递给该函数并执行。
4. 函数执行结果是一个 Derivation也就是一个软件包。
这个函数比较常见的用途是用来导入一些自定义的 Nix 包,比如说我们自己写了一个 `hello.nix`,然后就可以在任意 Nix Module 中使用 `pkgs.callPackage ./hello.nix {}` 来导入并使用它。
## 参考
- [Chapter 13. Callpackage Design Pattern - Nix Pills](https://nixos.org/guides/nix-pills/callpackage-design-pattern.html)

View file

@ -1,295 +0,0 @@
## 八、Nixpkgs 的高级用法 {#nixpkgs-advanced-usage}
callPackage、Overriding 与 Overlays 是在使用 Nix 时偶尔会用到的技术,它们都是用来自定义 Nix 包的构建方法的。
我们知道许多程序都有大量构建参数需要配置,不同的用户会希望使用不同的构建参数,这时候就需要 Overriding 与 Overlays 来实现。我举几个我遇到过的例子:
1. [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): fcitx5-rime 的 `rimeDataPkgs` 默认使用 `rime-data` 包,但是也可以通过 override 来自定义该参数的值,以加载自定义的 rime 配置(比如加载小鹤音形输入法配置)。
2. [vscode/with-extensions.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vscode/with-extensions.nix): vscode 的这个包也可以通过 override 来自定义 `vscodeExtensions` 参数的值来安装自定义插件。
1. [nix-vscode-extensions](https://github.com/nix-community/nix-vscode-extensions): 就是利用该参数实现的 vscode 插件管理
3. [firefox/common.nix](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): firefox 同样有许多可自定义的参数
4. 等等
总之如果需要自定义上述这类 Nix 包的构建参数,或者实施某些比较底层的修改,我们就得用到 Overriding 跟 Overlays。
### 1. pkgs.callPackage {#callpackage}
> [Chapter 13. Callpackage Design Pattern - Nix Pills](https://nixos.org/guides/nix-pills/callpackage-design-pattern.html)
前面我们介绍并大量使用了 `import xxx.nix` 来导入 Nix 文件,这种语法只是单纯地返回该文件的执行结果,不会对该结果进行进一步处理。
比如说 `xxx.nix` 的内容是形如 `{...}: {...}`,那么 `import xxx.nix` 的结果就是该文件中定义的这个函数。
`pkgs.callPackage` 也是用来导入 Nix 文件的,它的语法是 `pkgs.callPackage xxx.nix { ... }`. 但跟 `import` 不同的是,它导入的 nix 文件内容必须是一个 Derivation 或者返回 Derivation 的函数,它的执行结果一定是一个 Derivation也就是一个软件包。
那可以作为 `pkgs.callPackge` 参数的 nix 文件具体长啥样呢,可以去看看我们前面举例过的 `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix`,它们都可以被 `pkgs.callPackage` 导入。
`pkgs.callPackge xxx.nix {...}` 中的 `xxx.nix`,其内容为一个函数时(绝大多数 nix 包都是如此),执行流程如下:
1. `pkgs.callPackge xxx.nix {...}` 会先 `import xxx.nix`,得到其中定义的函数,该函数的参数通常会有 `lib`, `stdenv`, `fetchurl` 等参数,以及一些自定义参数,自定义参数通常都有默认值。
2. 接着 `pkgs.callPackge` 会首先从当前环境中查找名称匹配的值,作为将要传递给前述函数的参数。像 `lib` `stdenv` `fetchurl` 这些都是 nixpkgs 中的函数,在这一步就会查找到它们。
3. 接着 `pkgs.callPackge` 会将其第二个参数 `{...}` 与前一步得到的参数集attribute set进行合并得到一个新的参数列表然后将其传递给该函数并执行。
4. 函数执行结果是一个 Derivation也就是一个软件包。
这个函数比较常见的用途是用来导入一些自定义的 Nix 包,比如说我们自己写了一个 `hello.nix`,然后就可以在任意 Nix Module 中使用 `pkgs.callPackage ./hello.nix {}` 来导入并使用它。
### 2. Overriding {#overriding}
> [Chapter 4. Overriding - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overrides)
简单的说,所有 nixpkgs 中的 Nix 包都可以通过 `<pkg>.override {}` 来自定义某些构建参数,它返回一个使用了自定义参数的新 Derivation. 举个例子:
```nix
pkgs.fcitx5-rime.override {rimeDataPkgs = [
./rime-data-flypy
];}
```
上面这个 Nix 表达式的执行结果就是一个新的 Derivation它的 `rimeDataPkgs` 参数被覆盖为 `[./rime-data-flypy]`,而其他参数则沿用原来的值。
如何知道 `fcitx5-rime` 这个包有哪些参数可以覆写呢?有几种方法:
1. 直接在 GitHub 的 nixpkgs 源码中找:[fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix)
1. 注意要选择正确的分支,加入你用的是 nixos-unstable 分支,那就要在 nixos-unstable 分支中找。
2. 通过 `nix repl` 交互式查看:`nix repl '<nixpkgs>'`,然后输入 `:e pkgs.fcitx5-rime`,会通过编辑器打开这个包的源码,然后就可以看到这个包的所有参数了。
通过上述两种方法,都可以看到 `fcitx5-rime` 这个包拥有如下输入参数,它们都是可以通过 `override` 修改的:
```nix
{ lib, stdenv
, fetchFromGitHub
, pkg-config
, cmake
, extra-cmake-modules
, gettext
, fcitx5
, librime
, rime-data
, symlinkJoin
, rimeDataPkgs ? [ rime-data ]
}:
stdenv.mkDerivation rec {
...
}
```
除了覆写参数,还可以通过 `overrideAttrs` 来覆写使用 `stdenv.mkDerivation` 构建的 Derivation 的属性。
`pkgs.hello` 为例,首先通过前述方法查看这个包的源码:
```nix
# https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/applications/misc/hello/default.nix
{ callPackage
, lib
, stdenv
, fetchurl
, nixos
, testers
, hello
}:
stdenv.mkDerivation (finalAttrs: {
pname = "hello";
version = "2.12.1";
src = fetchurl {
url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
sha256 = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
};
doCheck = true;
# ......
})
```
其中 `pname` `version` `src` `doCheck` 等属性都是可以通过 `overrideAttrs` 来覆写的,比如:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
doCheck = false;
});
```
上面这个例子中,`doCheck` 就是一个新的 Derivation它的 `doCheck` 参数被改写为 `false`,而其他参数则沿用原来的值。
除了包源码中自定义的参数值外,我们也可以通过 `overrideAttrs` 直接改写 `stdenv.mkDerivation` 内部的默认参数,比如:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
separateDebugInfo = true;
});
```
具体的内部参数可以通过 `nix repl '<nixpkgs>'` 然后输入 `:e stdenv.mkDerivation` 来查看其源码。
### 3. Overlays {#overlays}
> [Chapter 3. Overlays - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays)
前面介绍的 override 函数都会生成新的 Derivation不影响 pkgs 中原有的 Derivation只适合作为局部参数使用。
但如果你需要覆写的 Derivation 还被其他 Nix 包所依赖,那其他 Nix 包使用的仍然会是原有的 Derivation.
为了解决这个问题Nix 提供了 overlays 能力。简单的说Overlays 可以全局修改 pkgs 中的 Derivation。
在旧的 Nix 环境中Nix 默认会自动应用 `~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix` 这类路径下的所有 overlays 配置。
但是在 Flakes 中,为了确保系统的可复现性,它不能依赖任何 Git 仓库之外的配置,所以这种旧的方法就不能用了。
在使用 Nix Flakes 编写 NixOS 配置时Home Manager 与 NixOS 都提供了 `nixpkgs.overlays` 这个 option 来引入 overlays, 相关文档:
- [home-manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.html#opt-nixpkgs.overlays)
- [nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169)
举个例子,如下内容就是一个加载 Overlays 的 Module它既可以用做 Home Manager Module也可以用做 NixOS Module因为这俩定义完全是一致的
> 不过我使用发现Home Manager 毕竟是个外部组件,而且现在全都用的 unstable 分支,这导致 Home Manager Module 有时候会有点小毛病,因此更建议以 NixOS Module 的形式引入 overlays
```nix
{ config, pkgs, lib, ... }:
{
nixpkgs.overlays = [
# overlayer1 - 参数名用 self 与 super表达继承关系
(self: super: {
google-chrome = super.google-chrome.override {
commandLineArgs =
"--proxy-server='https=127.0.0.1:3128;http=127.0.0.1:3128'";
};
})
# overlayer2 - 还可以使用 extend 来继承其他 overlay
# 这里改用 final 与 prev表达新旧关系
(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";
};
})
# overlay3 - 也可以将 overlay 定义在其他文件中
# 这里 overlay3.nix 中的内容格式与上面的一致,都是 `final: prev: { xxx = prev.xxx.override { ... }; }`
(import ./overlays/overlay3.nix)
];
}
```
这里只是个示例配置,参照此格式编写你自己的 overlays 配置,将该配置作为 NixOS Module 或者 Home Manager Module 引入,然后部署就可以看到效果了。
#### 模块化 overlays 配置
上面的例子说明了如何编写 overlays但是所有 overlays 都一股脑儿写在一起,就有点难以维护了,写得多了自然就希望模块化管理这些 overlays.
这里介绍下我找到的一个 overlays 模块化管理的最佳实践。
首先在 Git 仓库中创建 `overlays` 文件夹用于存放所有 overlays 配置,然后创建 `overlays/default.nix`,其内容如下:
```nix
args:
# import 当前文件夹下所有的 nix 文件,并以 args 为参数执行它们
# 返回值是一个所有执行结果的列表,也就是 overlays 的列表
builtins.map
(f: (import (./. + "/${f}") args)) # map 的第一个参数,是一个 import 并执行 nix 文件的函数
(builtins.filter # map 的第二个参数,它返回一个当前文件夹下除 default.nix 外所有 nix 文件的列表
(f: f != "default.nix")
(builtins.attrNames (builtins.readDir ./.)))
```
后续所有 overlays 配置都添加到 `overlays` 文件夹中,一个示例配置 `overlays/fcitx5/default.nix` 内容如下:
```nix
# 为了不使用默认的 rime-data改用我自定义的小鹤音形数据这里需要 override
# 参考 https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix
{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:
{
# ......
# 添加此参数
nixpkgs.overlays = import /path/to/overlays/dir;
# ......
}
```
比如说直接写 `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
# 添加如下内嵌 module 定义
# 这里将 modules 的所有参数 args 都传递到了 overlays 中
(args: { nixpkgs.overlays = import ./overlays args; })
# ......
];
};
};
};
}
```
按照上述方法进行配置,就可以很方便地模块化管理所有 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
```
你可以在我的配置仓库 [ryan4yin/nix-config/v0.0.4](https://github.com/ryan4yin/nix-config/tree/v0.0.4) 查看更详细的内容,获取些灵感。

14
docs/zh/nixpkgs/intro.md Normal file
View file

@ -0,0 +1,14 @@
## 八、Nixpkgs 的高级用法 {#nixpkgs-advanced-usage}
callPackage、Overriding 与 Overlays 是在使用 Nix 时偶尔会用到的技术,它们都是用来自定义 Nix 包的构建方法的。
我们知道许多程序都有大量构建参数需要配置,不同的用户会希望使用不同的构建参数,这时候就需要 Overriding 与 Overlays 来实现。我举几个我遇到过的例子:
1. [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): fcitx5-rime 的 `rimeDataPkgs` 默认使用 `rime-data` 包,但是也可以通过 override 来自定义该参数的值,以加载自定义的 rime 配置(比如加载小鹤音形输入法配置)。
2. [vscode/with-extensions.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vscode/with-extensions.nix): vscode 的这个包也可以通过 override 来自定义 `vscodeExtensions` 参数的值来安装自定义插件。
1. [nix-vscode-extensions](https://github.com/nix-community/nix-vscode-extensions): 就是利用该参数实现的 vscode 插件管理
3. [firefox/common.nix](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): firefox 同样有许多可自定义的参数
4. 等等
总之如果需要自定义上述这类 Nix 包的构建参数,或者实施某些比较底层的修改,我们就得用到 callPackage、Overriding 与 Overlays 这些特性。

172
docs/zh/nixpkgs/overlays.md Normal file
View file

@ -0,0 +1,172 @@
前面介绍的 override 函数都会生成新的 Derivation不影响 pkgs 中原有的 Derivation只适合作为局部参数使用。
但如果你需要覆写的 Derivation 还被其他 Nix 包所依赖,那其他 Nix 包使用的仍然会是原有的 Derivation.
为了解决这个问题Nix 提供了 overlays 能力。简单的说Overlays 可以全局修改 pkgs 中的 Derivation。
在旧的 Nix 环境中Nix 默认会自动应用 `~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix` 这类路径下的所有 overlays 配置。
但是在 Flakes 中,为了确保系统的可复现性,它不能依赖任何 Git 仓库之外的配置,所以这种旧的方法就不能用了。
在使用 Nix Flakes 编写 NixOS 配置时Home Manager 与 NixOS 都提供了 `nixpkgs.overlays` 这个 option 来引入 overlays, 相关文档:
- [home-manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.html#opt-nixpkgs.overlays)
- [nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169)
举个例子,如下内容就是一个加载 Overlays 的 Module它既可以用做 Home Manager Module也可以用做 NixOS Module因为这俩定义完全是一致的
> 不过我使用发现Home Manager 毕竟是个外部组件,而且现在全都用的 unstable 分支,这导致 Home Manager Module 有时候会有点小毛病,因此更建议以 NixOS Module 的形式引入 overlays
```nix
{ config, pkgs, lib, ... }:
{
nixpkgs.overlays = [
# overlayer1 - 参数名用 self 与 super表达继承关系
(self: super: {
google-chrome = super.google-chrome.override {
commandLineArgs =
"--proxy-server='https=127.0.0.1:3128;http=127.0.0.1:3128'";
};
})
# overlayer2 - 还可以使用 extend 来继承其他 overlay
# 这里改用 final 与 prev表达新旧关系
(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";
};
})
# overlay3 - 也可以将 overlay 定义在其他文件中
# 这里 overlay3.nix 中的内容格式与上面的一致,都是 `final: prev: { xxx = prev.xxx.override { ... }; }`
(import ./overlays/overlay3.nix)
];
}
```
这里只是个示例配置,参照此格式编写你自己的 overlays 配置,将该配置作为 NixOS Module 或者 Home Manager Module 引入,然后部署就可以看到效果了。
## 模块化 overlays 配置
上面的例子说明了如何编写 overlays但是所有 overlays 都一股脑儿写在一起,就有点难以维护了,写得多了自然就希望模块化管理这些 overlays.
这里介绍下我找到的一个 overlays 模块化管理的最佳实践。
首先在 Git 仓库中创建 `overlays` 文件夹用于存放所有 overlays 配置,然后创建 `overlays/default.nix`,其内容如下:
```nix
args:
# import 当前文件夹下所有的 nix 文件,并以 args 为参数执行它们
# 返回值是一个所有执行结果的列表,也就是 overlays 的列表
builtins.map
(f: (import (./. + "/${f}") args)) # map 的第一个参数,是一个 import 并执行 nix 文件的函数
(builtins.filter # map 的第二个参数,它返回一个当前文件夹下除 default.nix 外所有 nix 文件的列表
(f: f != "default.nix")
(builtins.attrNames (builtins.readDir ./.)))
```
后续所有 overlays 配置都添加到 `overlays` 文件夹中,一个示例配置 `overlays/fcitx5/default.nix` 内容如下:
```nix
# 为了不使用默认的 rime-data改用我自定义的小鹤音形数据这里需要 override
# 参考 https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix
{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:
{
# ......
# 添加此参数
nixpkgs.overlays = import /path/to/overlays/dir;
# ......
}
```
比如说直接写 `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
# 添加如下内嵌 module 定义
# 这里将 modules 的所有参数 args 都传递到了 overlays 中
(args: { nixpkgs.overlays = import ./overlays args; })
# ......
];
};
};
};
}
```
按照上述方法进行配置,就可以很方便地模块化管理所有 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
```
你可以在我的配置仓库 [ryan4yin/nix-config/v0.0.4](https://github.com/ryan4yin/nix-config/tree/v0.0.4) 查看更详细的内容,获取些灵感。
## 参考
- [Chapter 3. Overlays - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays)

View file

@ -0,0 +1,91 @@
简单的说,所有 nixpkgs 中的 Nix 包都可以通过 `<pkg>.override {}` 来自定义某些构建参数,它返回一个使用了自定义参数的新 Derivation. 举个例子:
```nix
pkgs.fcitx5-rime.override {rimeDataPkgs = [
./rime-data-flypy
];}
```
上面这个 Nix 表达式的执行结果就是一个新的 Derivation它的 `rimeDataPkgs` 参数被覆盖为 `[./rime-data-flypy]`,而其他参数则沿用原来的值。
如何知道 `fcitx5-rime` 这个包有哪些参数可以覆写呢?有几种方法:
1. 直接在 GitHub 的 nixpkgs 源码中找:[fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix)
1. 注意要选择正确的分支,加入你用的是 nixos-unstable 分支,那就要在 nixos-unstable 分支中找。
2. 通过 `nix repl` 交互式查看:`nix repl '<nixpkgs>'`,然后输入 `:e pkgs.fcitx5-rime`,会通过编辑器打开这个包的源码,然后就可以看到这个包的所有参数了。
通过上述两种方法,都可以看到 `fcitx5-rime` 这个包拥有如下输入参数,它们都是可以通过 `override` 修改的:
```nix
{ lib, stdenv
, fetchFromGitHub
, pkg-config
, cmake
, extra-cmake-modules
, gettext
, fcitx5
, librime
, rime-data
, symlinkJoin
, rimeDataPkgs ? [ rime-data ]
}:
stdenv.mkDerivation rec {
...
}
```
除了覆写参数,还可以通过 `overrideAttrs` 来覆写使用 `stdenv.mkDerivation` 构建的 Derivation 的属性。
`pkgs.hello` 为例,首先通过前述方法查看这个包的源码:
```nix
# https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/applications/misc/hello/default.nix
{ callPackage
, lib
, stdenv
, fetchurl
, nixos
, testers
, hello
}:
stdenv.mkDerivation (finalAttrs: {
pname = "hello";
version = "2.12.1";
src = fetchurl {
url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
sha256 = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
};
doCheck = true;
# ......
})
```
其中 `pname` `version` `src` `doCheck` 等属性都是可以通过 `overrideAttrs` 来覆写的,比如:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
doCheck = false;
});
```
上面这个例子中,`doCheck` 就是一个新的 Derivation它的 `doCheck` 参数被改写为 `false`,而其他参数则沿用原来的值。
除了包源码中自定义的参数值外,我们也可以通过 `overrideAttrs` 直接改写 `stdenv.mkDerivation` 内部的默认参数,比如:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
separateDebugInfo = true;
});
```
具体的内部参数可以通过 `nix repl '<nixpkgs>'` 然后输入 `:e stdenv.mkDerivation` 来查看其源码。
## 参考
- [Chapter 4. Overriding - nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/#chap-overrides)