mirror of
https://github.com/ryan4yin/nixos-and-flakes-book
synced 2024-11-10 14:54:13 +00:00
feat: finish 'nixpkgs's advanced usage'
This commit is contained in:
parent
6187bbd9b7
commit
9db31c0d59
11 changed files with 595 additions and 605 deletions
|
@ -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 最佳实践",
|
||||
|
|
16
docs/nixpkgs/callpackage.md
Normal file
16
docs/nixpkgs/callpackage.md
Normal 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.
|
|
@ -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
12
docs/nixpkgs/intro.md
Normal 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
165
docs/nixpkgs/overlays.md
Normal 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
|
||||
```
|
89
docs/nixpkgs/overriding.md
Normal file
89
docs/nixpkgs/overriding.md
Normal 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).
|
21
docs/zh/nixpkgs/callpackage.md
Normal file
21
docs/zh/nixpkgs/callpackage.md
Normal 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)
|
|
@ -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
14
docs/zh/nixpkgs/intro.md
Normal 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
172
docs/zh/nixpkgs/overlays.md
Normal 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)
|
91
docs/zh/nixpkgs/overriding.md
Normal file
91
docs/zh/nixpkgs/overriding.md
Normal 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)
|
Loading…
Reference in a new issue