Next: Search Paths, Previous: Фазы сборки, Up: Программный интерфейс [Contents][Index]
Как только вы начнете писать нетривиальные определения пакетов
(see Описание пакетов) или другие действия сборки
(see G-Expressions), вы, скорее всего, начнете искать помощников для
действий, подобных оболочке—создание каталогов, рекурсивное копирование и
удаление файлов, управление этапами сборки и т.д. Модуль (guix build
utils)
предоставляет такие служебные процедуры.
Большинство систем сборки загружают (guix build utils)
(see Системы сборки). Таким образом, при написании настраиваемых фаз сборки для
определений пакетов вы обычно можете предположить, что эти процедуры входят
в область действия.
При написании G-выражений вы можете импортировать (guix build utils)
на “стороне сборки”, используя with-import-modules
, а затем
поместить его в область видимости с помощью формы use-modules
(see Using Guile Modules in GNU Guile Reference Manual):
(with-imported-modules '((guix build utils)) ;import it (computed-file "empty-tree" #~(begin ;; Put it in scope. (use-modules (guix build utils)) ;; Happily use its 'mkdir-p' procedure. (mkdir-p (string-append #$output "/a/b/c")))))
Оставшаяся часть этого раздела является справочником по большинству
служебных процедур, предоставляемых (guix build utils)
.
В этом разделе описаны процедуры, относящиеся к именам файлов в store.
Проверить целостность склада.
Возвращает true, если объект obj — это пакет ранней версии.
Удалиnm /gnu/store и хэш из file, имени файла в store.
Результатом обычно является строка "package-version"
.
Учитывая name, имя пакета, такое как "foo-0.9.1b"
, возвращает
два значения: "foo"
и "0.9.1b"
. Если часть версии недоступна,
возвращаются name и #f
. Считается, что первый дефис, за
которым следует цифра, обозначает часть версии.
Процедуры, приведённые ниже, обеспечивают работу и управление ранними версиями пакетов.
Вернуть #t
, если dir существует и является каталогом.
Вернуть #t
, если file существует и исполняемый файл.
Вернуть #t
, если file является символической ссылкой (также
известной как “символическая ссылка”).
Вернуть #t
, если file является, соответственно, файлом ELF,
архивом ar
(например, статической библиотекой .a) или файлом
gzip.
Если file является файлом gzip, сбросить его timestamp (как в случае
gzip --no-name
) и вернуть истину. В противном случае вернуть
#f
. Когда keep-mtime? истинна, сохранить время модификации
file.
Следующие процедуры и макросы помогают создавать, изменять и удалять файлы.
Они обеспечивают функциональность, сопоставимую с такими обычными утилитами
оболочки, как mkdir -p
, cp -r
, rm -r
и
sed
. Они дополняют обширный, но низкоуровневый интерфейс файловой
системы Guile (see POSIX in GNU Guile Reference Manual).
Запустить body с directory в качестве текущего каталога процесса.
По сути, этот макрос изменяет текущий каталог на directory перед
вычислением body, используя chdir
(see Processes in GNU Guile Reference Manual). Она возвращается в исходный каталог, когда
остается динамический extent body, будь то через возврат
нормальной процедуры или через нелокальный выход, такой как исключение.
Создать каталог dir и всех его предков.
под тем же именем.
Сделать file доступным для записи его владельцу.
copy-file] [#:keep-mtime? #f] [#:keep-permissions? #t] Copy source directory to destination. Follow symlinks if follow-symlinks? is true; otherwise, just preserve them. Call copy-file to copy regular files. When keep-mtime? is true, keep the modification time of the files in source on those of destination. When keep-permissions? is true, preserve file permissions. Write verbose output to the log port.
rm -rf
, безиспользования символических ссылок. Также не следовать точкам монтирования, если follow-mounts? не истинна. Сообщать об ошибках, но игнорировать их.
((regexp match-var…) body…) … Заменить regexp в file строкой, возвращаемой body. body вычисляется с каждой привязкой match-var к соответствующему подвыражению позиционного регулярного выражения. Например:
(substitute* file (("hello") "good morning\n") (("foo([a-z]+)bar(.*)$" all letters end) (string-append "baz" letters end)))
Здесь, когда строка file содержит hello
, она заменяется на
good morning
. Каждый раз, когда строка file соответствует
второму регулярному выражению, all
привязывается к полному
совпадению, letters
привязано к первому подвыражению, а end
привязано к последнему.
Когда одно из match-var - _
, никакая переменная не связана с
соответствующей подстрокой соответствия.
В качестве альтернативы file может быть списком имен файлов, и в этом случае все они могут быть заменены.
В качестве альтернативы file может быть списком имен файлов, и в этом случае все они могут быть заменены.
В этом разделе описаны процедуры поиска и фильтрации файлов.
Вернуть предикат, который возвращает истину при передаче имени файла, базовое имя которого совпадает с regexp.
лексикографически отсортированный список файлов в dir, для которых
pred возвращает истину. pred передается два аргумента:
абсолютное имя файла и его буфер статистики; предикат по умолчанию всегда
возвращает истину. pred также может быть регулярным выражением, в
этом случае оно эквивалентно (file-name-predicate pred)
.
stat используется для получения информации о файле; использование
lstat
означает, что символические ссылки не соблюдаются. Если
directories? истина, то каталоги также будут включены. Если
fail-on-error? истина, генерировать исключение при ошибке.
Вот несколько примеров, в которых мы предполагаем, что текущий каталог является корнем дерева исходников Guix:
;; List all the regular files in the current directory. (find-files ".") ⇒ ("./.dir-locals.el" "./.gitignore" …) ;; List all the .scm files under gnu/services. (find-files "gnu/services" "\\.scm$") ⇒ ("gnu/services/admin.scm" "gnu/services/audio.scm" …) ;; List ar files in the current directory. (find-files "." (lambda (file stat) (ar-file? file))) ⇒ ("./libformat.a" "./libstore.a" …)
Вернуть полное имя файла для program, как в $PATH
, или
#f
, если program не найдена.
Return the complete file name for name as found in inputs;
search-input-file
searches for a regular file and
search-input-directory
searches for a directory. If name could
not be found, an exception is raised.
Here, inputs must be an association list like inputs
and
native-inputs
as available to build phases (see Фазы сборки).
Here is a (simplified) example of how search-input-file
is used in a
build phase of the wireguard-tools
package:
(add-after 'install 'wrap-wg-quick (lambda* (#:key inputs outputs #:allow-other-keys) (let ((coreutils (string-append (assoc-ref inputs "coreutils") "/bin"))) (wrap-program (search-input-file outputs "bin/wg-quick") #:sh (search-input-file inputs "bin/bash") `("PATH" ":" prefix ,(list coreutils))))))
You’ll find handy procedures to spawn processes in this module, essentially
convenient wrappers around Guile’s system*
(see system*
in GNU Guile Reference Manual).
Invoke program with the given args. Raise an
&invoke-error
exception if the exit code is non-zero; otherwise
return #t
.
The advantage compared to system*
is that you do not need to check
the return value. This reduces boilerplate in shell-script-like snippets
for instance in package build phases.
Return true if c is an &invoke-error
condition.
Access specific fields of c, an &invoke-error
condition.
Report to port (by default the current error port) about c, an
&invoke-error
condition, in a human-friendly way.
Typical usage would look like this:
(use-modules (srfi srfi-34) ;for 'guard' (guix build utils)) (guard (c ((invoke-error? c) (report-invoke-error c))) (invoke "date" "--imaginary-option")) -| command "date" "--imaginary-option" failed with status 1
Invoke program with args and capture program’s standard
output and standard error. If program succeeds, print nothing and
return the unspecified value; otherwise, raise a &message
error
condition that includes the status code and the output of program.
Here’s an example:
(use-modules (srfi srfi-34) ;for 'guard' (srfi srfi-35) ;for 'message-condition?' (guix build utils)) (guard (c ((message-condition? c) (display (condition-message c)))) (invoke/quiet "date") ;all is fine (invoke/quiet "date" "--imaginary-option")) -| 'date --imaginary-option' exited with status 1; output follows: date: unrecognized option '--imaginary-option' Try 'date --help' for more information.
(guix build utils)
также содержит инструменты для управления фазами
сборки, которые используются системами сборки (see Системы сборки). Фазы
сборки представлены в виде ассоциативных списков или “alists”
(see Association Lists in GNU Guile Reference Manual), где каждый
ключ представляет собой символ, обозначающий фазу, а связанное значение
представляет собой процедуру (see Фазы сборки).
Ядро Guile и модуль (srfi srfi-1)
предоставляют инструменты для
управления списками. Модуль (guix build utils)
дополняет их
инструментами, написанными с учетом фаз сборки.
Изменить phases последовательно в соответствии с каждым clause, которое может иметь одну из следующих форм:
(delete old-phase-name) (replace old-phase-name new-phase) (add-before old-phase-name new-phase-name new-phase) (add-after old-phase-name new-phase-name new-phase)
Где каждая phase-name выше - это выражение, преобразующееся в символ, а new-phase - выражение, преобразующееся в процедуру.
Пример ниже взят из определения пакета grep
. Он добавляет фазу для
запуска после фазы install
, которая называется
fix-egrep-and-fgrep
. Эта фаза представляет собой процедуру
(lambda*
обозначает анонимную процедуру), которая принимает аргумент
ключевого слова #:output
и игнорирует дополнительные аргументы
ключевого слова (see Optional Arguments in GNU Guile Reference
Manual, for more on lambda*
and optional and keyword arguments.) В
фазе используется substitute*
для изменения установленных сценариев
egrep и fgrep, чтобы они ссылались на grep
по
абсолютному имени файла:
(modify-phases %standard-phases (add-after 'install 'fix-egrep-and-fgrep ;; Patch 'egrep' and 'fgrep' to execute 'grep' via its ;; absolute file name instead of searching for it in $PATH. (lambda* (#:key outputs #:allow-other-keys) (let* ((out (assoc-ref outputs "out")) (bin (string-append out "/bin"))) (substitute* (list (string-append bin "/egrep") (string-append bin "/fgrep")) (("^exec grep") (string-append "exec " bin "/grep")))))))
В приведенном ниже примере фазы изменяются двумя способами: стандартная фаза
configure
удаляется, предположительно потому, что в пакете нет
сценария configure или чего-то подобного, и фаза install
по
умолчанию заменяется файлом, который вручную копирует устанавливаемые
исполняемые файлы:
(modify-phases %standard-phases (delete 'configure) ;no 'configure' script (replace 'install (lambda* (#:key outputs #:allow-other-keys) ;; The package's Makefile doesn't provide an "install" ;; rule so do it by ourselves. (let ((bin (string-append (assoc-ref outputs "out") "/bin"))) (install-file "footswitch" bin) (install-file "scythe" bin)))))
It is not unusual for a command to require certain environment variables to be set for proper functioning, typically search paths (see Search Paths). Failing to do that, the command might fail to find files or other commands it relies on, or it might pick the “wrong” ones—depending on the environment in which it runs. Examples include:
PATH
;
GUILE_LOAD_PATH
and GUILE_LOAD_COMPILED_PATH
;
QT_PLUGIN_PATH
.
For a package writer, the goal is to make sure commands always work the same
rather than depend on some external settings. One way to achieve that is to
wrap commands in a thin script that sets those environment variables,
thereby ensuring that those run-time dependencies are always found. The
wrapper would be used to set PATH
, GUILE_LOAD_PATH
, or
QT_PLUGIN_PATH
in the examples above.
To ease that task, the (guix build utils)
module provides a couple of
helpers to wrap commands.
variables should look like this:
'(variable delimiter position list-of-directories)
where delimiter is optional. :
will be used if delimiter
is not given.
For example, this call:
(wrap-program "foo" '("PATH" ":" = ("/gnu/.../bar/bin")) '("CERT_PATH" suffix ("/gnu/.../baz/certs" "/qux/certs")))
will copy foo to .foo-real and create the file foo with the following contents:
#!location/of/bin/bash export PATH="/gnu/.../bar/bin" export CERT_PATH="$CERT_PATH${CERT_PATH:+:}/gnu/.../baz/certs:/qux/certs" exec -a $0 location/of/.foo-real "$@"
If program has previously been wrapped by wrap-program
, the
wrapper is extended with definitions for variables. If it is not,
sh will be used as the interpreter.
such that variables are set first. The format of variables is
the same as in the wrap-program
procedure. This procedure differs
from wrap-program
in that it does not create a separate shell
script. Instead, program is modified directly by prepending a Guile
script, which is interpreted as a comment in the script’s language.
Special encoding comments as supported by Python are recreated on the second line.
Note that this procedure can only be used once per file as Guile scripts are not supported.
Next: Search Paths, Previous: Фазы сборки, Up: Программный интерфейс [Contents][Index]