假设我有一个非常简单的NixOS 配置文件:
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];
# SOME STUFF
environment.systemPackages = with pkgs; [ emacs gitFull ];
# SOME STUFF
}
我知道 NixOS 实现了模块系统,模块就是一个.nix
文件。每个.nix
文件都应包含任何有效的尼克斯表达(例如函数或集合)。这意味着 NixOS 配置文件/etc/nixos/configuration.nix
本身就是一个模块,包含 Nix 表达式。
我还知道,为了使另一个模块中的 Nix 表达式对我正在使用的模块可见,我可以使用内置的import
功能。
我想将系统包的声明(包含emacs
和 的列表gitFull
)拆分到 file 中packages.nix
。如何将 NixOS 配置文件拆分为单独的模块?
答案1
尼克斯表达式
A尼克斯表达就像任何编程语言表达式一样:任何计算结果为值或函数的东西。这种情况下的值也可以是列表或集合。由于 Nix 模块(扩展名为 的文件.nix
)可以包含任何 Nix 表达式,因此您会期望 NixOS 配置文件 ( /etc/nixos/configuration.nix
) 包含单个 Nix 表达式作为其文件内容。
NixOS 配置文件包含以下形式的 Nix 表达式:
{config, pkgs, ...}: { /* various configuration options */ }
如果你仔细观察,你会发现这是一个功能,因为功能遵循形式pattern: form
。您还可以看到它是一个接受集合并返回集合的函数。例如,如果您有一个 function f = {x, y}: {a = x + y;}
,那么您可以将其称为f {x=1; y=2;}
并返回一个 set {a=3;}
。
因此,这意味着当您调用 时,某些东西会使用必须包含属性和 的nixos-rebuild switch
集合来调用 NixOS 配置文件内的函数。config
pkgs
进口
以下示例中./hardware-configuration.nix
,将包列表提取到单独模块中的简单方法packages.nix
是将environment.systemPackages
选项取出并放入选项./packages.nix
中。imports
你的/etc/nixos/configuration.nix
看起来像:
{ config, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
# Include the package list.
./packages.nix
];
# SOME STUFF
# SOME STUFF
}
你的/etc/nixos/packages.nix
看起来像:
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ emacs gitFull ];
}
这是如何运作的?当您运行 时nixos-rebuild switch
,评估 Nix 表达式并决定安装软件包等的过程会调用configuration.nix
一组属性,其中一些属性是config
和pkgs
。
它在返回的集合中查找属性,因此它会计算包含相同参数(、等)imports
的模块中的每个 Nix 表达式。imports
config
pkgs
您必须将pkgs
中的函数作为参数(或者,从技术上讲,集合的属性,其本身就是一个参数)packages.nix
,因为从 Nix 语言的角度来看,该过程可能会或可能不会调用具有以下集合的函数:包含pkgs
.如果没有,运行时您会引用什么属性with pkgs
?
您还必须有省略号,因为该函数可能会使用其他属性来调用,而不仅仅是pkgs
.
pkgs
为什么里面没有configuration.nix
?您可以拥有它,但如果您不在文件中的任何位置引用它,则可以安全地省略它,因为省略号无论如何都会包含它们。
通过调用外部函数更新属性
另一种方法是创建一个函数,返回一个带有某些属性的集合,以及您将放入其中的该属性的值environment.systemPackages
。这是你的configuration.nix
:
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];
# SOME STUFF
environment.systemPackages = import ./packages.nix pkgs;
# SOME STUFF
}
你的packages.nix
:
pkgs: with pkgs; [ emacs gitFull ]
import ./packages.nix pkgs
意思是:加载并返回 Nix 表达式./packages.nix
,因为它是一个函数,所以用参数调用它pkgs
。with pkgs; [ emacs gitFull ]
是一个with 表达式,它将分号之前的表达式的范围带到分号之后的表达式。没有它,那就是[ pkgs.emacs pkgs.gitFull ]
。