Добро пожаловать на шестнадцатую пилюлю Nix.
В предыдущей пятнадцатой пилюле мы выяснили, как Nix обрабатывает выражения в угловых скобках. Теперь мы знаем, где находится <nixpkgs>
.
Теперь мы готовы к погружению в репозиторий nixpkgs сквозь всё многообразие инструментов и паттернов проектирования. Хочу обратить ваше внимание на то, что у nixpkgs
есть собственное руководство. Как мы говорили выше, Nix не накладывает ограничений на то, каким должен быть репозиторий, так что nixpkgs
— всего лишь один из возможных вариантов. Разные руководства подчёркивают тот факт, что связь между Nix и nixpkgs
не такая сильная, как вы, возможно, думали.
Выражение default.nix
Вместо того, чтобы с головой погрузиться в изучение пакетов, давайте для начала разберёмся со структурой nixpkgs
в целом.
Разрабатывая собственный репозиторий, мы создали для него файл default.nix
, куда поместили выражения для нескольких пакетов.
Точно также и у nixpkgs
есть собственный default.nix, который загружается, когда кто-то ссылается на <nixpkgs>
. Он проверяет, что версия Nix не меньше, чем 1.7 (на момент написания оригинального поста — прим. переводчика), а затем импортирует pkgs/top-level/all-packages.nix. Начиная с этого момента, этот набор пакетов мы будем называть pkgs.
Настоящий файл, который объединяет все пакеты — это all-packages.nix
. Обратите внимание, что пакеты хранятся в подкаталоге pkgs/
, в то время, как сама NixOS — в подкаталоге nixos/
.
Содержимое all-packages.nix
весьма интересно. Это функция, которая принимает пару интересных параметров:
system
: значение по-умолчанию — текущая системаconfig
: значение по-умолчаниюnull
прочее...
Параметр system, если верить комментарию в выражении — это система, для которой собираются пакеты. Он, например, позволяет собирать пакеты i686 на машине amd64.
Параметр config — это просто набор атрибутов. Пакеты могут использовать эти атрибуты, чтобы менять конфигурацию дериваций.
Параметр system
Вы часто встретите этот параметр в различных выражениях .nix
, например, в выражениях выпусков (releases). Причина в том, что pkgs
принимает параметр system
, так что, импортируя pkgs
, вы можете передать в него нужное значение.
myrelease.nix:
{ system ? builtins.currentSystem }:
let pkgs = import <nixpkgs> { inherit system; };
...
Для чего это может понадобиться? Например, для того, чтобы без серьёзных ухищрений выбрать набор пакетов конкретной системы:
nix-build -A psmisc --argstr system i686-linux
Этот вызов соберёт деривацию psmisc
для i686-linux вместо x86_67-linux. Концепция очень похожа на мультиархивы Debian.
Настройка кросс-компиляции есть и в nixpkgs
, но мы не будем погружаться в изучение этого вопроса, поскольку я в нём пока не разбирался (речь про автора оригинального цикла — Люка Бруно; впрочем, переводчик тоже в вопросе не разбирался — прим. переводчика).
Параметр config
Я уверен, вы читали в wiki или других руководствах про ~/.config/nixpkgs/config.nix
(ранее — ~/.nixpkgs/config.nix
), и я уверен, вы задавались вопросом, почему этот путь «вшит» в Nix.
На самом деле, он вшит не в Nix, а в nixpkgs.
Выражение all-packages.nix
принимает параметр config
. Если там содержится null
, функция ищет переменную окружения NIXPKGS_CONFIG
. Если переменная не найдена, nixpkgs
обращается к $HOME/.config/nixpkgs/config.nix
.
При обнаружении config.nix
, он будет импортирован как выражение Nix, которое и станет значением config
(конечно, в том случае, если параметр не был явно передан при импорте <nixpkgs>
).
Значение config
доступно после импорта репозитория:
$ nix repl
nix-repl> pkgs = import <nixpkgs> {}
nix-repl> pkgs.config
{ }
nix-repl> pkgs = import <nixpkgs> { config = { foo = "bar"; }; }
nix-repl> pkgs.config
{ foo = "bar"; }
Что указывать в config
— вопрос удобства и соглашений.
Например, config.allowUnfree
— атрибут, запрещающий сборку пакетов, чья лицензия по умолчанию не является свободной. Настройка config.pulseaudio
подсказывает, собирать ли пакеты с поддержкой PulseAudio, если это возможно и если деривация это умеет.
О функциях .nix
Файл .nix
содержит выражение Nix, которое может быть функцией. Напомню, что nix-build
обрабатывает только те выражения, результатом которых является деривация. Так что вполне естественно возвращать деривацию напрямую из файла .nix
. Кроме того, вполне естественно передавать в файл .nix
параметры, помогающие настроить эту деривацию.
Для таких случае Nix использует трюк:
Если выражение является деривацией, собрать её.
Если выражение является функцией, вызвать её и собрать деривацию, которую она вернула.
Например, с помощью nix-build
можно собрать такой файл:
{ pkgs ? import <nixpkgs> {} }:
pkgs.psmisc
Nix может вызвать функцию, поскольку у параметра pkgs
есть значение по умолчанию. Вы можете передать другое значение pkgs
, используя опцию --arg.
Останется ли схема рабочей, если у вас будет функция, которая возвращает функцию, которая возвращает деривацию? Нет, Nix вызывает найденную функцию только один раз.
Заключение
Мы разобрались с тем, что из себя представляет репозиторий <nixpkgs>
. Это функция, которая принимает несколько параметров и возвращает набор всех пакетов. Из-за ленивых вычислений, собраны будут только те деривации, к которым вы обратитесь.
Вы можете использовать этот репозиторий, чтобы собирать собственные пакеты, как мы сделали в предыдущей пилюле, создавая наш собственный репозиторий.
В последнее время я немного занят выпуском NixOS 14.11 и другими вещами, а также думаю о переходе с Blogger на другую блог-платформу, больше ориентированную на программистов.
Поэтому прошу прощения, что пишу редко и мало (снова речь идёт об авторе оригинального цикла Люка Бруно — прим. переводчика).
В следующей пилюле
...мы поговорим о переопределении пакетов в репозитории nixpkgs
. Что, если бы вам захотелось изменить несколько параметров вашей библиотеки? Смогут ли пакеты, настроив параметры, подключить новую библиотеку вместо старой? Одна из возможностей, как мы узнали в этой главе — использование параметра config
. Однако у этого подхода есть ограничения. А другой способ — это переопределение дериваций.