导入nixpkgs使用flake overlays的attrValues报autoslot属性缺失错误
问题现象
使用attrValues overlays.overlays批量向nixpkgs传入overlay配置时运行失败,抛出错误error: attribute 'autoslot' missing;手动枚举overlay组成列表传入时可正常运行,相关配置如下:
{ description = "Shared settings for our packages!"; inputs = { nixpkgs.url = github:NixOS/nixpkgs/nixos-22.05; flake-utils.url = github:numtide/flake-utils; flake-compat = { url = "github:edolstra/flake-compat"; flake = false; }; }; outputs = inputs@{ self, nixpkgs, flake-utils, ... }: with builtins; with flake-utils.lib; let lib = import ./package.nix nixpkgs; overlays = with lib; rec { overlays = let lib-overlay = import ./overlay.nix nixpkgs; in j.foldToSet' [ { lib = lib-overlay; default = lib-overlay; } (j.imports.overlaySet { dir = ./callPackages/python2; func = file: final: prev: j.update.python.callPython.two final prev file; }) (j.imports.overlaySet { dir = ./callPackages/python3; func = file: final: prev: j.update.python.callPython.three final prev file; }) (j.imports.set { dir = ./overlays; recursive = true; ignores.dirs = true; }) (j.imports.overlaySet { dir = ./callPackages; call = 1; }) ]; overlay = overlays.default; defaultOverlay = overlay; }; make = system: with lib; rec { # 该写法无法正常运行 legacyPackages = import nixpkgs { inherit system; overlays = attrValues overlays.overlays; }; # 该写法可正常运行 legacyPackages = import nixpkgs { inherit system; overlays = with overlays.overlays; [ overlays.overlays.lib Python autoslot ]; }; # 问题追踪位置 packages = flattenTree (let _ = j.filters.has.attrs legacyPackages (unique (flatten [ (subtractLists (attrNames nixpkgs.legacyPackages.${system}) (attrNames legacyPackages)) (attrNames overlays.overlays) ])); in trace (attrNames legacyPackages.Python.pkgs.autoslot) _); package = packages.default; defaultPackage = package; apps.default = settings.make.app package; app = apps.default; defaultApp = app; devShells.default = import ./devShell.nix system self; devShell = devShells.default; defaultdevShell = devShell; }; in (eachSystem allSystems make) // overlays // { inherit lib; }; }
问题原因
- overlay加载顺序不符合依赖要求:
builtins.attrValues返回的属性值列表默认按属性名字典序排序,和手动枚举的lib -> Python -> autoslot顺序不一致。autoslot是Python相关overlay提供的依赖项,当依赖autoslot的overlay先于提供autoslot的overlay加载时,就会触发属性缺失错误。 - 混入冗余别名项:
overlays.overlays集合内定义了default/overlay/defaultOverlay这类自引用别名,attrValues会把这些重复指向同一个overlay的别名项也加入加载列表,重复加载会打乱属性覆盖逻辑,进一步放大顺序问题。
解决方案
- 存在跨overlay依赖的场景,不要直接用
attrValues批量取值,显式按依赖顺序指定加载列表:# 按依赖优先级从高到低排列overlay名称,被依赖的项放在前面 overlayLoadOrder = [ "lib" "Python" "autoslot" /* 其余overlay按依赖顺序补全 */ ]; loadedOverlays = builtins.map (name: overlays.overlays.${name}) overlayLoadOrder; legacyPackages = import nixpkgs { inherit system; overlays = loadedOverlays; }; - 调整overlay集合的结构,把实际生效的overlay和对外暴露的别名拆分存储,避免
attrValues取到冗余项:
如果拆分后所有overlay之间没有依赖关系,可以直接用overlays = with lib; rec { # 仅存储实际需要加载的overlay,不要在这个集合里放default/overlay这类别名 runtimeOverlays = j.foldToSet' [ { lib = lib-overlay; } (j.imports.overlaySet { dir = ./callPackages/python2; /* 其余配置保持不变 */ }) (j.imports.overlaySet { dir = ./callPackages/python3; /* 其余配置保持不变 */ }) (j.imports.set { dir = ./overlays; recursive = true; ignores.dirs = true; }) (j.imports.overlaySet { dir = ./callPackages; call = 1; }) ]; # 对外暴露的别名单独定义,不混入实际加载的overlay集合 overlay = runtimeOverlays.lib; defaultOverlay = overlay; overlays = runtimeOverlays // { default = overlay; }; };attrValues overlays.runtimeOverlays传入;如果存在跨依赖,还是需要按上一种方法显式指定加载顺序。 - 顺序排查技巧:在传入nixpkgs前打印实际加载的overlay列表,和正常运行的枚举顺序对比调整即可:
overlays = builtins.trace (builtins.map (o: o.meta.name or "unnamed-overlay") overlaysToLoad) overlaysToLoad;
内容的提问来源于stack exchange,提问作者syvlorg
相关产品推荐
相关产品推荐

