mcpField
N
nix-platform-specific-options

nix-platform-specific-options

github.com/edmundmiller开发8044 次安装今天更新
代码仓库

关于 nix-platform-specific-options

nix-platform-specific-options 是编写含平台相关选项的 Nix 模块参考技能,说明如何用 optionalAttrs 处理平台检查、用 mkIf 处理配置条件,以避免选项缺失错误和无限递归。

主要功能

  1. 01区分平台检查与配置检查
  2. 02隐藏特定平台的选项路径
  3. 03避免模块求值时无限递归
  4. 04使用静态选项默认值并在配置中解析
  5. 05排查常见递归模式

适用场景

  1. 01编写 NixOS 和 Darwin 专属模块选项
  2. 02排查跨平台的选项缺失错误
  3. 03查找导致递归的 config 引用

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/edmundmiller/dotfiles --skill nix-platform-specific-options

安装后在 Claude Code 中输入/nix-platform-specific-options确认已加载。

详细介绍

Nix 模块的平台特定选项

概述

编写需要隐藏平台特定选项(NixOS 与 Darwin)的 Nix 模块时,仅使用 mkIf 会导致无限递归。本指南介绍了正确的模式。

问题

mkIf 会惰性求值,但选项路径在模块求值期间仍然可见。这会导致如下错误:

error: The option `users.defaultUserShell' does not exist.

或者,当在选项默认值或 optionalAttrs 条件中引用 config 时,导致无限递归。

模式

平台检查使用 optionalAttrs,依赖配置的检查使用 mkIf。

检查类型工具求值时机
平台(isDarwin、!isDarwin)optionalAttrs解析时
配置值(cfg.enable、cfg.flavor)mkIf惰性

示例

❌ 错误:使用 mkIf 进行平台检查
config = mkIf (!isDarwin) {
  users.defaultUserShell = pkgs.zsh;  # Darwin sees this path!
};
✅ 正确:使用 optionalAttrs 进行平台检查
config = optionalAttrs (!isDarwin) {
  users.defaultUserShell = pkgs.zsh;  # Hidden from Darwin
};
❌ 错误:在 optionalAttrs 条件中使用配置值
# cfg.flavor evaluated at parse time → infinite recursion
(optionalAttrs (isDarwin && cfg.flavor == "personal") {
  services.onepassword-secrets.enable = true;
})
✅ 正确:在 optionalAttrs 内嵌套 mkIf
# Platform check at parse time, config check lazy
(optionalAttrs isDarwin (mkIf (cfg.flavor == "personal") {
  services.onepassword-secrets.enable = true;
}))
❌ 错误:在选项默认值中引用 config
options.modules.foo = {
  user = mkOpt types.str config.user.name;  # Infinite recursion!
};
✅ 正确:使用静态默认值,在 config 部分使用 config
options.modules.foo = {
  user = mkOpt types.str null;
};

config = mkIf cfg.enable (let
  user = if cfg.user != null then cfg.user else config.user.name;
in {
  # Use 'user' variable here
});

组合模式

对于同时包含平台特定选项和依赖配置的行为的模块:

config = mkIf cfg.enable (mkMerge [
  # Common config (all platforms)
  { /* ... */ }

  # Darwin-only options
  (optionalAttrs isDarwin {
    programs.zsh.interactiveShellInit = "...";
  })

  # NixOS-only options
  (optionalAttrs (!isDarwin) {
    users.defaultUserShell = pkgs.zsh;
  })

  # Darwin + config-dependent (nested)
  (optionalAttrs isDarwin (mkIf (cfg.flavor == "personal") {
    services.onepassword-secrets.enable = true;
  }))
]);

快速参考

场景模式
仅适用于 NixOS 的选项optionalAttrs (!isDarwin) { ... }
仅适用于 Darwin 的选项optionalAttrs isDarwin { ... }
平台 + 启用检查optionalAttrs isDarwin (mkIf cfg.enable { ... })
平台 + 配置值optionalAttrs isDarwin (mkIf (cfg.foo == "bar") { ... })
默认选项来自配置默认值使用 null,在 config 部分解析

调试

看到提及 _module.freeformType 或 anon-43 的无限递归错误时:

  1. 搜索选项默认值中的 config. 引用
  2. 搜索 optionalAttrs 条件中的 cfg. 引用
  3. 搜索用于保护平台特定选项的 mkIf (!isDarwin) 或 mkIf isDarwin
# Find problematic patterns
grep -rn "mkOpt.*config\." modules/
grep -rn "optionalAttrs.*cfg\." modules/
grep -rn "mkIf.*isDarwin" modules/

评论

支持 Markdown