За последние несколько недель мы рассмотрели две основные системы сборки, которые люди используют для Haskell, Stack и Cabal. Однако эти системы специфичны для Haskell. Например, вы не сможете создать проект на C ++ или Node.js с помощью Cabal. Однако на этой неделе мы собираемся обсудить Nix, более широко применимый менеджер пакетов.

Мы могли использовать Nix для проекта практически на любом языке программирования. Однако он, как правило, привлекает непропорционально много внимания разработчиков Haskell. На это есть несколько причин. Во-первых, другие языки, как правило, имеют более зрелые цепочки инструментов, чем Haskell. Так что нет необходимости исследовать альтернативные решения, такие как Nix. Во-вторых, авторы Nix описывают его как «чисто функциональный» менеджер пакетов. Таким образом, его дизайн и функциональность включают в себя множество идей, привлекающих хаскеллеров.

Итак, в этой статье мы собираемся обсудить основные функции Nix. Он имеет несколько особых преимуществ, связанных с его функциональным характером. Мы также проведем ускоренный курс по некоторым основным командам. На следующей неделе мы начнем изучать с ним еще несколько специфичных для Haskell задач.

Несмотря на то, что Nix имеет множество интересных функций, он также требует сложного обучения. Так что, если вы новичок в Haskell, я настоятельно рекомендую вам начать со Stack. Прочтите нашу Серия Liftoff и пройдите наш бесплатный Мини-курс по стеку, чтобы узнать больше!

Установка и основные команды

Для начала давайте установим Nix. Это достаточно просто на машине с Linux или MacOS. Вам просто нужно curl скрипт установки и запустить его:

bash <(curl https://nixos.org/nix/install)

После того, как у вас будет Nix, вы сможете устанавливать пакеты из «каналов». Канал - это механизм, который позволяет вам получать готовые двоичные файлы и библиотеки. В некотором смысле он работает как Hackage, но для всех типов программ. Установив, вы получите стабильный канал по умолчанию.

Основная команда, которую вы будете использовать, - nix-env. Это позволяет вам взаимодействовать с пакетами на канале и в вашей системе. Например, nix-env -qa отобразит все доступные пакеты, которые вы можете установить из канала. Чтобы установить пакет, вы будете использовать параметр -i (или --install). Эта команда установит базовую программу GNU hello:

>> nix-env -i hello
...
Installing 'hello-2.10'
>> hello
Hello, world!

Вы также можете удалить программу с помощью опции -e. Если вы предпочитаете протестировать программу, не устанавливая ее, вы можете создать для нее оболочку nix! Команда nix-shell для вызовет оболочку, в которой для вас установлена ​​программа:

>> nix-env -e hello
>> hello
No such file or directory
>> nix-shell -p hello
[nix-shell:~]$ hello
Hello, world!
[nix-shell:~]$ exit

Эти простые команды позволяют загружать пакеты других людей. Но самое интересное - использовать Nix для создания собственных пакетов. Мы вернемся к этому на следующей неделе!

Совместимость с Windows

Как следует из названия, авторы Nix разработали его для операционных систем на основе Unix. Таким образом, его не существует для Windows. Если вы программируете на машине с Windows, лучше всего использовать подсистему Windows для Linux (WSL). Другой вариант - это какой-то виртуальный ящик, но он сильно замедлит вас.

На своей машине я обнаружил, что мне нужно немного взломать, чтобы установить Nix на WSL. Вместо обычной установки я последовал совету из this pull request. При установке вам понадобится следующая строка в уже существующем /etc/nix/nix.conf файле.

use-sqlite-wal = false

Вы можете сделать это вручную или использовать эту команду при установке:

>> echo 'use-sqlite-wal = false' | \
  sudo tee -a /etc/nix/nix.conf && sh <(curl https://nixos.org/nix/install)

После этого все должно заработать!

Песочница на стероидах

А теперь давайте подробнее рассмотрим функциональность Nix. Что означает, что Nix - это «функциональный» менеджер пакетов? Во-первых, наши действия не должны иметь «побочных эффектов». В случае управления пакетами это означает, что мы можем установить программу без воздействия на другие программы на нашем компьютере. По сути, это крайняя форма песочницы.

Когда вы устанавливаете Nix, он создает специальную папку /nix/store в корне вашей системы. Когда вы используете Nix, все пакеты, которые вы загружаете и создаете на своем компьютере, получают свой собственный подкаталог. Например, когда мы установили hello, мы получаем следующий каталог:

/nix/store/234v87nsmj70i1592h713i6xidfkqyjw-hello-2.10

Обратите внимание, что с нашим пакетом связан специальный хэш. Это важно. Мы потенциально можем обновить наш канал, чтобы проверить наличие более новой версии. Тогда мы могли бы установить и это. Это может создать подобный каталог с другим (гипотетическим) хешем:

>> nix-env --upgrade hello
>> ls /nix/store
/nix/store/abcd123smj70iqaswe713i6xidfpogjq-hello-2.11
...

Но оригинальная версия hello все равно будет в нашем магазине! Обновление и переустановка не повлияют на него, и он будет работать как раньше. А если нам не понравилась новая версия, мы могли ее откатить!

nix-env --rollback

Входы и выходы

Теперь давайте разберемся, что происходит с этими хешами. Каждый пакет nix также является «функциональным» в том смысле, что он является функцией его конкретных входных данных. То есть у каждого пакета есть некоторый список зависимостей, а также исходный код. И мы можем воспроизвести выходной двоичный файл с этих входов детерминированным образом.

Хэш, который мы получаем перед пакетом, создается из всех различных входных данных. Поэтому, если мы изменим зависимости для нашего пакета, мы получим новый хэш, поскольку результат может быть другим. И если мы изменим исходный код, наш хеш также должен быть другим, поскольку мы создаем новую программу.

Поэтому, когда мы определяем наш собственный пакет Nix, мы будем описывать его зависимости, используя язык Nix. Это будет включать в себя перечисление версий и конфигураций сборки в файле .nix. Это позволяет нам создавать «производные» нашей программы. И реальный результат состоит в том, что это происхождение будет одинаковым, независимо от того, на какой машине вы работаете! Nix гарантирует, что он загрузит все одинаковые зависимости и скомпилирует их одинаковым образом.

Вывод

Надеюсь, теперь вы хорошо знакомы с основами Nix. На следующей неделе мы начнем изучать, как создавать собственные проекты Nix. Мы рассмотрим объединение возможностей Cabal и Nix для создания проекта Haskell!