19. Nix в пилюлях: Основы stdenv

от автора

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

Настало время исследовать nixpkgs и, конкретно, одну из его основных дериваций — stdenv.

Деривация stdenv не считается какой-то особенной, но очень важна для репозитория nixpkgs. Она служит базой для создания пакетов, поскольку подгружает зависимости для инструментария GCC, GNU make, утилит ядра, утилит patch и diff и т. д. Благодаря ей, нам доступны основные утилиты, необходимые для сборки огромной кучи программ, присутствующих в nixpkgs в данный момент.

Что такое stdenv?

Прежде всего, stdenv — это очень простая деривация:

$ nix-build '<nixpkgs>' -A stdenv /nix/store/k4jklkcag4zq4xkqhkpy156mgfm34ipn-stdenv $ ls -R result/ result/: nix-support/  setup  result/nix-support: propagated-user-env-packages 

В ней всего лишь два файла: /setup и /nix-support/propagated-user-env-packages. Последний можно не принимать во внимание, поскольку, по факту, он пустой. Действительно важный файл — это /setup.

Как такая простая деривация может включать в себя весь набор инструментов и базовых утилит для сборки пакетов? Взглянем на зависимости времени выполнения:

$ nix-store -q --references result /nix/store/3a45nb37s0ndljp68228snsqr3qsyp96-bzip2-1.0.6 /nix/store/a457ywa1haa0sgr9g7a1pgldrg3s798d-coreutils-8.24 /nix/store/zmd4jk4db5lgxb8l93mhkvr3x92g2sx2-bash-4.3-p39 /nix/store/47sfpm2qclpqvrzijizimk4md1739b1b-gcc-wrapper-4.9.3 ... 

Как такое может быть? Пакет должен как-то ссылаться на другие пакеты. Оказывается, зависимости прописаны в файле /setup:

$ head result/setup export SHELL=/nix/store/zmd4jk4db5lgxb8l93mhkvr3x92g2sx2-bash-4.3-p39/bin/bash initialPath="/nix/store/a457ywa1haa0sgr9g7a1pgldrg3s798d-coreutils-8.24 ..." defaultNativeBuildInputs="/nix/store/sgwq15xg00xnm435gjicspm048rqg9y6-patchelf-0.8 ..." 

Файл /setup

Помните наш обобщённый скрипт builder.sh из восьмой пилюли? Он инициализировал переменную PATH, распаковывал исходники и запускал для нас команды autotools.

Файл /setup из stdenv — точно такой же. Он инициализирует несколько переменных окружения, таких как PATH и создаёт несколько вспомогательных функций bash для сборки пакетов. Давайте его прочитаем.

Чтобы было удобно запускать команды, в файле /setup для наборов инструментов и утилит прописаны переменные окружения. Подобный трюк мы проворачивали с baseInputs и buildInputs, когда создавали универсальный скрипт сборки.

Сборка в stdenv разбита на фазы: unpackPhase, configurePhase, buildPhase, checkPhase, installPhase, fixupPhase. Список фаз по умолчанию находится в функции genericBuild.

Функция запускает эти фазы одну за другой. Все фазы — это, на самом деле, функции bash, так что вы легко можете их прочитать.

У каждой фазы есть хуки для запуска команд до или после фазы. Фазы можно переопределить, переставить местами, да и в принципе сделать с ними что угодно, так как это просто код на bash.

Как использовать этот файл? Как наш старый скрипт сборки. Чтобы проверить его, сделаем фиктивную пустую деривацию, запустим setup из stdenv с помощью source, распакуем исходники hello и скомпилируем их:

$ nix-shell -E 'derivation { name = "fake"; builder = "fake"; system = "x86_64-linux"; }' nix-shell$ unset PATH nix-shell$ source /nix/store/k4jklkcag4zq4xkqhkpy156mgfm34ipn-stdenv/setup nix-shell$ tar -xf hello-2.10.tar.gz nix-shell$ cd hello-2.10 nix-shell$ configurePhase ... nix-shell$ buildPhase ... 

Я очистил PATH, чтобы ещё раз показать, что в stdenv есть всё, что нужно для сборки пакетов autotools, не имеющих других зависимостей.

Мы запустили функции configurePhase и buildPhase, и они отработали. Эти функции bash имеют «говорящие» имена, их код вы можете найти в файле setup.

Из чего состоит setup

До сих пор мы работали с обычными скриптами bash. А что насчёт Nix? В репозитории nixpkgs есть полезная функция, похожая на ту, которую мы написали в нашем старом скрипте. Она вызывает функцию деривации, подтягивая stdenv и запуская genericBuild.
Это stdenv.mkDerivation.

Обратите внимание, что stdenv — это не только деривация, но и набор атрибутов, содержащий, в том числе, mkDerivation. Это сделано для удобства.

Давайте напишем выражение hello.nix, используя stdenv:

with import <nixpkgs> { }; stdenv.mkDerivation {   name = "hello";   src = ./hello-2.10.tar.gz; } 

Не пугайтесь выражения with. Оно подгружает репозиторий nixpkgs в область видимости, чтобы мы могли напрямую использовать stdenv. Это очень похоже на выражение hello из пилюли 8.

Программа отлично собирается и работает:

$ nix-build hello.nix ... /nix/store/6y0mzdarm5qxfafvn2zm9nr01d1j0a72-hello $ result/bin/hello Hello, world! 

Сборщик stdenv.mkDerivation

Взглянем на скрипт сборки, используемый mkDerivation. Вы можете найти код здесь в nixpkgs:

{   # ...   builder = attrs.realBuilder or shell;   args =     attrs.args or [       "-e"       (attrs.builder or ./default-builder.sh)     ];   stdenv = result;   # ... } 

Сравним его с нашей старой обёрткой над деривациями из предыдущих пилюль. Здесь пакет собирается с помощью bash (переменная shell), аргументом которого является default-builder.sh. В набор атрибутов, уже присутствующему в деривации stdenv, мы добавляем переменную окружения $stdenv.

Вы можете открыть default-builder.sh и посмотреть, что он делает:

source $stdenv/setup genericBuild 

То же самое мы делали в десятой пилюлей чтобы из nix-shell было удобно работать с деривациями. При входе в оболочку, файл setup настраивает окружение, но не запускает сборку. А при запуске nix-build он действительно запускает процесс сборки.

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

$ nix derivation show $(nix-instantiate hello.nix) warning: you did not specify '--add-root'; the result might be removed by the garbage collector {   "/nix/store/abwj50lycl0m515yblnrvwyydlhhqvj2-hello.drv": {     "outputs": {       "out": {         "path": "/nix/store/6y0mzdarm5qxfafvn2zm9nr01d1j0a72-hello"       }     },     "inputSrcs": [       "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh",       "/nix/store/svc70mmzrlgq42m9acs0prsmci7ksh6h-hello-2.10.tar.gz"     ],     "inputDrvs": {       "/nix/store/hcgwbx42mcxr7ksnv0i1fg7kw6jvxshb-bash-4.4-p19.drv": [         "out"       ],       "/nix/store/sfxh3ybqh97cgl4s59nrpi78kgcc8f3d-stdenv-linux.drv": [         "out"       ]     },     "platform": "x86_64-linux",     "builder": "/nix/store/q1g0rl8zfmz7r371fp5p42p4acmv297d-bash-4.4-p19/bin/bash",     "args": [       "-e",       "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"     ],     "env": {       "buildInputs": "",       "builder": "/nix/store/q1g0rl8zfmz7r371fp5p42p4acmv297d-bash-4.4-p19/bin/bash",       "configureFlags": "",       "depsBuildBuild": "",       "depsBuildBuildPropagated": "",       "depsBuildTarget": "",       "depsBuildTargetPropagated": "",       "depsHostBuild": "",       "depsHostBuildPropagated": "",       "depsTargetTarget": "",       "depsTargetTargetPropagated": "",       "name": "hello",       "nativeBuildInputs": "",       "out": "/nix/store/6y0mzdarm5qxfafvn2zm9nr01d1j0a72-hello",       "propagatedBuildInputs": "",       "propagatedNativeBuildInputs": "",       "src": "/nix/store/svc70mmzrlgq42m9acs0prsmci7ksh6h-hello-2.10.tar.gz",       "stdenv": "/nix/store/6kz2vbh98s2r1pfshidkzhiy2s2qdw0a-stdenv-linux",       "system": "x86_64-linux"     }   } } 

Он настолько короткий, что я решил вставить его полностью. Программа сборки — это bash с аргументами -d default-builder.sh. В файле вы видите переменные окружения src и stdenv.

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

Заключение

Деривация stdenv — это ядро репозитория nixpkgs. Все пакеты используют обёртку stdenv.mkDerivation вместо прямого вызова дериваций. Она выполняет разные операции и создаёт удобное окружение для сборки.

Процесс в целом прост:

  • nix-build

  • bash -e default-builder.sh

  • source $stdenv/setup

  • genericBuild

И это всё. То, что вам надо знать о фазах stdenv есть в файле setup.

Серьёзно, найдите время его прочитать. И не забывайте, что в руководстве по nixpkgs тоже есть важные документы.

В следующей пилюле

Мы поговорим о том, как добавить зависимости в наши пакеты с помощью buildInputs и propagatedBuildInputs, и о том, как влиять на зависимые сборки с помощью хуков настройки и окружения. Эти концепции очень важны для понимания, как nixpkgs собирает пакеты.


ссылка на оригинал статьи https://habr.com/ru/articles/875910/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *