Файли маніфестів MicroPython¶
Короткий огляд¶
MicroPython має функцію, яка дозволяє «заморозити» Python-код у мікропрограмі як альтернативу завантаженню коду з файлової системи.
Це має такі переваги:
код попередньо компілюється у байт-код, що усуває необхідність компіляції Python-джерела під час завантаження.
байт-код можна виконувати безпосередньо з ROM (тобто флеш-пам’яті), не копіюючи його в RAM. Аналогічно, будь-які константні об’єкти (рядки, кортежі тощо) також завантажуються з ROM. Це може значно збільшити обсяг пам’яті, доступної для вашого застосунку.
на пристроях без файлової системи це єдиний спосіб завантажити Python-код.
Під час розробки заморожування, як правило, не рекомендується, оскільки це значно уповільнить цикл розробки — кожне оновлення вимагатиме повторного прошивання всієї мікропрограми. Проте вибіркове заморожування рідко змінюваних залежностей (наприклад, сторонніх бібліотек) може бути корисним.
Спосіб перелічення Python-файлів для заморожування у мікропрограмі — це «маніфест», тобто Python-файл, який буде інтерпретовано процесом збірки. Зазвичай файл маніфесту створюється як частина визначення плати, але можна написати окремий файл маніфесту та використовувати його з наявним визначенням плати.
Файли маніфестів можуть визначати залежності від бібліотек micropython-lib, а також від Python-файлів у файловій системі та від інших файлів маніфестів.
Написання файлів маніфестів¶
Файл маніфесту — це Python-файл, що містить послідовність викликів функцій. Дивіться доступні функції, описані нижче.
Будь-які шляхи, що використовуються у файлах маніфестів, можуть містити такі змінні. Усі вони перетворюються на абсолютні шляхи.
$(MPY_DIR)— шлях до репозиторію micropython.$(MPY_LIB_DIR)— шлях до підмодуля micropython-lib. Рекомендується використовуватиrequire().$(PORT_DIR)— шлях до поточного порту (наприклад,ports/stm32)$(BOARD_DIR)— шлях до поточної плати (наприклад,ports/stm32/boards/OPENMV4)
Власні файли маніфестів не повинні розміщуватися в основному репозиторії MicroPython. Їх слід зберігати під контролем версій разом із рештою проекту.
Зазвичай маніфест для компіляції мікропрограми має включати маніфест порту, який може містити заморожені модулі, необхідні для роботи плати. Якщо потрібно лише додати додаткові модулі до наявної плати, включіть маніфест плати (який, своєю чергою, включить маніфест порту).
Збірка з власним маніфестом¶
Ваш маніфест можна вказати в командному рядку make за допомогою:
$ make BOARD=MYBOARD FROZEN_MANIFEST=/path/to/my/project/manifest.py
Це застосовується до всіх портів, включно з CMake-based (наприклад, rp2), оскільки обгортка Makefile передає це до збірки CMake.
Додавання маніфесту до визначення плати¶
Якщо у вас є власне визначення плати, ви можете налаштувати автоматичне включення вашого маніфесту. На портах на основі make (більшість портів) встановіть змінну FROZEN_MANIFEST у файлі mpconfigboard.mk.
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
На портах на основі CMake (наприклад, rp2) використовуйте натомість mpconfigboard.cmake
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
Функції високого рівня¶
Це функції, які ви будете використовувати найчастіше. Вони додають код до набору, що попередньо компілюється у байт-код та заморожується в образ мікропрограми:
moduleтаpackageзаморожують ваш власний локальний код — один файл або цілий каталог пакета відповідно.requireзаморожує опублікований пакет (та його залежності) з micropython-lib за іменем.includeвключає інший маніфест, щоб його заморожені модулі також були додані.add_libraryтаmetadata— допоміжні функції (реєстрація додаткових шляхів пошуку дляrequireта оголошення метаданих пакета).
Типовий маніфест мікропрограми спочатку includeує маніфест порту або плати (щоб необхідні модулі залишались замороженими), а потім додає власні рядки module/package/require.
Примітка: аргумент opt може бути встановлений для різних функцій — він керує рівнем оптимізації, що використовується крос-компілятором. Дивіться micropython.opt_level().
- add_library(library, library_path, prepend=False)¶
Реєструє шлях до зовнішньої іменованої бібліотеки (library).
Використовуйте це, коли потрібно, щоб
requireзнаходив пакети з каталогу, відмінного від micropython-lib — наприклад, з вашої власної колекції драйверів або стороннього репозиторію бібліотеки.Шлях library_path буде автоматично проглядатися при використанні
require. За замовчуванням додана бібліотека додається в кінець списку бібліотек для пошуку. ПередайтеTrueу prepend, щоб додати її на початок списку.Крім того, додану бібліотеку можна явно запросити за допомогою
require("name", library="library").
- package(package_path, files=None, base_path='.', opt=None)¶
Заморозити цілий пакет — каталог файлів
.py(можливо, з підпакетами) — щоб його можна було імпортувати якimport <package>. Використовуйтеmoduleдля одного окремого файлу.Це еквівалентно копіюванню каталогу «package_path» на пристрій (але як заморожений код).
У найпростішому випадку, щоб заморозити пакет «foo» у поточному каталозі:
package("foo")рекурсивно включить усі .py файли у foo і буде заморожено як
foo/**/*.py.Якщо пакет знаходиться не в тому самому каталозі, що й файл маніфесту, використовуйте
base_path:package("foo", base_path="path/to/libraries")Ви можете використовувати змінні, наведені вище, наприклад
$(PORT_DIR)уbase_path.Щоб обмежити набір певними файлами пакета, використовуйте
files(примітка: шляхи повинні бути відносними до пакета):package("foo", files=["bar/baz.py"]).
- module(module_path, base_path='.', opt=None)¶
Заморозити один окремий файл
.py, щоб його можна було імпортувати за іменем (module("foo.py")дозволяєimport foo). Використовуйтеpackageдля каталогу/пакета.Якщо файл знаходиться у поточному каталозі:
module("foo.py")Інакше використовуйте base_path для визначення розташування файлу:
module("foo.py", base_path="src/drivers")Ви можете використовувати змінні, наведені вище, наприклад
$(PORT_DIR)уbase_path.
- require(name, library=None)¶
Вимагати пакет за іменем (та його залежності) з micropython-lib.
Саме так стандартні розширення бібліотеки та драйвери спільноти заморожуються: названий пакет отримується з підмодуля micropython-lib і заморожується разом із усім, від чого залежить. Використовуйте
moduleабоpackageдля заморожування власного коду замість опублікованого пакета.За бажанням вкажіть library (рядок) для посилання на пакет з бібліотеки, попередньо зареєстрованої за допомогою
add_library. Інакше буде використано список шляхів до бібліотек.
- include(manifest_path)¶
Включити інший маніфест. Саме так компонуються маніфести: власний маніфест мікропрограми повинен
includeманіфест порту (або плати), щоб необхідні модулі залишалися замороженими, а потім додавати власні записи.Зазвичай маніфест для компіляції мікропрограми має включати маніфест порту, який може містити заморожені модулі, необхідні для роботи плати.
Аргумент manifest може бути рядком (ім’я файлу) або ітерованим об’єктом рядків.
Відносні шляхи розраховуються відносно поточного файлу маніфесту.
Якщо шлях вказує на каталог, то неявно включається файл manifest.py всередині цього каталогу.
Ви можете використовувати змінні, наведені вище, наприклад
$(PORT_DIR)уmanifest_path.
- metadata(description=None, version=None, license=None, author=None)¶
Визначити метадані для цього файлу маніфесту. Це корисно для маніфестів пакетів micropython-lib.
Ці поля використовуються при публікації/встановленні пакета з/до micropython-lib через mip; вони не потрібні у маніфесті мікропрограми плати.
Функції низького рівня¶
Ці функції задокументовані для повноти, але за винятком freeze_as_str весь функціонал доступний через функції високого рівня.
Функції freeze* відрізняються лише способом зберігання коду:
freeze_as_mpy/freeze_mpyзберігають попередньо скомпільований байт-код (.mpy) у флеш-пам’яті. Код виконується безпосередньо з флеш-пам’яті, використовує мінімальну RAM та швидко імпортується. Саме це використовуютьmodule,packageтаrequireвнутрішньо.freeze_as_strнатомість заморожує Python джерело, яке компілюється у байт-код під час імпорту (використовуючи RAM і потребуючи компілятора на пристрої). Це єдина можливість, не передбачена функціями високого рівня, тому вона є зазначеним вище винятком.
- freeze(path, script=None, opt=0)¶
Базовий примітив, на якому будуються функції високого рівня; надавайте перевагу їм. Заморожує вхідні дані, задані path, автоматично визначаючи їхній тип. Скрипт
.pyбуде спочатку скомпільовано у.mpy, а потім заморожено; файл.mpyбуде заморожено безпосередньо.path повинен бути каталогом — базовим каталогом для початку пошуку файлів. При імпорті отриманих заморожених модулів ім’я модуля починається після path, тобто path не включається в ім’я модуля.
Якщо path є відносним, він розраховується відносно поточного
manifest.py.Якщо script дорівнює None, всі файли у path будуть заморожені.
Якщо script є ітерованим об’єктом, то
freeze()викликається для всіх його елементів (з тими самими path та opt).Якщо script є рядком, то він вказує файл або каталог для заморожування та може включати додаткові каталоги перед файлом або останнім каталогом. Файл або каталог буде шукатися у path. Якщо script є каталогом, усі файли в ньому будуть заморожені.
opt — рівень оптимізації, що передається mpy-cross під час компіляції
.pyу.mpy. Ці рівні описані уmicropython.opt_level().
- freeze_as_str(path)¶
Заморозити вказаний path та всі скрипти
.pyу ньому як рядок, який буде скомпільовано при імпорті. Використовуйте це лише тоді, коли заморожений код повинен залишатися джерелом Python; це коштує RAM під час імпорту порівняно з варіантами.mpy.
- freeze_as_mpy(path, script=None, opt=0)¶
Заморозити вхідні дані, попередньо скомпілювавши скрипти
.pyу файли.mpy, а потім заморозивши отримані файли.mpy. Саме це робитьmoduleтаpackageпід капотом. Детальніше про аргументи дивіться уfreeze().
- freeze_mpy(path, script=None, opt=0)¶
Заморозити вхідні дані, які повинні бути файлами
.mpy, що заморожуються безпосередньо (без кроку компіляції). Детальніше про аргументи дивіться уfreeze().
Приклади¶
Щоб заморозити один файл із поточного каталогу, який буде доступний як import mydriver, використовуйте:
module("mydriver.py")
Щоб заморозити каталог файлів у підкаталозі «mydriver» поточного каталогу, який буде доступний як import mydriver, використовуйте:
package("mydriver")
Щоб заморозити бібліотеку «hmac» з micropython-lib, використовуйте:
require("hmac")
Більш повний приклад власного файлу manifest.py (для плати з власним маніфестом за замовчуванням):
# Include the board's default manifest.
include("$(BOARD_DIR)/manifest.py")
# Add a custom driver
module("mydriver.py")
# Add aiorepl from micropython-lib
require("aiorepl")
Тоді плату можна зібрати за допомогою
$ cd ports/stm32
$ make BOARD=MYBOARD FROZEN_MANIFEST=~/src/myproject/manifest.py
Зверніть увагу, що більшість плат не мають власного файлу manifest.py, натомість вони безпосередньо використовують портовий; у такому разі ваш маніфест повинен лише include("$(PORT_DIR)/boards/manifest.py").