Nix中derivation类set为何表现异常且无法转换为JSON?
其实你遇到的核心问题是搞混了Nix里两种看起来相似但本质完全不同的东西:普通属性集合(attrset)和构建派生对象(derivation)。我来一步步给你拆解原因:
1. 类型本质的差异
普通的{ a = 1; b = 2; }是标准的attrset(属性集合),它就是单纯的键值对容器,所有属性都可以直接访问,也能被builtins.toJSON正常序列化。
而你通过Flake拿到的cosmos-shell是一个derivation(构建派生对象)——虽然builtins.typeOf会返回set(这是Nix类型系统里的一个小细节,derivation属于广义的set范畴,但有特殊的封装行为),但它本质是Nix用来描述“如何构建某个软件包”的特殊对象,内部存储的是构建所需的元数据(比如依赖项、构建脚本、输出路径等),而非普通的键值对。
2. 为什么无法直接获取定义它的元素?
当你通过Flake引用一个包时,拿到的是经过mkDerivation(或类似构建函数)处理后的最终derivation实例,而不是定义这个包的原始attrset。打个比方:原始attrset是“蛋糕配方”,derivation是“已经准备好烘焙的半成品”——你拿到的是半成品,自然看不到完整的配方细节。
如果想获取定义这个包的原始属性,你需要找到Flake中暴露原始配置的入口(比如有些Flake会把src或者完整的构建attrset作为额外输出),但这完全取决于Flake作者的设计,没有统一的方法。
3. 如何查看Derivation的内部信息?
如果你想了解这个derivation的构建细节,可以用以下方法:
- 在命令行中,用
nix show-derivation命令查看完整元数据:nix show-derivation $(nix eval --raw github:<flake-repo>#packages.<arch>.cosmos-shell) - 在Nix表达式中,能直接访问的derivation属性非常有限,比如
outPath可以获取最终输出的存储路径,builtins.parseDrvName可以解析derivation路径的名称部分,但大部分内部构建元数据无法通过普通属性访问。
4. 为什么builtins.toJSON无法转换?
builtins.toJSON只能处理静态的、可序列化的Nix值(比如attrset、字符串、数字、列表),而derivation是一个动态的构建引用,它代表的是“一个即将被构建的产物”,而非静态数据,所以Nix不允许直接将其序列化为JSON。
内容的提问来源于stack exchange,提问作者Pierre-olivier Gendraud

