如何通过Nix Flakes覆盖nixpkgs中的Haskell包?
在Nix Flakes中用本地Yesod仓库覆盖nixpkgs Haskell包的正确方案
问题根源分析
你之前遇到的几个错误,原因分别是:
- 相对路径无法被Flakes识别:Flakes构建时会将项目目录快照到Nix Store,但
./myyesod不在flake的输入列表或被跟踪的文件范围内,因此Store里找不到该路径,报错“文件不存在”。 - 输入类型处理错误:将本地仓库作为flake输入时,默认会被当作Flake处理,因此Nix会寻找
flake.nix;添加flake=false后直接引用整个仓库目录,又因为Yesod是多包仓库,未指定具体子包路径,导致生成的包依赖结构非法,触发“依赖类型无效”错误。
正确配置步骤
1. 配置Flake输入,引入本地Yesod仓库
在flake.nix的inputs部分添加本地仓库,明确声明不是Flake:
inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; myyesod = { url = "git+file:///home/chris/temp/wiptemp/1402/yesod"; flake = false; }; };
2. 在Package Overrides中替换对应子包
Yesod仓库是多包结构,需要针对每个需要替换的子包(如yesod、yesod-form、yesod-core等),用callCabal2nix指定仓库内的对应子目录。
如果是针对特定GHC版本覆盖:
outputs = { self, nixpkgs, myyesod }: let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; }; haskellPackages = pkgs.haskell.packages.ghc927.override { packageOverrides = self: super: { yesod = super.callCabal2nix "yesod" "${myyesod}/yesod" { }; yesod-form = super.callCabal2nix "yesod-form" "${myyesod}/yesod-form" { }; yesod-core = super.callCabal2nix "yesod-core" "${myyesod}/yesod-core" { }; # 根据你的项目依赖,补充其他需要替换的Yesod子包 }; }; in { # 定义你的项目包和开发Shell packages.${system}.my-project = haskellPackages.callCabal2nix "yesod-subsite-radio-field" ./src { }; devShells.${system}.default = pkgs.mkShell { buildInputs = [ haskellPackages.ghc haskellPackages.cabal-install ]; }; };
如果要全局覆盖所有Haskell编译器的包:
packageOverrides = prev.lib.composeExtensions prev.haskell.packageOverrides (_: hprev: { yesod = hprev.callCabal2nix "yesod" "${inputs.myyesod}/yesod" { }; yesod-form = hprev.callCabal2nix "yesod-form" "${inputs.myyesod}/yesod-form" { }; # 补充其他子包 });
注意事项
- 确认本地Yesod仓库的目录结构正确,每个子包在仓库根目录下有独立文件夹,且包含对应的
.cabal文件。 - 若本地仓库有未提交的修改,运行
nix flake lock --update-input myyesod可以让Nix更新锁定状态,使用最新的本地内容。 - 替换时要覆盖项目依赖的所有相关Yesod子包,避免出现混合使用nixpkgs版本和本地版本的兼容性问题。
内容的提问来源于stack exchange,提问作者Chris Stryczynski
相关产品推荐
相关产品推荐

