Python: Добавление продвинутой функциональности

В рецептах разрешается использовать python код для выполнения сложных действий, невыполнимых обычными средствами рецептов. Python может использоваться как в присваивании переменных, так и в реализации задач.

Для использования в операторе присваивания python код должен быть помечен ${@...}:

TAG = ${@bb.data.getVar('PV',d,1).replace('.', '_')}

Приведенный пример получает значение переменной PV из объекта данных bitbake и заменяет все точки на чёрточки. Таким образом, если переменная PV имела значение 0.9.0, то в TAG будет записано 0-9-0.

Чаще всего в рецептах используются следующие python функции:

bb.data.getVar(<var>,d,1)

Получить содержимое указанной переменной из базы bitbake для текущего рецепта.

<variable>.replace(<key>, <replacement>)

Найти все вхождения строки key и заменить их на replacement. Эта функция также может быть использована для удаления части строки, для этого нужно указать '' (две одинарные кавычки) вместо replacement.

Следующий пример удаляет параметр '-frename-registers' из переменной CFLAGS:

CFLAGS := "${@'${CFLAGS}'.replace('-frename-registers', '')}"
		  

os.path.dirname(<filename>)

Возврат имени директории.

Эта функция наиболее часто встречается в рецептах, устанавливающих FILESDIR (подробнее в разделе FILESPATH/FILESDIR). Например, после получения пути к рецепту, FILE, вызывается os.path.dirname для удаления имени файла:

FILESDIR = 
		  "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/make-${PV}"

. Обратите внимание, что в таком приёме больше нет необходимости, так как переменная FILE_DIRNAME автоматически устанавливается в имя директории, содержащей FILE и приведенный выше пример в новых рецептах нужно записывать следующим образом:

FILESDIR = "$FILE_DIRNAME/make-${PV}"

<variable>.split(<key>)[<index>]

Разделение содержимого переменной по указанному ключу. [<index>] используется для выбора найденных соответствий из массива, сгенерированного командой split.

Следующий пример из рецепта genext2fs_1.3+1.4rc1.bb разделяет значение переменной PV по знаку + и в результате получается массив из двух элементов: 1.3 и 1.4rc1. Затем по индексу [1] выбирается значение второго элемента массива и именно оно записывается в TRIMMEDV :

TRIMMEDV = "${@bb.data.getVar('PV', d, 1).split('+')[1]}"
		  

Функции, определенные в bitbake классах, могут быть вызваны наравне со встроенными python функциями. Набор общих функций представлен в базовом классе classes/base.bbclass:

base_conditional

Эта функция используется для записи в переменную одного из двух значений в зависимости от значения другой переменной. Общий вид вызова функции следующий:

		  ${@base_conditional(
				'<variable-name>', 
				'<value>', 
				'<true-result>', 
				'<false-result>', d)}"
		  

где:

variable-name

Имя сравниваемой переменной.

value

Значение для сравнения с переменной.

true-result

Это значение возвращается если значение переменной variable-name совпадает с value.

false-result

Возвращается если значение переменной variable-name совпало с value.

Следующий пример из openssl рецепта показывает добавление к флагам компиляции строки -DL_ENDING или -DB_ENDIAN в зависимости от значения переменной SITEINFO_ENDIANESS , которая устанавливается в 'le' для little endian целей и be для big endian:

do_compile () {
    ...
    # Additional flag based on target endiness (see siteinfo.bbclass)
    CFLAG="${CFLAG} ${@base_conditional('SITEINFO_ENDIANESS', 'le', '-DL_ENDIAN', '-DB_ENDIAN', d)}"
    ...
base_contains

Проверяет наличие элемента в массиве. Общий вид вызова следующий:

		  ${@base_contains(
				'<array-name>', 
				'<value>', 
				'<true-result>', 
				'<false-result>', d)}"
		  

где:

array-name

Имя массива, в котором ведётся поиск.

value

Искомое значение.

true-result

Возвращается если значение value было найдено в array-name.

false-result

Возвращается если значение value не было найдено в array-name.

Следующий пример из task-angstrom-x11 показывает использование base_contains для добавления рецепта в список зависимостей времени выполнения только для машин с сенсорным экраном:

RDEPENDS_angstrom-gpe-task-base := "\
    ...
    ${@base_contains("MACHINE_FEATURES", "touchscreen", "libgtkstylus", "",d)} \
    ...

Чтобы реализовать задачу на python нужно добавить префикс "python ". Чаще всего в этом нет необходимости и стоит избегать таких задач где это возможно. Пример из devshell рецепта показывает, как задача компиляции реализуется с использованием python:

	python do_compile() {
    import os
    import os.path

    workdir = bb.data.getVar('WORKDIR', d, 1)
    shellfile = os.path.join(workdir, bb.data.expand("${TARGET_PREFIX}${DISTRO}-${MACHINE}-devshell", d))

    f = open(shellfile, "w")

    # emit variables and shell functions
        devshell_emit_env(f, d, False, ["die", "oe", "autotools_do_configure"])

    f.close()
	}