Упаковка программного обеспечения с помощью Nix

Реплики Replit работают на базе Nix. Nix — это инструмент для управления пакетами программного обеспечения и системными конфигурациями. Сообщество Nix также поддерживает Nix Packages Collection (Nixpkgs), официальный репозиторий пакетов Nix. Он содержит более 50 000 проектов. Велики шансы, что нужное вам программное обеспечение уже находится там! Вы можете искать пакеты на сайте NixOS (пользователи DuckDuckGo могут использовать команду !nixpkg bang).

Однако, несмотря на то, что NixOS является крупнейшим хранилищем упакованного программного обеспечения (на момент написания статьи), существует программное обеспечение, которое не было упаковано в Nix Package Set. Если вам нужно что-то упаковать, чтобы использовать это в Nix, вы можете сделать запрос на упаковку, но тогда вам придется ждать, пока доброволец упакует это для вас. Гораздо быстрее научиться упаковывать самостоятельно!

Упаковывать программы в Nix проще, чем в большинстве других репозиториев. Язык Nix представляет собой DSL специально разработанный для упаковки программного обеспечения. Отчасти поэтому Nixpkgs имеет наибольшее количество пакетов, несмотря на то, что у него всего лишь около шестой части мейнтейнеров репозитория с наибольшим количеством мейнтейнеров, AUR (2182 против 12292).

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

Для начала давайте поговорим о получении программ. Прежде чем упаковывать что-либо, нам нужно получить его копию.

Получение программного обеспечения

Прежде чем мы сможем собрать пакет, нам нужно получить либо исходный код, либо, если исходный код недоступен, двоичный файл. В Nix есть много различных фетчеров, которые мы можем использовать для получения файлов.

Nix изо всех сил старается быть воспроизводимым, то есть гарантировать, что всякий раз, когда вы собираете пакет с одними и теми же исходными данными, он дает вам точно такой же результат. Когда мы получаем что-то из сети, мы должны быть уверены, что то, что мы получили, это то, что мы ожидали. Вот почему все Nix fetchers требуют, чтобы вы предоставили хэш ожидаемого файла. Хэш — это короткое, характерное представление некоторых данных. Это как цифровой отпечаток пальца. Если хэш загруженного файла совпадает с хэшем ожидаемого файла, мы можем быть уверены, что получили именно тот файл, который ожидали. Nix поддерживает хэши md5, sha1, sha256 и sha512, хотя первые два устарели и больше не должны использоваться.

Как получить хэш файла? Некоторые проекты публикуют хэши или контрольные суммы своих загрузок на своем сайте. Если это так, используйте то, что они вам предоставили. Если нет, вы можете скачать файл самостоятельно, а затем запустить программу типа sha256sum для получения хэша. Это хорошо работает для простых файлов, но становится немного сложнее, когда вы используете fetcher вроде fetchFromGitHub для получения определенной версии репозитория Git. Простой обходной путь — заполнить хэш нелепым значением, а затем попытаться собрать пакет. Nix прервет сборку после выборки, поскольку хэш не совпадет, но он выведет хэш того, что он нашел, в консоль. Вы можете скопировать это значение и использовать его в качестве правильного хэша. Повторный запуск сборки теперь должен пройти успешно.

Кроме того, существуют инструменты командной строки, которые могут выполнить предварительную выборку файла за вас. Они получат файл, поместят его в хранилище Nix и выведут хэш на консоль. Команда nix-prefetch-url устанавливается в стандартную среду Nix, включая Replit repls. Оба nix-prefetch-git и nix-prefetch-github находятся в Nixpkgs (поэтому их можно легко установить с помощью replit.nix) и работают аналогично. Для более продвинутого использования можно использовать nix-prefetch, также в Nixpkgs, который может выполнять предварительную выборку с помощью любого фетчера Nix.

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

Выборка файлов и архивов с помощью fetchurl и fetchzip.

Самым простым фетчером является fetchurl. Он забирает файл и помещает его в хранилище Nix. Фетчер fetchzip очень похож, но он распакует архив, прежде чем сохранить его в хранилище Nix. Это полезно, если вам нужно обратиться к конкретным файлам из архива, а не к загрузке в целом. Несмотря на свое название, он может работать с разными форматами архивов, а не только с zip-файлами. В общем, если вам не нужно ссылаться на конкретный файл в архиве в выражении Nix, используйте fetchurl, который не будет распаковывать архив перед тем, как поместить его в хранилище Nix. Это сэкономит место, и, как мы подробнее рассмотрим позже, архивы в любом случае автоматически распаковываются в процессе сборки.

Войдите в Replit или создайте учетную запись, если вы еще этого не сделали. После входа в систему создайте новый пустой Repl.

Найдите файл replit.nix в вашей программе repl. Если вы не видите его на боковой панели «Файлы», выберите в меню «Показать скрытые файлы».

Отредактируйте replit.nix, чтобы он выглядел следующим образом:

{ pkgs }:

let
  hello = pkgs.stdenv.mkDerivation rec {
    pname = "hello";
    version = "2.12";
    src = pkgs.fetchurl {
      url = "mirror://gnu/hello/hello-${version}.tar.gz";
      sha256 = "1111111111111111111111111111111111111111111111111111";
    };
  };
in {
  deps = [
    hello
  ];
}
Войти в полноэкранный режим Выйти из полноэкранного режима

После внесения этих изменений в replit.nix, откройте вкладку «Консоль» и нажмите Enter. Вывод должен быть аналогичным:

Nix сообщает нам хэш файла, который он извлек, в данном случае: 1ayhp9v4m4rdhjmnl2bq3cibrbqqkgjbl3s7yk2nhlh8vj3ay16g. Ваш вывод может отличаться, это просто означает, что вы используете обновленную версию Nixpkgs, поэтому stdenv был обновлен; поскольку это зависимость производной, которую производит stdenv.mkDerivation, и поскольку хэши производных зависят от хэшей входных производных, хэш вашей производной тоже изменится.

Теперь, когда у нас есть настоящий хэш, скопируйте его в атрибут sha256 в производной, нажмите Enter в консоли, которая примет изменение, и Nix успешно соберет пакет hello — хотя он ничего не выдаст, когда это произойдет. Команда hello будет добавлена в ваше окружение. Если вы ее запустите, программа hello просто выдаст на консоль эхо «Hello, world!». На первый взгляд, это не очень полезная программа, но на самом деле ее назначение — помогать тестировать системы упаковки. Теперь мы знаем, что наша работает!

Если вы были особенно внимательны, вы могли заметить, что Nix говорит нам, что будет собрано два производных, хотя мы просим его собрать только одно. Это потому, что каждый фетчер на самом деле создает производную: извлеченный файл, который добавляется в хранилище Nix. Пакеты Nix могут зависеть только от того, что находится в Nix Store, поэтому, чтобы собрать hello, нам нужно, чтобы его исходный код тоже был помещен в Nix Store. Поскольку у нас его еще нет, его нужно сначала «собрать» (в данном случае — извлечь). На самом деле fetcher — это особый тип конструктора.

Мы также могли бы получить тот же хэш с помощью nix-prefetch-url:

nix-prefetch-url https://ftpmirror.gnu.org/hello/hello-2.12.tar.gz
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы можете скопировать строку 1ayhp9v4m4rdhjmnl2bq3cibrbqqkgjbl3s7yk2nhlh8vj3ay16g в поле sha256 в производной, и это также будет работать (опять же, ваш фактический хэш может быть другим). Иногда хэши имеют другой формат, но это не проблема. Nix fetchers понимают различные типы хэшей, представленных в различных форматах.

Некоторые замечания по поводу хэшей

В нашем первом примере мы изначально предоставили хэш, который, как мы знали, был неверным, чтобы Nix вывел правильный хэш в сообщении об ошибке несоответствия хэша. Доверие к хэшу, который Nix выдает нам обратно, — это подход, называемый доверием при первом использовании. Мы предполагаем, что файл, который Nix действительно извлек, является правильным. Для многих целей это нормально.

Если у вас в производной настоящий хэш, а не фиктивный, и вы все равно получаете эту ошибку, тщательно попытайтесь выяснить, что могло произойти, поскольку это означает, что Nix сообщает вам, что файл, который он действительно извлек, не тот, который вы ожидали. Возможно, загрузка была повреждена из-за проблем с сетью, и в этом случае повторная попытка может оказаться успешной; или целевой файл был изменен на сервере. Это может произойти, если вы пытаетесь загрузить с URL-адреса, который не предоставляет стабильную версию, или если злоумышленник тайно заменил файл. Если вы не уверены, попробуйте выяснить у доверенной стороны, например, у издателей кода, все ли в порядке.

Вы можете заметить, что хэш, который Nix вычисляет для файла, не совпадает с хэшем, который вычисляет sha256sum. На самом деле это один и тот же хэш, но они закодированы по-разному. Большинство инструментов хэширования выводят хэш в шестнадцатеричном формате (base 16), но Nix предпочитает свой собственный нестандартный формат base 32, потому что он короче (это base 32, но в нем не используются символы e, o, u и t, чтобы уменьшить вероятность оскорбительных последовательностей букв). Чтобы преобразовать хэш с основанием 16 в хэш с основанием 32 или наоборот, используйте nix-hash:

$ nix-hash --to-base32 --type sha256 cf04af86dc085268c5f4470fbae49b18afbc221b78096aab842d934a76bad0ab
1ayhp9v4m4rdhjmnl2bq3cibrbqqkgjbl3s7yk2nhlh8vj3ay16g
$ nix-hash --to-base16 --type sha256 1ayhp9v4m4rdhjmnl2bq3cibrbqqkgjbl3s7yk2nhlh8vj3ay16g
cf04af86dc085268c5f4470fbae49b18afbc221b78096aab842d934a76bad0ab
Войти в полноэкранный режим Выйти из полноэкранного режима

Вам не нужно кодировать хэши в пользовательском формате base 32 Nix перед их использованием. Обычный формат base 16 работает отлично.

Получение Git-репозиториев с помощью fetchgit.

Если нужный вам исходный код находится в Git-репозитории, вы можете использовать fetchgit. Он ожидает по крайней мере один дополнительный атрибут по сравнению с fetchurl, атрибут rev. Это может быть полный идентификатор коммита Git (хэш sha1) или имя тега, например v2.12.

Попробуйте использовать следующий файл replit.nix:

{ pkgs }:

let
  hello = pkgs.stdenv.mkDerivation rec {
    pname = "hello";
    version = "2.12";
    src = pkgs.fetchgit {
      url = "https://github.com/ritza-co/simple-hello-world-demo.git";
      rev = "v${version}";
      sha256 = "1111111111111111111111111111111111111111111111111111";
    };
  };
in {
  deps = [
    hello
  ];
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Еще раз, после изменения replit.nix, откройте вкладку Console и нажмите Enter. Вывод должен быть аналогичным:

Detected change in environment, reloading shell...
nix error: building nix env: exit status 102
Output has been trimmed to the last 20 lines
executing builder '/nix/store/bm7jr70d9ghn5cczb3q0w90apsm05p54-bash-5.1-p8/bin/bash'
building '/nix/store/6drp4pmqj67b3ysy88fhawz4fdf2kwkb-simple-hello-world-demo.drv'...
exporting https://github.com/ritza-co/simple-hello-world-demo.git (rev v2.12) into /nix/store/hmmp6c24wg43d9cbslmhgrrccvhhaxac-simple-hello-world-demo
Initialized empty Git repository in /nix/store/hmmp6c24wg43d9cbslmhgrrccvhhaxac-simple-hello-world-demo/.git/
remote: Enumerating objects: 462, done.
remote: Counting objects: 100% (462/462), done.
remote: Compressing objects: 100% (333/333), done.
remote: Total 462 (delta 127), reused 462 (delta 127), pack-reused 0
Receiving objects: 100% (462/462), 1.09 MiB | 7.15 MiB/s, done.
Resolving deltas: 100% (127/127), done.
From https://github.com/ritza-co/simple-hello-world-demo
 * tag               v2.12      -> FETCH_HEAD
Switched to a new branch 'fetchgit'
removing `.git'...
hash mismatch in fixed-output derivation '/nix/store/bj8zf0n8xdfrkj5mndmlhg34ac3pd91l-simple-hello-world-demo':
  wanted: sha256:1111111111111111111111111111111111111111111111111111
  got:    sha256:1mc1vrixpkzkdnvpzn3b01awvha6z7k2dnpai3c6g89in8l1wr70
cannot build derivation '/nix/store/gw50rkh9d2m4hxiyyldcz6wk0hf76pkx-hello.drv': 1 dependencies couldn't be built
error: build of '/nix/store/gw50rkh9d2m4hxiyyldcz6wk0hf76pkx-hello.drv' failed
Вход в полноэкранный режим Выход из полноэкранного режима

Замена sha256 в производной на 1mc1vrixpkzkdnvpzn3b01awvha6z7k2dnpai3c6g89in8l1wr70 позволит сборке пройти успешно (ваш хэш может быть другим, проверьте строку got: sha256:).

Существуют также fetchers для других репозиториев контроля версий, например fetchsvn, fetchhg или fetchcvs.

Получение кода из GitHub с помощью fetchFromGitHub.

Фильтр fetchFromGitHub не принимает атрибут url, заменяя его атрибутами owner и repo.

Попробуйте использовать следующий файл replit.nix:

{ pkgs }:

let
  hello = pkgs.stdenv.mkDerivation rec {
    pname = "hello";
    version = "2.12";
    src = pkgs.fetchFromGitHub {
      owner = "ritza-co";
      repo = "simple-hello-world-demo";
      rev = "v${version}";
      sha256 = "1111111111111111111111111111111111111111111111111111";
    };
  };
in {
  deps = [
    hello
  ];
}
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Существуют также fetchers для других форков Git, например fetchFromGitLab, fetchFromBitbucket или fetchFromSavannah. Большинство из них работают так же, как fetchFromGitHub.

Сборка пакета

Теперь, когда мы знаем, как получить исходный код, нам нужно знать, как собрать его в реальное программное обеспечение. Наша маленькая программа hello построена стандартным образом, и опции по умолчанию, используемые stdenv.mkDerivation, идеально подходят для нее. Большинство программ не так просты, и нам придется подстроить некоторые из этих опций.

Для некоторых распространенных типов программ в Nix есть специальные конструкторы, которые облегчают создание этих типов программ. Примерами могут служить программы на Python или C#.

Стандартным» конструктором является stdenv.mkDerivation. Специальные конструкторы обычно являются обертками вокруг stdenv.mkDerivation, поэтому они многое наследуют от него. Если программа, которую вам нужно собрать, написана на C или вы не можете найти для нее специализированный конструктор, используйте для сборки stdenv.mkDerivation.

Даже если для вашей программы есть специальный конструктор, вероятно, будет полезно прочитать следующий раздел stdenv.mkDerivation, чтобы понять основы сборки пакета в Nix.

Сборка с помощью stdenv.mkDerivation

До сих пор мы не объяснили, что такое деривация в Nix. Деривация — это набор атрибутов, который сообщает Nix, что ему нужно знать для сборки пакета.

Он содержит информацию о:

  • От каких других производных, если таковые имеются, зависит производная;
  • Какой сценарий сборки использовать;
  • Для какой платформы производить сборку;
  • Какие аргументы и переменные окружения должны быть доступны сборщику; и
  • Куда Nix должен поместить результаты сборки.

В качестве заключительной части оценки выражения Nix, которое создает производную, Nix сохраняет набор атрибутов производной на диск в хранилище Nix в виде файла .drv. Он представляет собой действие сборки. Позже, на этапе сборки, Nix будет использовать этот файл .drv для сборки пакета, который он описывает. Если вы хотите посмотреть, как выглядит такой файл, выполните следующую команду в консоли:

nix show-derivation $(which hello)
Войти в полноэкранный режим Выйти из полноэкранного режима

Это покажет вам производный файл hello, который был использован Nix для его создания.

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

В Nix есть встроенная функция derivation, которая создает наборы атрибутов производных, но мы обычно используем вместо нее stdenv.mkDerivation, которая проще в использовании. Построитель stdenv.mkDerivation не встроен в сам язык Nix. Он является частью Nixpkgs и развивался со временем по мере того, как сообщество создавало все больше и больше пакетов, включая свои наработки в полезные абстракции.

Минимальные атрибуты, которые нужны stdenv.mkDerivation — это name и src. Если name не предоставлено, он попытается создать его из pname + version: "${pname}-${version}".

Конструктор stdenv.mkDerivation автоматизирует общие задачи сборки и предоставляет общие инструменты Unix: gcc, coreutils/findutils/diffutils, sed/grep/awk, tar/gzip/bzip2/xz, make, bash, и patch. Если ваш пакет использует стандартную процедуру сборки Unix ./configure; make; make install (как в нашем предыдущем примере hello), вам вообще не нужно настраивать стандартную сборку. Если stdenv.mkDerivation не работает автоматически, вы можете легко настроить или переопределить различные фазы сборки.

Давайте рассмотрим более сложную деривацию:

{ pkgs }:

let
  mle = with pkgs; stdenv.mkDerivation rec {
    pname = "mle";
    version = "1.5.0";

    src = fetchFromGitHub {
      owner = "adsr";
      repo = "mle";
      rev = "v${version}";
      sha256 = "1nhd00lsx9v12zdmps92magz76c2d8zzln3lxvzl4ng73gbvq3n0";
    };

    # Bug fixes found after v1.5.0 release
    patches = [
      (fetchpatch {
        name = "skip_locale_dep_test.patch";
        url = "https://github.com/adsr/mle/commit/e4dc4314b02a324701d9ae9873461d34cce041e5.patch";
        sha256 = "sha256-j3Z/n+2LqB9vEkWzvRVSOrF6yE+hk6f0dvEsTQ74erw=";
      })
      (fetchpatch {
        name = "fix_input_trail.patch";
        url = "https://github.com/adsr/mle/commit/bc05ec0eee4143d824010c6688fce526550ed508.patch";
        sha256 = "sha256-dM63EBDQfHLAqGZk3C5NtNAv23nCTxXVW8XpLkAeEyQ=";
      })
    ];

    # Fix location of Lua 5.4 header and library
    postPatch = ''
      substituteInPlace Makefile --replace "-llua5.4" "-llua";
      substituteInPlace mle.h    --replace "<lua5.4/" "<";
      patchShebangs tests/*
    '';

    # Use select(2) instead of poll(2) (poll is returning POLLINVAL on macOS)
    # Enable compiler optimization
    CFLAGS = "-DTB_OPT_SELECT -O2";

    nativeBuildInputs = [ makeWrapper installShellFiles ];

    buildInputs = [ pcre uthash lua5_4 ];

    doCheck = true;

    installFlags = [ "prefix=${placeholder "out"}" ];

    postInstall = ''
      installManPage mle.1
    '';
  };
in {
  deps = [
    mle
  ];
}
Вход в полноэкранный режим Выход из полноэкранного режима

Эта формула была адаптирована из формулы mle в Nixpgks. Давайте разберем некоторые из новых концепций.

Зависимости

Если ваша программа зависит от других пакетов, которые не являются частью стандартного окружения, вы можете предоставить их с помощью атрибута buildInputs следующим образом:

pkgs.stdenv.mkDerivation {
  name = "foo-1.2.3";
  ...
  buildInputs = with pkgs; [libbar perl ncurses];
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Вы также можете увидеть nativeBuildInputs, который можно рассматривать как зависимость во время сборки, в то время как buildInputs предназначен для зависимостей во время выполнения. Это чрезмерное упрощение, но это хорошее приближение.

Если вы не знаете, куда поместить зависимость, используйте buildInputs. Даже если вы случайно поместите туда зависимость времени сборки, деривация все равно будет собрана. Это не идеальный вариант, но если вы просто пытаетесь внедрить некоторые программы в свою замену, он подойдет.

Есть еще больше способов указать зависимости, но если вы не занимаетесь кросс-компиляцией, они вряд ли будут иметь для вас значение.

Патчи

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

pkgs.stdenv.mkDerivation {
  name = "foo-1.2.3";
  ...
  patches = [
    (fetchpatch {
      url = "https://example.com/patches/001_arches_align.patch";
      sha256 = "0i3qclm2mh98c04rqpx1r4qagd3wpxlkj7lvq0ddpkmr8bm0fh0m";
    })

    (fetchpatch {
      url = "https://example.com/patches/002_no_remove_static_const.patch";
      sha256 = "0zfjqmjsj0y1kfzxbp29v6nxq5qwgazhb9clqc544sm5zn0bdp8n";
    })

    (fetchpatch {
      url = "https://example.com/patches/003_64_bit_clean.patch";
      sha256 = "0mda9fkaqf2s1xl6vlbkbq20362h3is9dpml9kfmacpbifl4dx3n";
    })
    ];
}
Вход в полноэкранный режим Выход из полноэкранного режима

Патчи применяются в том порядке, в котором они перечислены. Они должны быть в формате, принимаемом командой patch, и могут быть сжаты с помощью gzip, bzip2 или xz.

Они могут быть локальными файлами, или вы можете получить их. Для получения патчей лучше использовать fetchpatch, а не fetchurl. Он работает аналогично, но выполняет нормализацию патчей перед вычислением хэша, например, удаляет комментарии и нестабильные части, иногда добавляемые системами контроля версий, которые меняются со временем (и которые в противном случае привели бы к изменению хэша).

Переменные окружения

Любые атрибуты, которые вы установили в stdenv.mkDerivation, также будут доступны в среде сборки в качестве переменных окружения. Помните, что они будут установлены во всех фазах, если вы зададите их таким образом.

Фазы сборки

Стандартный скрипт сборки имеет несколько фаз, которые определяются как функции bash. Вы можете влиять на поведение каждой фазы, устанавливая определенные атрибуты stdenv.mkDerivation, некоторые из которых подробно описаны ниже. Наиболее распространенными фазами являются следующие, в порядке убывания:

    • По умолчанию он поддерживает обычные tar-архивы или архивы, сжатые gzip (*.tar.gz, *.tgz или *.tar.Z), bzip2 (*. tar.bz2, *.tbz2 или *.tbz) или xz (*.tar.xz, *.tar.lzma или *.txz).
    • Он также может автоматически распаковывать zip-файлы. Zip-файлы распаковываются с помощью пакета unzip, который отсутствует в стандартной среде. Добавьте его в nativeBuildInputs.
    • Установка dontUnpack в true пропустит этот этап.
    • Установка dontPatch в true пропускает эту фазу, но если patches не установлено, то она также пропускается.
    • Установите configureScript, чтобы изменить сценарий конфигурации. По умолчанию используется ./configure.
    • Установите configureFlags для передачи дополнительных аргументов сценарию конфигурации.
    • По умолчанию к флагам configure добавляется --prefix=$prefix. Установите dontAddPrefix, чтобы отключить это.
    • Установите prefix, чтобы установить переменную $prefix выше (помните, что атрибуты, определенные здесь, также отображаются как переменные окружения). По умолчанию она установлена в $out, который является выходным каталогом, который Nix создает для вашего пакета в хранилище Nix.
    • Установка dontConfigure в true пропустит эту фазу.
    • Установите makeFile, чтобы изменить имя MakeFile.
    • Установите makeFlags, чтобы передать дополнительные флаги в make.
    • Установите buildFlags для передачи дополнительных флагов в make, но вызываемых только на этапе сборки.
    • Установка dontBuild в true пропустит эту фазу.
    • Установите installFlags для передачи дополнительных флагов в make, которые будут вызываться только во время фазы установки.
    • Помните, что makeFlags также будет влиять на эту фазу.
    • Установка dontInstall в true пропустит эту фазу.

Вы можете переопределить любую из этих фаз, установив атрибут с именем фазы. Он будет выполнен как сценарий bash в стандартном окружении.

Вы также можете настроить сборку, выполняя код до и после каждой фазы. Установите атрибут pre или post и имя фазы (с заглавной буквы), например, preConfigure или postBuild.

Вы можете добавить еще несколько фаз до или после каждой из этих фаз, или даже полностью изменить их порядок. Подробнее о том, как это сделать, читайте в документации по фазам сборки.

Здесь мы рассмотрели основы. Для большего читайте документацию stdenv.mkDerivation. Помните, что это основа для самого большого репозитория программного обеспечения, и как таковой он способен на многое.

Функции и утилиты оболочки

Стандартная среда также имеет несколько функций и утилит оболочки, которые могут быть полезны, если вы вносите коррективы в вышеописанные этапы, например:

  substituteInPlace ./foo.sh 
    --replace /usr/bin/bar $bar/bin/bar 
    --replace /usr/bin/baz $bar/bin/baz
Войти в полноэкранный режим Выход из полноэкранного режима

Специальные конструкторы

Как мы уже говорили, stdenv.mkDerivation — не единственный билдер. Многие фреймворки, языки программирования или системы сборки имеют специальные построители, которые обеспечивают удобства и абстракции для их идиосинкразии. Обязательно посмотрите на сборщики для конкретных языков и фреймворков в руководстве по Nixpkgs.

Это не обязательно исчерпывающий список. Даже если в руководстве нет специального конструктора для вашего случая использования, он все равно может существовать. Лучший способ узнать это — посмотреть исходный код Nixpkgs, который размещен на GitHub.

Ищите термины, инструменты и команды, характерные для вашей экосистемы. Вы можете воспользоваться веб-поиском на GitHub или сделать локальный клон репозитория с помощью grep (подумайте о создании неглубокого клона с помощью флага git’s --depth=1, поскольку это довольно большой репозиторий с большим количеством ветвей и длинной историей).

Крючки для установки пакетов

Хуки — это скрипты, которые запускаются во время сборки, если зависимость использует их. Если зависимость вашей производной использует хук, то этот хук будет запущен во время сборки вашей производной.

Вы не должны использовать хуки напрямую, но имейте в виду, что зависимость от пакетов, использующих хуки, может изменить способ работы вашей сборки. Даже stdenv.mkDerivation включает некоторые хуки, например, для размещения документации в нужном месте, для удаления отладочных символов или для сжатия man-страниц.

Есть хуки для конкретных технологий, например, производная cmake использует хук cmake, который вносит некоторые изменения в stdenv.mkDerivation для проектов Cmake. Таким образом, включение cmake (производной) в nativeBuildInputs вашей производной изменит способ ее работы. В этой ситуации вы можете использовать атрибут cmakeFlags.

Дополнительное чтение

Для получения дополнительной информации обязательно посмотрите на:

  • Nix Pills 6: Our First Derivation, 7: Working Derivation, и 8: Generic Builders для постепенного создания stdenv.mkDerivation с первых принципов.
  • Руководство по Nixpkgs, авторитетный справочник, который содержит дополнительную информацию, например, о расширенных возможностях, которые мы здесь не рассматриваем. Особый интерес может представлять раздел о тривиальных конструкторах для создания таких вещей, как текстовые файлы или сценарии оболочки.
  • Packaging/Binaries на NixOS Wiki. Вам может понадобиться использовать предварительно скомпилированный двоичный файл. Это наиболее часто встречается в проприетарном программном обеспечении.

Оцените статью
devanswers.ru
Добавить комментарий