NixOS 局部构建指南:用 nix-build -A 精确构建系统配置中的任意部件
【免费下载链接】nixpkgsNix Packages collection & NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs
NixOS 的完整系统构建代价不低,但在开发调试时往往只需要其中的一小部分——一个 kernel 镜像、一棵 /etc 符号链接树,甚至单个 systemd 服务单元。本指南基于 NixOS 手册中 "Building Specific Parts of NixOS" 一章,讲明如何用nix-build -A按选项路径(attribute path)只构建配置中的特定部分,并结合 nixpkgs 仓库源码解释每个可构建部件是如何在模块系统中生成的,帮助你在不重建整个系统的前提下快速验证内核启动、单元行为与 /etc 生成结果。
基本用法:按 NixOS 选项路径构建
NixOS 配置经过模块系统求值后,会展开成一个巨大的 attrset,其中每一个类型为 derivation 的选项都可以单独被构建。基本命令是:
$ cd /path/to/nixpkgs/nixos $ nix-build -A config.option其中option是一个类型为 derivation 的 NixOS 选项,即"可构建的东西"。-A后面的属性路径以config.开头,表示引用求值后的config属性(而不是模块声明时的options元数据)。下面按手册列出的顺序,逐一说明最常用的可构建选项及其实现来源。
system.build.toplevel:整个系统的顶层推导
system.build.toplevel是构建整个 NixOS 系统的顶层选项,配置中的其余所有内容都被它间接拉入构建闭包。这正是nixos-rebuild实际构建的产物,也是构建完成后/run/current-system所指向的 store 路径。它的快捷写法是:
$ nix-build -A system从源码结构看,这个选项在 top-level.nix 中被声明为只读选项:
system.build = { toplevel = mkOption { type = types.package; readOnly = true; description = '' This option contains the store path that typically represents a NixOS system. You can read this path in a custom deployment tool for example. ''; }; };其赋值逻辑在 top-level.nix:
system.build.toplevel = if config.system.includeBuildDependencies then systemWithBuildDeps else system;这里system本身由一个pkgs.stdenvNoCC.mkDerivation构建(见 top-level.nix),其构建脚本只做轻量的链接与拷贝工作:把systemd拷贝为$out/init(或使用nixos-init流程)、把system.build.etc的 etc 树、system.path(即 sw 环境)、systemd目录软链进输出,并写出nixos-version、system等元数据文件。推导名称形如nixos-system-<system.name>-<label>,其中system.name默认取networking.hostName(见 top-level.nix)。这也解释了为什么修改networking.hostName会导致顶层推导名称变化。
system.build.manual.manualHTML:NixOS 手册
system.build.manual.manualHTML构建 NixOS 手册本身(HTML 版本)。从源码看,该构建结果在 documentation.nix 中被赋值给system.build.manual。当你需要检查自己编写的模块文档(option 描述、章节 Markdown)渲染是否正常时,可以直接构建这个部件而不必等待完整的系统构建完成。
system.build.etc:/etc 的符号链接树
system.build.etc是一棵构成/etc静态部分的符号链接树。它在 etc.nix 中生成(system.build.etc = etc;)。顶层系统构建时,正是通过ln -s ${config.system.build.etc}/etc $out/etc(见 top-level.nix)把这棵树挂进系统路径。单独构建它可以快速检查配置文件声明(services.<name>.enable等)最终产出的/etc内容,而无需执行一次完整的nixos-rebuild build。
system.build.initialRamdisk 与 system.build.kernel:快速验证内核启动
system.build.initialRamdisk和system.build.kernel分别构建系统的初始内存磁盘(initrd)与内核。这使得可以不经过完整系统、不经过引导加载器,直接用 QEMU 的-kernel与-initrd选项快速测试内核与 initrd 能否正确启动:
$ nix-build -A config.system.build.initialRamdisk -o initrd $ nix-build -A config.system.build.kernel -o kernel $ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/null内核与 initrd 的模块实现分别在 kernel.nix 和 initrd.nix 中。值得注意的一点是,initrd 还被用作system.replaceDependencies.cutoffPackages的默认值(见 top-level.nix),因为 initrd 的内部结构使得运行时依赖替换过程"失效且容易损坏"。
system.build.nixos-rebuild、nixos-install 与 nixos-generate-config:构建 NixOS 命令本身
system.build.nixos-rebuild、system.build.nixos-install、system.build.nixos-generate-config三个选项分别构建对应的 NixOS 命令行工具。这意味着nixos-rebuild等命令本身也是可构建的 derivation——你可以为不同配置版本构建不同的nixos-rebuild,用于部署时随系统一起下发。
systemd.units. .unit:单独构建并测试单个单元
systemd.units.unit-name.unit构建指定名称的 systemd 单元。systemd.units这个选项在 systemd.nix 中定义。由于单元名称本身包含点号(如httpd.service),在属性路径中必须用引号把名称包起来:
$ nix-build -A 'config.systemd.units."httpd.service".unit'更进一步,你可以不重建整个系统,单独测试某个单元的做法是把它放进/run/systemd/system:
$ cp $(nix-build -A 'config.systemd.units."httpd.service".unit')/httpd.service \ /run/systemd/system/tmp-httpd.service # systemctl daemon-reload # systemctl start tmp-httpd.service这里有一个关键细节:单元必须不能与/etc/systemd/system中任何单元同名,因为/etc/systemd/system的单元优先于/run/systemd/system。所以示例中刻意把它安装为tmp-httpd.service,避免与真实单元冲突而被遮蔽。
小结:局部构建的适用场景
归纳本手册章节,NixOS 模块系统把"整个系统"拆成了一组可按选项路径独立求值和构建的部件,每个部件对应一个明确的开发调试场景:
| 可构建选项 | 用途 | 典型场景 |
|---|---|---|
system.build.toplevel(快捷写法-A system) | 整个系统 | 等价于nixos-rebuild build的产物 |
system.build.manual.manualHTML | NixOS 手册 | 验证模块文档渲染 |
system.build.etc | /etc 静态符号链接树 | 检查配置产出文件 |
system.build.initialRamdisk/system.build.kernel | initrd 与内核 | QEMU 快速启动验证 |
system.build.nixos-rebuild等 | NixOS 命令工具 | 构建可分发的管理命令 |
systemd.units."name".unit | 单个 systemd 单元 | 不重建系统地测试单元 |
使用时只需记住一条规则:nix-build -A后的路径是 NixOS 选项的属性路径,以config.为前缀;凡路径中包含点号的名称(单元名)必须加引号。所有相关实现均可在上述仓库路径的模块源码中查证,便于进一步追踪各部件的生成逻辑。
【免费下载链接】nixpkgsNix Packages collection & NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考