图片由 Waifu Diffusion v1.3 (float16) 生成 — Baby blue gopher, laptop computer, starbucks, 1girl, hacker vibes, manga, thick outlines, evangelion, angel attack, chibi, cat ears
有时你醒来,意识到现实选择了对你的暴力。这种暴力的后果意味着很难应对其他人为您做出的选择,然后您只能让事情顺利进行。这是我在 NixOS 配置中编译用Go编写的东西时遇到的情况。
然而,我已经找到了摆脱这种邪恶命运的方法,并开辟了一条新的道路。我发现gomod2nix
可以帮助我摆脱哲学上的厄运和绝望。为了帮助您理解解决方案,我想花点时间帮助您理解这个问题以及为什么它在实践中如此痛苦。
问题
大多数包管理生态系统都力求确定性。这意味着包管理器希望确保在给出相同的输入和命令时实现相同的最终状态。很长一段时间,Go 社区根本没有让包管理具有确定性的故事。这导致了十亿个版本管理工具的家庭手工业,这些工具相互不兼容,并导致人们使用过于复杂的依赖关系解决策略。
在某些时候,谷歌的人们已经受够了这种混乱(尽管他们没有受到影响,因为他们的所有项目都没有像其他人一样使用 Go 构建系统)并且vgo 提案向我们所有人释放了。 Go 模块(当时是 vgo)提供的其中一件事是项目的版本依赖关系的想法。这对于 Go 生态系统来说工作得很好,并为人们提供了创建确定性构建的简单方法,即使他们的项目依赖于随机的 GitHub 存储库。
从 NixOS 的角度来看,主要问题是 Go 团队使用了与 Nix 不兼容的哈希方法。出于某种原因,他们还决定发明自己的配置文件解析器,这些解析器在 Nix 中没有任何经过实战检验的解析器。所以我们需要在这两个世界之间架起一座桥梁。
gomod2nix
是我们所知道的唯一方法,它使用一种工具来代码生成一个 Nix可以理解的充满哈希的数据文件。在上游 nixpkgs 中,您可以使用buildGoModule
类的东西,但是您对自己的项目有更多的自由。开始新项目
为新的 Go 项目设置它的最简单方法之一是使用他们的 Nix 模板。为此,启用 flakes并在空文件夹中运行这些命令:
nix flake init -t github:nix-community/gomod2nix#app git init
然后使用git add
将所有内容(包括生成的gomod2nix.toml
)添加到 git 中:
git add .
然后您可以使用nix develop
进入开发环境并使用nix build
build 构建您的程序。当您在项目中添加或删除依赖项时,您需要运行gomod2nix
来修复gomod2nix.toml
。
gomod2nix
将其移植到现有项目中
如果你已经有一个使用 Nix flakes 管理的现有 Go 程序,你需要将gomod2nix
添加到你的 flake 输入,nixpkgs 覆盖,然后在你的packages
输出中使用它。将此添加到您的inputs
中:
{ inputs = { nixpkgs.url = "nixpkgs/nixos-unstable"; utils.url = "github:numtide/flake-utils";
gomod2nix = { url = "github:tweag/gomod2nix"; inputs.nixpkgs.follows = "nixpkgs"; inputs.utils.follows = "utils"; }; }; }
然后您需要将它添加到outputs
函数的参数中:
outputs = { self, nixpkgs, utils, gomod2nix }:
最后将其覆盖应用到您的nixpkgs
导入。这可能与你的 flake 的工作方式不同,但通常你应该寻找导入nixpkgs
参数的东西并向它添加gomod2nix
覆盖,如下所示:
let pkgs = import nixpkgs { inherit system; overlays = [ gomod2nix.overlays.default ]; };
然后,您可以按照上游文档的建议使用pkgs.buildGoApplication
。如果您想要一个更复杂的使用buildGoApplication
的示例,请查看 我的实验性存储库。
gomod2nix
工具,请将gomod2nix.packages.${system}.default
添加到buildInputs
列表中。工具的总列表可能如下所示: devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ go gopls gotools go-tools gomod2nix.packages.${system}.default sqlite-interactive ]; };
然后一切都会正常工作。