Иногда ты просыпаешься и понимаешь, что реальность выбрала насилие против тебя. Последствия этого насилия означают, что вам трудно справиться с выбором, который сделали за вас другие люди, и тогда вам просто нужно заставить все работать. Это ситуация, с которой я сталкиваюсь, когда компилирую вещи, написанные на Go , в своих конфигурациях NixOS.
Тем не менее, я нашел способ обойти эту злую судьбу и проложил новый путь. Я нашел gomod2nix
, чтобы помочь мне выбраться из этой ямы философской гибели и отчаяния. Чтобы помочь вам понять решение, я хочу воспользоваться моментом, чтобы помочь вам понять проблему и то, почему это такая огромная боль на практике.
Проблема
Большинство экосистем управления пакетами стремятся быть детерминированными. Это означает, что менеджеры пакетов хотят убедиться, что одно и то же конечное состояние достигается при одинаковых входных данных и командах. Долгое время у сообщества Go просто не было идей, как сделать управление пакетами детерминированным. Это привело к кустарной индустрии миллиардов инструментов управления версиями, которые были взаимно несовместимы, и заставляли людей использовать чрезмерно сложные стратегии разрешения зависимостей.
В какой-то момент людям в Google надоел этот хаос (хотя он их не затронул, потому что все их проекты не используют систему сборки Go, как все остальные), и предложение vgo обрушилось на всех нас. Одной из вещей, которые предлагали модули Go (тогда vgo), была идея версионных зависимостей для проектов. Это работает достаточно прилично для экосистемы Go и дает людям простые способы создания детерминированных сборок, даже если их проекты зависят от случайных репозиториев GitHub.
Основная проблема с точки зрения NixOS заключается в том, что команда Go использует метод хэширования, несовместимый с Nix. Они тоже почему-то решили изобрести свои парсеры конфигурационных файлов, у них нет проверенных в бою парсеров в никсе. Так что нам нужен мост между этими двумя мирами.

gomod2nix
— это единственный известный нам способ, который использует инструмент для кодовой генерации файла данных, полного хэшей, которые может понять Nix. В исходных nixpkgs вы бы использовали что-то вроде buildGoModule
, однако у вас гораздо больше свободы с вашими собственными проектами.Начало работы с новыми проектами
Один из самых простых способов настроить это для нового проекта Go — использовать их шаблон Nix. Для этого включите флейки и запустите эти команды в пустой папке:
nix flake init -t github:nix-community/gomod2nix#app git init
Затем добавьте все (включая сгенерированный gomod2nix.toml
) в git с помощью git add
:
git add .

Затем вы можете войти в среду разработки с помощью nix develop
и собрать свою программу с помощью nix build
. Когда вы добавляете или удаляете зависимости из своего проекта, вам нужно запустить gomod2nix
, чтобы исправить gomod2nix.toml
.
gomod2nix
Встраивание в существующие проекты
Если у вас уже есть существующая программа Go, управляемая с помощью Nix flakes, вам нужно будет добавить 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
. Это может отличаться от того, как работает ваш флейк, но в целом вам следует поискать что-то, что импортирует аргумент nixpkgs
, и добавить к нему оверлей gomod2nix
примерно так:
let pkgs = import nixpkgs { inherit system; overlays = [ gomod2nix.overlays.default ]; };
Затем вы можете использовать pkgs.buildGoApplication
, как предлагает вышестоящая документация . Если вам нужен более сложный пример использования buildGoApplication
, посмотрите мой экспериментальный репозиторий.

gomod2nix
в devShell, добавьте gomod2nix.packages.${system}.default
в список buildInputs
. Общий список инструментов может выглядеть так: devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ go gopls gotools go-tools gomod2nix.packages.${system}.default sqlite-interactive ]; };
Тогда все будет работать как обычно.