Программирование ARM Zephyr: конфигурация Kconfig Wed, April 24 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Zephyr: конфигурация Kconfig Печать
Добавил(а) microsin   

Ядро и подсистемы Zephyr можно сконфигурировать во время построения (build time), чтобы адаптировать их для специфичных нужд приложения и платформы. Конфигурация обрабатывается через Kconfig, у которого такая же система конфигурации, какая используется Linux kernel. Преимущество такого подхода - поддержка конфигурации без какого-либо изменения исходного кода.

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

Вывод из Kconfig - заголовочный файл autoconf.h с макросами, которые можно проверить во время сборки. Код не используемых функций может быть выкинут из компиляции, чтобы освободить память.

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

Есть две интерактивные конфигурации интерфейса, доступные для обзора доступных опций Kconfig и введения временных изменений опций: menuconfig и guiconfig. Интерфейс menuconfig работает в терминале, а guiconfig в графическом окне.

Примечание: конфигурацию проекта также можно поменять вручную редактированием файла zephyr/.config приложения, этот файл находится в директории build. Однако использование утилит menuconfig и guiconfig часто удобнее, поскольку они корректно обрабатывают зависимости между символами конфигурации. Если Вы попытаетесь разрешить символ с неудовлетворенными зависимостями zephyr/.config, то это назначение будет игнорировано и перезапишется при переконфигурировании.

Чтобы сделать настройки постоянными, вы должны установить их в файле *.conf, как описано ниже во врезке "Установка значений конфигурации Kconfig".

Совет: сохранение минимального файла конфигурации (выбором D в menuconfig) и проверка его состояние может быть удобной, когда делаются постоянные изменения. Файл минимальной конфигурации перечисляет только те символы, значение которых отличается от их значения по умолчанию.

Для запуска одного из интерфейсов конфигурации выполните следующее:

1. Сделайте сборку приложения, как обычно, используя west или cmake. При использовании west:

west build -b < board>

При использовании CMake и ninja:

mkdir build && cd build
cmake -GNinja -DBOARD=< board> ..
ninja

2. Для запуска menuconfig используйте одну из следующих команд:

west build -t menuconfig
ninja menuconfig

Для запуска графического интерфейса guiconfig используйте одну из следующих команд:

west build -t guiconfig
ninja guiconfig

Примечание: если Вы столкнулись с ошибкой импорта для tkinter, когда попытались запустить guiconfig, то не хватает необходимых пакетов, см. документацию по установке зависимостей хоста Linux [2]. Необходимый пакет обычно называется наподобие python3-tk/python3-tkinter. Пакет tkinter не включен по умолчанию для многих инсталляций Python несмотря на то, что является частью стандартной библиотеки.

Два типа интерфейса показаны ниже на скриншотах:

menuconfig

guiconfig

Утилита guiconfig всегда показывает текст подсказки и другую информацию, связанную с текущим выбранным элементом, в нижней части окна. В интерфейсе menuconfig нажмите ? для просмотра той же информации.

Примечание: если вы предпочитаете работать в guiconfig, то хорошей идеей будет проверить любые изменения в файлах Kconfig, которые вы сделали, в режиме одиночного меню (single-menu mode), который переключается галочкой сверху. В отличие от режима full-tree режим single-menu будет различать символы, определенные в menuconfig, показывая все так, как это выглядит в интерфейсе menuconfig.

3. Меняйте значения коонфигурации menuconfig следующим образом:

● Перемещайтесь по пунктам меню клавишами со стрелками. Также поддерживаются общие привязки клавиш Vim.

● Используйте Space и Enter для входа в меню и переключения значений настроек. Меню обозначаются ---> справа. Нажмите ESC для возврата в родительское меню.

Двоичные опции конфигурации показаны в квадратных скобках [ ], в то время как числовые и строковые символы конфигурации показываются в круглых скобках ( ). Значения символов, которые нельзя поменять, показываются как - - или -*-. Также вы можете нажать Y или N для установки двоичного символа конфигурации в соответствующее значение.

● Нажмите ? для отображения информации по текущему выбранному символу, включая его текст подсказки. Нажмите ESC или Q для возврата в меню из режима отображения информации.

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

4. Если нажать Q в menuconfig, то появится диалог, предлагающее сохранить изменения конфигурации при выходе (если изменения имели место):

menuconfig quit

Нажатие Y в этом диалоге сохранит опции конфигурации в файл с именем по умолчанию (zephyr/.config). Вы будете обычно сохранять конфигурацию с именем файла по умолчанию кроме случаев, когда экспериментируете с разными конфигурациями.

Интерфейс guiconfig также запросит сохранение конфигурации при выходе, если она была изменена.

Примечание: файл конфигурации, используемый во время сборки, всегда носит имя zephyr/.config. Если у вас есть другая сохраненная конфигурация, и вы хотите выполнить сборку с ней, то сделайте копию этой конфигурации в файл zephyr/.config. Проверьте перед этим, что сохранили оригинальный файл конфигурации. Также имейте в виду, что имена файлов, начинающиеся на точку, по умолчанию не отображаются в Linux и macOS. Чтобы увидеть их в списках, используйте флаг -a.

Поиск нужного символа в дереве меню и переход к нему могут быть утомительными. Чтобы сразу перескочить к нужному символу, нажмите клавишу / (это также работает и в guiconfig). Это отобразит диалог поиска, где можно найти символы по имени и перейти к ним.

menuconfig jump to

В утилите guiconfig диалог поиска также позволяет менять значения символов напрямую.

guiconfig jump to

Если вы перескочили к символу, который в настоящий момент не отображается (например из-за того, что в конфигурации для него есть неразрешенные зависимости), то будет разрешен режим просмотра опций полностью (show-all mode). В show-all mode будут показаны все символы, включая текущие невидимые. Для выключения режима show-all нажмите A в menuconfig или Ctrl-A в guiconfig.

Примечание: show-all mode выключить нельзя, если в текущем меню нет видимых символов.

Чтобы разобраться, почему невидим символ, к которому вы перешли, проверьте его зависимости, для чего нажмите ? в menuconfig, или просмотрите информацию в нижней части окна guiconfig. Если вы обнаружили, что символ зависит от другого символа, который не разрешен, то перейдите к нему для проверки, можно ли его разрешить.

Примечание: в menuconfig можно нажать Ctrl-F для просмотра подсказки по текущему выбранному элементу в диалоге быстрого поиска без выхода из этого диалога.

Для дополнительной информации по menuconfig и guiconfig см. строки документации Python (docstrings) в верхней части menuconfig.py и guiconfig.py.

Интерфейсы изменения настроек menuconfig и guiconfig могут использоваться для тестирования конфигураций во время разработки приложения. В этой врезке объясняется, как сделать установленные настройки постоянными.

Примечание: перед тем, как делать изменения в файлах Kconfig, полезно ознакомиться с материалом "Kconfig - советы и лучшие практики", представленным во врезке ниже.

[Видимые и невидимые символы Kconfig]

При внесении изменений в Kconfig важно понимать различия между видимыми и невидимыми символами.

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

Пример видимого символа:

config FPU
   bool "Support floating point operations"
   depends on HAS_FPU

Этот символ показан в menuconfig следующим образом, где его можно переключить в противоположное состояние:

[ ] Support floating point operations

● Невидимый символ не имеет текстового приглашения по модификации. Эти символы не показываются в интерактивном интерфейсе конфигурации, и у пользователя нет прямого контроля над их значениями. По этой причине невидимые символы берут свое значение из значений по умолчанию, или из других символов.

Пример невидимого символа:

config CPU_HAS_FPU
   bool
   help
     This symbol is y if the CPU has a hardware floating point unit.

В этом случае CPU_HAS_FPU разрешается через другие символы, которые выбирают CPU_HAS_FPU.

[Установка символов в конфигурационных файлах]

Видимые символы можно конфигурировать установкой их значений в файлах конфигурации. Начальная конфигурация генерируется путем слияния файла *_defconfig для платы с настройками приложения, обычно в файле prj.conf (подробнее см. далее "Начальная конфигурация").

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

CONFIG_< имя символа>=< значение>

Здесь не должно быть пробелов вокруг знака равенства.

Символы bool (двоичные символы) могут быть разрешены или запрещены установкой их соответственно в значения y или n. Символ FPU из примера выше должен быть разрешен так:

CONFIG_FPU=y

Двоичный символ также может быть установлен в n вместе с комментарием, примерно так:

# CONFIG_SOME_OTHER_BOOL is not set

Этот формат вы увидите в слитой конфигурации zephyr/.config.

Такой стиль запрета принят по историческим соображениям: файлы конфигурации Kconfig могут быть обработаны как файлы makefile (хотя Zephyr это не использует). Использование символов со значениями n как соответствие неустановленным переменным упрощает проверку в Make.

Другие символы назначаются примерно так:

CONFIG_SOME_STRING="cool value"
CONFIG_SOME_INT=123

Комментарии используют символ #:

# This is a comment

Присваивания в файлах конфигурации имеют силу только если удовлетворены их зависимости для символа. Иначе будет выведено предупреждение. Чтобы выяснить, какие у символа зависимости, используйте один из интерактивных интерфейсов конфигурации (можно напрямую перейти к нужному символу нажатием /).

[Начальная конфигурация]

Начальная конфигурация для приложения появляется из слияния настроек конфигурации из трех источниковThe initial configuration for an application comes from merging configuration settings from three sources:

1. Конфигурации BOARD, учитывающего специфику платы разработчика. Она сохраняется в файл boards/< архитектура>/< плата>/< плата>_defconfig.
2. Любые элементы кэша CMake с префиксом CONFIG_.
3. Конфигурация приложения.

Конфигурация приложения может составляться из источников, перечисленных ниже. По умолчанию используется файл prj.conf.

1. Если установлена переменная CONF_FILE, то файл (файлы) конфигурации, указанные в ней, сливаются и используются как конфигурация приложения. CONF_FILE может быть установлена следующими способами:

   - В CMakeLists.txt, перед вызовом find_package(Zephyr).
   - Передачей опции -DCONF_FILE=< файл (файлы) конфигурации>, либо напрямую в командной строке, либо через west.
   - Из переменной кэша CMake.

2. Иначе если установлена CONF_FILE, и присутствует один файл конфигурации в форме prj_< build>.conf, то если существует файл boards/< BOARD>_< build>.conf в той же папке, что и файл prj_< build>.conf, то используется результат слияния prj_< build>.conf и boards/< BOARD>_< build>.conf.

3. Иначе используется prj_< BOARD>.conf, если он присутствует в директории конфигурации приложения.

4. Иначе, если существует boards/< BOARD>.conf в директории конфигурации приложения, то используется результат его слияния с prj.conf.

5. Иначе, если используются ревизии платы, и существует boards/< BOARD>_< revision>.conf в директории конфигурации приложения, то используется результат слияния их с prj.conf и boards/< BOARD>.conf.

6. Иначе используется prj.conf, если он присутствует в директории конфигурации приложения.

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

См. раздел "Конфигурация приложения -> Директория конфигурации" в статье [3], где описывается, как определяется директория конфигурации приложения.

Если символ назначен и в < BOARD>_defconfig, и в конфигурации приложения, то преимущество получает значение в конфигурации приложения.

Слитая конфигурация сохраняется в zephyr/.config в папке build.

Пока существует zephyr/.config, и эта конфигурация свежая (более новая, чем любые из файлов BOARD и файлов конфигурации приложения), она будет использоваться предпочтительно для генерации новой слитой конфигурации. Файл zephyr/.config это также конфигурация, которая модифицируются в интерактивных интерфейсах изменения конфигурации.

[Конфигурирование невидимых символов Kconfig]

Когда производятся изменения конфигурации по умолчанию для платы, вам может понадобиться сконфигурировать невидимые символы. Это делается в файле boards/< архитектура>/< плата>/Kconfig.defconfig, который является обычным файлом Kconfig.

Примечание: назначения в файлах .config не влияют на невидимые символы, так что эта схема не просто организационная проблема.

Назначение значений в Kconfig.defconfig полагается на определение символа Kconfig в нескольких местах. Например, мы хотим ниже установить FOO_WIDTH в 32:

config FOO_WIDTH
   int

Чтобы это сделать, мы расширяем определение FOO_WIDTH в Kconfig.defconfig следующим образом:

if BOARD_MY_BOARD
 
config FOO_WIDTH
    default 32
 
endif

Примечание: поскольку тип символа (int) уже указан в первом месте определения, но здесь указание типа повторять не нужно. Хорошая идея - задавать тип задается только в "базовом" определении символа по причина, которые объясняются далее в секции "Общие сокращения Kconfig" врезки "Kconfig - советы и лучшие практики".

Значения по умолчанию (default) в файлах Kconfig.defconfig имеют приоритет над назначениями, указанными в "базовом" определении символа. Внутренне это реализовано через первоначальное подключение файлов Kconfig.defconfig (они берутся первыми). Kconfig использует первое значение default с удовлетворенным условием, где пустое условие соответствует "if y" (всегда удовлетворено).

Обратите внимание, что условия из обрамляющего верхнего if распространяются на свойства символа, так что default из примера выше эквивалентно default 32 if BOARD_MY_BOARD.

Предупреждение: когда символ определен в нескольких местах, зависимости объединяются друг с другом по ИЛИ, вместо того чтобы объединяться по И. Нельзя сделать зависимости символа более ограничительными путем определения символа в нескольких местах.

Например, прямые зависимости символа в примере ниже становятся DEP1 || DEP2:

config FOO
  ...
  depends on DEP1
 
config FOO
  ...
  depends on DEP2

Когда делаются изменения в файлах Kconfig.defconfig, после этого всегда проверяйте прямые зависимости символа в одном из интерактивных интерфейсов конфигурации. Часто необходимо повторять зависимости из базового определения символа, чтобы избежать ослабления требований к зависимостям символа.

[Мотивация для файлов Kconfig.defconfig]

Одна из причин использования такой схемы конфигурации заключается в том, чтобы избежать создания фиксированных зависящих от платы, конфигурируемых в интерактивных интерфейсах. Если вся конфигурация платы сделана через < BOARD>_defconfig, то все символы должны быть видны, поскольку значения в < BOARD>_defconfig на влияют на невидимые символы.

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

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

[Конфигурирование выбора]

Существует 2 способа конфигурирования выбора Kconfig (choice):

1. Путем установки одного из choice-символов в y.

Установка в файле конфигурации одного из choice символа в y автоматически даст всем другим choice символам значение n. Если в y установлено несколько choice-символов, то учитываться будет только последний, установленный в y (остальные получат значение n). Это позволяет переназначить choice-выбор из файла defconfig платы значением из файла prj.conf приложения.

2. Путем изменения умолчания (default) для choice в Kconfig.defconfig.

Как с символами, изменение default для choice осуществляется определением choice в нескольких местах. Чтобы это работало, у choice должно быть имя.

В качестве примера рассмотрим случай, когда у choice есть следующее базовое определение (здесь FOO это имя для choice):

choice FOO
   bool "Foo choice"
   default B
 
config A
   bool "A"
 
config B
   bool "B"
 
endchoice

Чтобы поменять символ по умолчанию FOO на A, нужно в Kconfig.defconfig добавить следующее определение:

choice FOO
   default A
 
endchoice

Метод Kconfig.defconfig должен использоваться, когда зависимости choice могут быть не удовлетворены. В этом случае выбор умолчания устанавливается всякий раз, когда пользователь делает choice видимым.

Более подробную информацию о вычислении значений символов можно узнать из начальной шапки файла kconfiglib.py [4].

[Что следует превратить в опции Kconfig]

Когда принимаете решение, что походит ли что-нибудь для опций Kconfig, полезно отличать символы, у которых есть приглашение для модификации (prompt, или текстовая подсказка), и символы, у которых этого нет.

Если у символа есть prompt (например bool "Enable foo"), то пользователь может поменять значение символа в интерфейсе menuconfig или guiconfig (см. выше врезку "Интерактивные интерфейсы Kconfig"), либо вручную, редактированием файлов конфигурации. Соответственно символ без prompt-а пользователь не может поменять напрямую, ни в интерактивном интерфейсе, ни даже редактированием файлов конфигурации.

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

Символы без prompt-ов называются скрытыми, или невидимыми символами, потому что они не видны в menuconfig и guiconfig. Символы, у которых есть prompt, также могут быть невидимыми, если зависимости для них не удовлетворены.

Символы без prompt-ов нельзя конфигурировать пользователем напрямую (они получают свое значение из других символов), так что для них применяется меньше ограничений. Если некоторые унаследованные настройки проще вычислить в Kconfig, чем например во время сборки, то делайте это в Kconfig, однако разделяйте между собой символы с prompt-ами и без них.

См. далее секцию "Опциональные prompt" для получения информации о том, как работать с настройками, которые фиксированы на одних машинах и конфигурируются на других.

[Что не следует превращать в опции Kconfig]

В Zephyr конфигурация Kconfig выполняется после выбора целевой платы (target board). В целом не имеет смысла использовать Kconfig для значения, которое соответствует фиксированной, специфической для определенной машины настройке. Обычно вместо этого такие параметры настройки должны быть обработаны через devicetree.

В частности, избегайте добавлять новые опции Kconfig следующих типов:

Опции, которые задают устройство в системе по имени. Например, если вы пишете драйвер устройства I2C, то избегайте создания опции с именем MY_DEVICE_I2C_BUS_NAME, чтобы указать узел шины, котором управляет устройство. Для альтернативы см. "Device drivers that depend on other devices" документации [5].

Подобным образом, если ваше приложение зависит от аппаратной специфики устройства PWM для управления RGB LED, то избегайте создания опции наподобие MY_PWM_DEVICE_NAME. Для альтернативы см. "Applications that depend on board-specific devices" документации [5].

Опции, которые задают фиксированные аппаратные конфигурации. Например, избегайте опций Kconfig, указывающих ножку GPIO.

Альтернатива, применимая к драйверам устройства - определить спецификатор GPIO с типом массива phandle во время привязки (device binding), и используйте GPIO devicetree API из кода на языке C (см. "Hardware specific APIs" документации [6]). Подобный совет применим для других случаев, где devicetree.h предоставляет Hardware specific API для ссылки на другие узлы в системе. Для примеров поищите исходный код для драйверов, использующий эти вызовы API.

Могут подойти специфичные для приложения devicetree binding для идентификации свойств, особенных для определенной платы. Для примера см. tests/drivers/gpio/gpio_basic_api.

Для приложений в качестве альтернативы, основанной на devicetree, см. пример Blinky.

[Операторы select]

Оператор select используется для разрешения одного символа, т. е. установки его в y всякий раз, когда другой символ установлен в y. Например, следующий код заставляет CONSOLE принять y всякий раз, когда USB_CONSOLE установлено в y:

config CONSOLE
   bool "Console support"
 
...
 
config USB_CONSOLE
   bool "USB console support"
   select CONSOLE

Далее будут рассмотрены типичные случаи правильного и ошибочного использования select.

Неправильный select. Оператор select может поначалу казаться полезной функцией, но при чрезмерном использовании может вызывать проблемы.

Например, к символу CONSOLE добавляется новая зависимость разработчиком, который не знает о символе USB_CONSOLE (или просто забыл о нем):

config CONSOLE
   bool "Console support"
   depends on STRING_ROUTINES

Теперь разрешение USB_CONSOLE принуждает установку CONSOLE в y, даже если STRING_ROUTINES установлено в n. Для исправления этой проблемы должна быть также добавлена зависимость STRING_ROUTINES к USB_CONSOLE:

config USB_CONSOLE
   bool "USB console support"
   select CONSOLE
   depends on STRING_ROUTINES
 
...
 
config STRING_ROUTINES
   bool "Include string routines"

Часто встречаются более коварные случае с зависимостями, унаследованными из операторов if и menu.

Альтернативной попыткой исправить проблему может быть превращение зависимостей в другой select:

config CONSOLE
   bool "Console support"
   select STRING_ROUTINES
 
...
 
config USB_CONSOLE
   bool "USB console support"
   select CONSOLE

На практике это часто наоборот усиливает проблему, потому что любые зависимости добавленные к STRING_ROUTINES, нужно теперь копировать как в CONSOLE, так и в USB_CONSOLE.

Как правило, всякий раз при обновлении зависимости символа обновляются зависимости всех символов, которые (явно или косвенно) выбирают его. На практике это часто упускается из виду, даже для самого простого случая, показанного выше.

В частности, следует избегать цепочек символов, где каждый символ выбирает другой, кроме простых вспомогательных символов, как это рассматривается далее в секции "Использование select для helper-символов".

Либеральное использование select также приводит к тому, что файлы Kconfig становятся трудно читаемыми, как из-за дополнительных зависимостей, так и из-за нелокального характера select, который скрывает способы, которыми символ может быть разрешен.

Альтернативы для select. Для примера из предыдущей секции лучшим решением будет превратить select в depends on:

config CONSOLE
   bool "Console support"
 
...
 
config USB_CONSOLE
   bool "USB console support"
   depends on CONSOLE

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

Возражение для использования здесь depends on состоит в том, что файлы конфигурации, которые разрешают USB_CONSOLE, теперь также должны разрешить CONSOLE:

CONFIG_CONSOLE=y
CONFIG_USB_CONSOLE=y

Это сводится к компромиссу, однако если разрешение CONSOLE это норма, то адаптация должна сделать умолчание CONSOLE в y:

config CONSOLE
   bool "Console support"
   default y

Это дает в файлах конфигурации только одно присвоение:

CONFIG_USB_CONSOLE=y

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

CONFIG_CONSOLE=n

Использование select для helper-символов. Хорошее и безопасное использование select для создание "helper" символов, которые захватывают некоторое условие. Такие helper-символы предпочтительно не должны содержать prompt или зависимостей.

Например, helper-символ для индикации, что определенный CPU/SoC содержит FPU, должен быть определен следующим образом:

config CPU_HAS_FPU
   bool
   help
      If y, the CPU has an FPU
 
...
 
config SOC_FOO
   bool "FOO SoC"
   select CPU_HAS_FPU
 
...
 
config SOC_BAR
   bool "BAR SoC"
   select CPU_HAS_FPU

Это делает возможным для других символов проверку поддержки FPU традиционным способом, без просмотра определенных архитектур:

config FPU
   bool "Support floating point operations"
   depends on CPU_HAS_FPU

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

config FPU
   bool "Support floating point operations"
   depends on SOC_FOO || SOC_BAR || ...

Невидимые helper-символы могут быть также полезны без select. Например, следующий код определяет helper-символ, у которого значение y, если у машины есть произвольно определенный "большой” объем памяти:

config LARGE_MEM
   def_bool MEM_SIZE >= 64

Этот пример - сокращение от следующего:

config LARGE_MEM
  bool
  default MEM_SIZE >= 64

[Рекомендации по select]

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

● Избегайте выбора символов с prompt-ми или зависимостями. Предпочтительно используйте depends on. Если depends on приводит к разрастанию в файлах конфигурации, рассмотрите возможность добавления Kconfig default для наиболее общего значения.

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

Здравый смысл здесь применим, однако имейте в виду, что select часто на практике приводит к проблемам. Оператор depends on обычно более чистое и безопасное решение.

● Делайте сколько угодно select для простых helper-символов без prompt-ов и зависимостей. Это хороший инструмент для упрощения файлов Kconfig.

[Условные подключения]

Блоки if добавляют зависимости к каждому элементу в пределах if, как если бы использовался оператор depends on.

Общее недопонимание, связанное с if - предполагать, что следующий код условно подключает файл конфигурации Kconfig.other:

if DEP
source "Kconfig.other"
endif

В реальности условных включений в Kconfig нет. У if нет специального назначения, касающегося source.

Примечание: условное подключение будет невозможно реализовать, потому что условия if могут содержать (явно или косвенно) ссылки вперед на символы, которые еще не определены.

Скажем, Kconfig.other, упомянутый выше, содержит такое определение:

config FOO
   bool "Support foo"

В этом случае FOO закончится следующим определением:

config FOO
   bool "Support foo"
   depends on DEP

Следует отметить, что избыточно добавлять depends on DEP к определению FOO в Kconfig.other, потому что зависимость DEP уже добавлена if DEP.

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

[Застрявшие символы в menuconfig и guiconfig]

Есть некий тонкий глюк, связанный с взаимозависимыми символами, у которых есть prompt. Рассмотрим такие символы:

config FOO
   bool "Foo"
 
config STACK_SIZE
   hex "Stack size"
   default 0x200 if FOO
   default 0x100

Предположим, что есть намерение использовать более крупный стек при каждом разрешении FOO, и что изначально в конфигурации FOO запрещен. Также помните, что Zephyr создает начальную конфигурацию zephyr/.config в директории build путем слияния файлов конфигурации (например, подключения prj.conf). Этот файл конфигурации существует перед тем, как будет запущен menuconfig или guiconfig.

При первом входе в интерфейс конфигурации значение STACK_SIZE равно 0x100, как и ожидалось. После разрешения FOO, вы можете справедливо ожидать, что значение STACK_SIZE поменяется на 0x200, но оно останется 0x100.

Чтобы понять, что происходит, вспомните, что у STACK_SIZE есть prompt, а значит этот параметр конфигурируется пользователем, и имейте в виду, что все действия Kconfig происходят от начальной конфигурации:

CONFIG_STACK_SIZE=0x100

Поскольку Kconfig не может знать, пришло ли значение 0x100 от умолчания, или было введено пользователем, он должен предположить, что значение пришло от пользователя. Поскольку STACK_SIZE конфигурируется пользователем, то соблюдается значение из конфигурации, и любые умолчания символа игнорируются. Вот почему STACK_SIZE "замораживается" на 0x100, когда переключается FOO.

Правильное исправление зависит от того, что необходимо получить. Могут быть разные сценарии, для которых подойдут разные советы:

● Если STACK_SIZE может всегда быть получен автоматически, и не надо, чтобы его конфигурировал пользователь, то просто удалите prompt:

config STACK_SIZE
   hex
   default 0x200 if FOO
   default 0x100

Символы без prompt-ов игнорируют любое значение из сохраненной конфигурации.

● Если STACK_SIZE обычно должен конфигурироваться пользователем, но должен быть установлен в 0x200, когда разрешается FOO, то запретите его prompt, когда FOO разрешен, как описано в секции "Опциональные prompt":

config STACK_SIZE
   hex "Stack size" if !FOO
   default 0x200 if FOO
   default 0x100

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

config CUSTOM_STACK_SIZE
   bool "Use a custom stack size"
   help
     Enable this if you need to use a custom stack size. When disabled, a
     suitable stack size is calculated automatically.
 
config STACK_SIZE
   hex "Stack size" if CUSTOM_STACK_SIZE
   default 0x200 if FOO
   default 0x100

Пока CUSTOM_STACK_SIZE запрещен, STACK_SIZE будет игнорировать значение из сохраненной конфигурации.

Хорошая идея - попробовать изменять параметры в интерфейсе menuconfig или guiconfig, чтобы убедиться, что все идет как надо. Это особенно справедливо при введении таких довольно сложных конструкций.

[Назначение значений символам, у которых нет prompt]

Присваивания скрытых (так называемых невидимых, у которых нет prompt) символов в файлах конфигурации всегда игнорируются. Скрытые символы всегда получают свои значения косвенно, от других символов, например через default и select.

Общим источником путаницы является открытие выходного файла конфигурации (zephyr/.config), где видно множество присвоений скрытым символам, откуда делается ошибочное предположение, что эти назначения должны соблюдаться, когда конфигурация считывается Kconfig. В реальности все присваивания скрытым символам в zephyr/.config игнорируются системой Kconfig, как и для других файлов конфигурации.

Чтобы понять, почему zephyr/.config все еще включает присваивания скрытым символам, нужно вспомнить, что zephyr/.config обслуживает 2 отдельные функции:

1. Хранит сохраненную конфигурацию.
2. Хранит вывод конфигурации. Файл zephyr/.config парсится файлами CMake, чтобы они могли запрашивать настройки конфигурации.

Таким образом, присвоения скрытых символов в zephyr/.config это просто вывод конфигурации. Сам Kconfig игнорирует присваивания скрытым символам, когда вычисляет значения символов.

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

[Оператор depends on и символы string/int/hex]

Оператор depends on работает не только для символов bool, но также и для символов string, int и hex (и для choice).

Kconfig-определения ниже будут скрывать символ FOO_DEVICE_FREQUENCY, и запретят любой вывод конфигурации для него, когда запрещен FOO_DEVICE.

config FOO_DEVICE
   bool "Foo device"
 
config FOO_DEVICE_FREQUENCY
   int "Foo device frequency"
   depends on FOO_DEVICE

В общем хорошей идеей будет проверить, что в интерфейсе menuconfig/guiconfig отображаются только соответствующие символы. Если показывать FOO_DEVICE_FREQUENCY, когда FOO_DEVICE запрещен (и возможно скрыт), то это делает трудно понимаемой взаимосвязь между этими символами, даже если код никогда не смотрит на FOO_DEVICE_FREQUENCY, когда FOO_DEVICE запрещен.

[Символы menuconfig]

Если за определением символа FOO немедленно следуют другие символы, которые зависят от FOO, то эти символы становятся дочерними по отношению к FOO. Если FOO определен с config FOO, то дочерние элементы отображаются с отступом относительно FOO. Определение вместо этого FOO через menuconfig FOO поместит дочерние элементы в отдельное меню, корнем которого будет FOO.

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

menu "Foo subsystem"
 
config FOO_SUBSYSTEM
   bool "Foo subsystem"
 
if FOO_SUBSYSTEM
 
config FOO_FEATURE_1
   bool "Foo feature 1"
 
config FOO_FEATURE_2
   bool "Foo feature 2"
 
config FOO_FREQUENCY
   int "Foo frequency"
 
... lots of other FOO-related symbols
 
endif # FOO_SUBSYSTEM
 
endmenu

В этом случае возможно лучшим решением будет свернуть FOO_SUBSYSTEM в символ menuconfig:

menuconfig FOO_SUBSYSTEM
   bool "Foo subsystem"
 
if FOO_SUBSYSTEM
 
config FOO_FEATURE_1
   bool "Foo feature 1"
 
config FOO_FEATURE_2
   bool "Foo feature 2"
 
config FOO_FREQUENCY
   int "Foo frequency"
 
... lots of other FOO-related symbols
 
endif # FOO_SUBSYSTEM

В интерфейсе menuconfig это будет выглядеть следующим образом:

[*] Foo subsystem  --->

Обратите внимание, что определять menuconfig без дочерних символов не имеет смысла. Этого следует избегать, потому что будет выглядеть идентично символу со всеми невидимыми дочерними символами:

[*] I have no children  ----
[*] All my children are invisible  ----

[Проверка изменений в menuconfig/guiconfig]

Когда в файлы Kconfig добавляются новые символы, или делаются другие изменения, хорошей идеей будет просмотреть впоследствии эти символы в интерфейсе menuconfig или guiconfig. Чтобы быстро перейти к нужному символу, пользуйтесь функцией клавиши /.

Вот что следует проверить:

● Символы размещены в походящем месте? Удостоверьтесь, что они находятся в меню там, где больше всего подходят по смыслу, радом со связанными символами.

Если один символ зависит от другого, то часто хорошей идеей будет поместить зависимый символ сразу после символа, от которого он зависит. Он будет затем в интерфейсе menuconfig показан с отступом от родительского символа, и в guiconfig в отдельном меню родительского символа. Это также работает, если несколько символов размещены после символа, от которого они зависят.

● Легко ли из текста prompt понять назначение символа?

● Если добавляется несколько символов, все ли комбинации значений, которые они устанавливают, имеют смысл?

Например, если добавлены 2 символа FOO_SUPPORT и NO_FOO_SUPPORT, и оба могут быть разрешены одновременно, то это дает бессмысленную конфигурацию. В таком случае может быть будет лучше оставить только символ FOO_SUPPORT.

● Есть ли дублированные зависимости?

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

[Проверка изменений с помощью scripts/kconfig/lint.py]

После того, как вы сделали изменения Kconfig, можно использовать скрипт scripts/kconfig/lint.py для проверки наличия некоторых потенциальных проблем, наподобие не используемых символов и символов, которые нельзя разрешить. Используйте --help для просмотра доступных опций.

Некоторые проверки довольно эвристические, так что помеченный после проверки символ не обязательно содержит проблему. Если проверка возвращает ложное положительное значение, например из-за вставки токена в C (CONFIG_FOO_##index##_BAR), то просто игнорируйте её.

Когда исследуется неизвестный символ FOO_BAR, хорошей идеей будет запустить git grep FOO_BAR, чтобы найти ссылки на него. Также рекомендуется искать по некоторой части имени символа, например git grep FOO и git grep BAR, поскольку это может помочь раскрыть вставку токена.

[Рекомендации по стилю и сокращения]

В этой секции даны некоторые рекомендации по оформлению файлов Kconfig и сокращения.

Оформление общих зависимостей. Если последовательность символы/choice имеют общую зависимость, зависимость может быть обработана с помощью if. В качестве примера рассмотрим код:

config FOO
     bool "Foo"
     depends on DEP
 
config BAR
     bool "Bar"
     depends on DEP
 
choice
     prompt "Choice"
     depends on DEP
 
config BAZ
     bool "Baz"
 
config QAZ
     bool "Qaz"
 
endchoice

Здесь зависимость DEP может быть обработана следующим образом:

if DEP
 
config FOO
     bool "Foo"
 
config BAR
     bool "Bar"
 
choice
     prompt "Choice"
 
config BAZ
     bool "Baz"
 
config QAZ
     bool "Qaz"
 
endchoice
 
endif # DEP

Примечание: внутренне вторая версия кода трансформируется в первую.

Если последовательность символы/choice с общими зависимостями все находятся в одном меню, то зависимость можно поместить в само меню:

menu "Foo features"
     depends on FOO_SUPPORT
 
config FOO_FEATURE_1
     bool "Foo feature 1"
 
config FOO_FEATURE_2
     bool "Foo feature 2"
 
endmenu

Если FOO_SUPPORT установлено в n, то пропадет все меню.

Избыточные значения по умолчанию. Символы bool неявно по умолчанию получают значения n, и строковые символы неявно по умолчанию получают пустые строки. Таким образом, default n и default "" (почти) всегда избыточны.

Рекомендуемый стиль в Zephyr пропускать избыточные значения по умолчанию для символов bool и string. Это также дает более чистую документацию (Implicitly defaults to n instead of n if < dependencies, possibly inherited>).

Примечание: есть один случай, когда умолчание n/"" не избыточно, когда определение символа в нескольких местах, и есть необходимость в его переопределении, например default y в последующем определении.

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

Общие сокращения Kconfig. В Kconfig есть 2 сокращения, касающихся prompt и default.

● < type> "prompt" сокращение для одновременного указания типа и текста prompt. Например, следующие два определения эквивалентны:

config FOO
   bool "foo"
 
config FOO
   bool
   prompt "foo"

В Zephyr первый стиль является сокращением и более предпочтителен.

● def_< type> < value> сокращение для одновременного указания и типа, и значения. Например, следующие два определения эквивалентны:

config FOO
   def_bool BAR && BAZ
 
config FOO
   bool
   default BAR && BAZ

Использование обоих сокращений < type> "prompt" и def_< type> < value> в одном и том же определении будет избыточным, потому что тип определяется дважды.

Сокращение def_< type> < value> обычно полезно только для символов без prompt, и обычно неясно.

Примечание: для символов, определенных в нескольких местах (например файле Kconfig.defconfig в Zephyr), лучше всегда давать тип символу только в "базовом" определении символа, и использовать default (вместо def_< type> value) для остальных определений. Таким образом, если базовое определение символа удалено, то символ останется без типа, что приведен к генерации предупреждения, указывающего на другие определения символа. Это упростит поиск и удаление дополнительных определений символа.

Строки prompt. Для символа Kconfig, который разрешает драйвер/подсистему FOO, рассмотрите возможность указания только "Foo" в качестве текста prompt вместо того, чтобы указывать "Enable Foo support" или что-то подобное. Это обычно будет яснее в контексте опции, которая может быть переключена on/off, что делает сущности более целостными.

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

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

# < Обзор символов, определенных в этом файле, предпочтительно на English >
(пустая стока)
# Copyright (c) 2019 ...
# SPDX-License-Identifier: < лицензия>
(пустая стока)
(определения Kconfig)

● Форматируйте комментарии как # Comment вместо #Comment.

● Поместите пустую строку перед/после каждого if/endif верхнего уровня.

● Используйте один символ табуляции для каждого отступа.

● Делайте отступ текста help с двумя дополнительными пробелами.

[Менее известные и используемые возможности Kconfig]

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

Оператор imply. Этот оператор подобен select, однако учитывает зависимости и не устанавливает значение принудительно. Например, следующих код может использоваться для включения поддержки USB-клавиатуры по умолчанию на FOO SoC, все еще сохраняя для пользователя возможность это выключить:

config SOC_FOO
   bool "FOO SoC"
   imply USB_KEYBOARD
 
...
 
config USB_KEYBOARD
   bool "USB keyboard support"

Таким образом, imply действует как предложение, в то время как select принудительно устанавливает значение.

Опциональные prompt. В prompt символа может быть помещено условие, чтобы сделать это конфигурируемым для пользователя. Например, значение MASK, которое жестко закодировано в 0xFF на некоторых платах, и конфигурируется на других, может быть выражено следующим образом:

config MASK
   hex "Bitmask" if HAS_CONFIGURABLE_MASK
   default 0xFF

Примечание: это сокращение для следующего:

config MASK
   hex
   prompt "Bitmask" if HAS_CONFIGURABLE_MASK
   default 0xFF

Helper-символ HAS_CONFIGURABLE_MASK будет выбран платами, чтобы указать, что MASK можно конфигурировать. Когда MASK конфигурируема, она также по умолчанию будет 0xFF.

Опциональные choice. Определение choice с ключевым словом optional позволяет выключить весь choice при выборе ни одного из символов:

choice
   prompt "Use legacy protocol"
   optional
 
config LEGACY_PROTOCOL_1
   bool "Legacy protocol 1"
 
config LEGACY_PROTOCOL_2
   bool "Legacy protocol 2"
 
endchoice

В интерфейсе menuconfig это будет отображено, например, как [*] Use legacy protocol (Legacy protocol 1) --->, где choice может быть переключен в off того, чтобы не был выбран ни один из символов.

Условия visible if. Помещение условия visible if в меню скроет меню и все символы в нем, позволяя по-прежнему оставлять значения умолчания символов.

В качестве мотивирующего примера рассмотрим код:

menu "Foo subsystem"
   depends on HAS_CONFIGURABLE_FOO
 
config FOO_SETTING_1
   int "Foo setting 1"
   default 1
 
config FOO_SETTING_2
   int "Foo setting 2"
   default 2
 
endmenu

Когда HAS_CONFIGURABLE_FOO установлено в n, для FOO_SETTING_1 и FOO_SETTING_2 не генерируется вывод конфигурации, поскольку код выше логически становится эквивалентен коду:

config FOO_SETTING_1
   int "Foo setting 1"
   default 1
   depends on HAS_CONFIGURABLE_FOO
 
config FOO_SETTING_2
   int "Foo setting 2"
   default 2
   depends on HAS_CONFIGURABLE_FOO

Если мы хотим, чтобы символы все еще получили свои значения по умолчанию, даже когда HAS_CONFIGURABLE_FOO установлено в n, но они не были конфигурируемыми для пользователя, то вместо этого мы можем использовать visible if:

menu "Foo subsystem"
   visible if HAS_CONFIGURABLE_FOO
 
config FOO_SETTING_1
   int "Foo setting 1"
   default 1
 
config FOO_SETTING_2
   int "Foo setting 2"
   default 2
 
endmenu

Логически это эквивалентно следующему:

config FOO_SETTING_1
   int "Foo setting 1" if HAS_CONFIGURABLE_FOO
   default 1
 
config FOO_SETTING_2
   int "Foo setting 2" if HAS_CONFIGURABLE_FOO
   default 2

Примечание: см. секцию "Опциональные prompt" для информации по условиям в prompt.

Когда HAS_CONFIGURABLE установлено в n, мы теперь получим следующий вывод конфигурации для символов, вместо отсутствия вывода:

...
CONFIG_FOO_SETTING_1=1
CONFIG_FOO_SETTING_2=2
...

Kconfiglib поддерживает пользовательские функции препроцессора Kconfig, написанные на Python. Эти функции определены в scripts/kconfig/kconfigfunctions.py.

Примечание: официальная документация по препроцессору Kconfig находится в описании языка макросов Kconfig [7].

Большинство пользовательских функций препроцессора используется для получения информации об устройствах (devicetree) в Kconfig. Например, значение по умолчанию символа Kconfig может быть взято из свойства devicetree reg.

Функции, относящиеся к devicetree. Функции, перечисленные ниже, используются для получения информации об устройствах в Kconfig. См. строки документации Python в scripts/kconfig/kconfigfunctions.py для получения подробной информации.

Версия *_int каждой функции возвратит значение как десятичное целое, в то время как версия *_hex возвратит шестнадцатеричное значение с 0x.

$(dt_has_compat,< compatible string>)
$(dt_compat_enabled,< compatible string>)
$(dt_compat_on_bus,< compatible string>,)
$(dt_chosen_label,< property in /chosen>)
$(dt_chosen_enabled,< property in /chosen>)
$(dt_chosen_path,< property in /chosen>)
$(dt_chosen_has_compat,< property in /chosen>)
$(dt_path_enabled,< node path>)
$(dt_alias_enabled,< node alias>)
$(dt_nodelabel_enabled,< node label>)
$(dt_nodelabel_enabled_with_compat,< node label>,< compatible string>)
$(dt_chosen_reg_addr_int,< property in /chosen>[,< index>,< unit>])
$(dt_chosen_reg_addr_hex,< property in /chosen>[,< index>,< unit>])
$(dt_chosen_reg_size_int,< property in /chosen>[,< index>,< unit>])
$(dt_chosen_reg_size_hex,< property in /chosen>[,< index>,< unit>])
$(dt_node_reg_addr_int,< node path>[,< index>,< unit>])
$(dt_node_reg_addr_hex,< node path>[,< index>,< unit>])
$(dt_node_reg_size_int,< node path>[,< index>,< unit>])
$(dt_node_reg_size_hex,< node path>[,< index>,< unit>])
$(dt_compat_enabled,< compatible string>)
$(dt_chosen_enabled,< property in /chosen>)
$(dt_node_bool_prop,< node path>,< prop>)
$(dt_nodelabel_bool_prop,< node label>,< prop>)
$(dt_node_has_prop,< node path>,< prop>)
$(dt_nodelabel_has_prop,< node label>,< prop>)
$(dt_node_int_prop_int,< node path>,< prop>[,< unit>])
$(dt_node_int_prop_hex,< node path>,< prop>[,< unit>])
$(dt_node_str_prop_equals,< node path>,< prop>,< value>)
$(dt_nodelabel_has_compat,< node label>,< compatible string>)
$(dt_nodelabel_path,< node label>)
$(shields_list_contains,< shield name>)

Пример использования. Предположим, что есть devicetree для некоторой платы:

{
   soc {
      #address-cells = < 1>;
      #size-cells = < 1>;
 
      spi0: spi@10014000 {
         compatible = "sifive,spi0";
         reg = < 0x10014000 0x1000 0x20010000 0x3c0900>;
         reg-names = "control", "mem";
         ...
   };
};

Второй элемент reg в spi@1001400 (< 0x20010000 0x3c0900>) соответствует mem, и имеет значение адреса 0x20010000. Этот адрес может быть вставлен в Kconfig следующим образом:

config FLASH_BASE_ADDRESS
   default $(dt_node_reg_addr_hex,/soc/spi@1001400,1)

После применения препроцессора это превратится в следующее определение:

config FLASH_BASE_ADDRESS
   default 0x20010000

Zephyr использует реализацию Kconfiglib [8] для Kconfig, которая включает некоторые расширения Kconfig:

● Переменные окружения в операторах source разворачиваются напрямую, это значит отсутствие необходимости определения "bounce" символов с option env="ENV_VAR".

Примечание: option env также был удален из C tools в Linux 4.18.

Рекомендуется для обращения к переменным окружения использовать синтаксис $(FOO) вместо $FOO. Это использует новый препроцессор Kconfig. Синтаксис $FOO используется только для обеспечения обратной совместимости.

● Оператор source поддерживает glob-шаблоны, и подключает каждый подходящий файл. Шаблон требуется для совпадения как минимум с одним файлом.

Рассмотрим следующий пример:

source "foo/bar/*/Kconfig"

Если шаблон foo/bar/*/Kconfig совпадает с файлами foo/bar/baz/Kconfig и foo/bar/qaz/Kconfig, то этот оператор эквивалентен двум операторам source:

source "foo/bar/baz/Kconfig"
source "foo/bar/qaz/Kconfig"

Если не было обнаружено ни одного совпадения, то генерируется ошибка.

Шаблоны wildcard принимаются так же, как и для модуля Python glob [9].

Для случаев, когда нормальным будет отсутствие совпадения ни с одним файлом (или чистое имя файла не существует), доступен отдельный оператор osource (optional source). Оператор osource соответствует отсутствию оператора, если не было совпадения ни с одним из файлов.

Примечание: source и osource являются аналогами include и -include в Make.

● Доступен оператор rsource для подключения файлов, указанных по относительному пути. Путь относителен директории, где находится файл Kconfig, содержащий оператор rsource.

В качестве примера предположим, что foo/Kconfig это файл конфигурации верхнего уровня Kconfig, и что в foo/bar/Kconfig есть следующие операторы:

source "qaz/Kconfig1"
rsource "qaz/Kconfig2"

Это приведет к подключению двух файлов foo/qaz/Kconfig1 и foo/bar/qaz/Kconfig2.

Оператор rsource можно использовать для создания поддеревьев Kconfig, которые можно свободно перемещать. Оператор rsource также поддерживает glob-шаблоны.

Недостаток rsource в том, что он может усложнить поиск, где файл был подключен, поэтому используйте rsource только при необходимости.

● Оператор orsource доступен в качестве комбинации osource и rsource.

Например, следующий оператор подключит Kconfig1 и Kconfig2 из текущей директории (если они существуют):

orsource "Kconfig[12]"

● Доступны ключевые слова def_int, def_hex и def_string, аналогичные def_bool. Они одновременно устанавливают и тип, и значение по умолчанию.

[Ссылки]

1. Zephyr Kconfig Configuration site:zephyrproject.org.
2. Install Linux Host Dependencies site:zephyrproject.org.
3. Zephyr: разработка приложения.
4. zephyr/scripts/kconfig/kconfiglib.py site:github.com.
5. Zephyr Devicetree HOWTOs site:zephyrproject.org.
6. Zephyr Devicetree API site:zephyrproject.org.
7. Kconfig macro language site:kernel.org.
8. ulfalizer / Kconfiglib site:github.com.
9. glob Unix style pathname pattern expansion site:docs.python.org.

 

Комментарии  

 
0 #1 Alex 24.05.2023 19:04
Где можно найти отдельную реализацию Kconfig для Win10 в виде *.exe?
Цитировать
 

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


Защитный код
Обновить

Top of Page