Fișierele manifest MicroPython¶
Rezumat¶
MicroPython are o funcționalitate care permite ca un cod Python să fie „înghețat” în firmware, ca alternativă la încărcarea codului din sistemul de fișiere.
Aceasta oferă următoarele avantaje:
codul este precompilat în bytecode, evitând necesitatea de a compila sursa Python la momentul încărcării.
bytecode-ul poate fi executat direct din ROM (adică din memoria flash) în loc să fie copiat în RAM. În mod similar, orice obiecte constante (șiruri de caractere, tupluri etc.) sunt încărcate tot din ROM. Acest lucru poate duce la o cantitate semnificativ mai mare de memorie disponibilă pentru aplicația dumneavoastră.
pe dispozitivele care nu au un sistem de fișiere, aceasta este singura modalitate de a încărca cod Python.
În timpul dezvoltării, înghețarea nu este recomandată în general, deoarece va încetini semnificativ ciclul de dezvoltare, întrucât fiecare actualizare va necesita reflashing-ul întregului firmware. Totuși, poate fi în continuare utilă pentru a îngheța selectiv unele dependențe care se modifică rar (cum ar fi bibliotecile terțe).
Modalitatea de a lista fișierele Python care vor fi înghețate în firmware este prin intermediul unui „manifest”, care este un fișier Python ce va fi interpretat de procesul de compilare. De obicei, ați scrie un fișier manifest ca parte a definiției unei plăci, dar puteți de asemenea scrie un fișier manifest de sine stătător și să îl utilizați cu o definiție de placă existentă.
Fișierele manifest pot defini dependențe de biblioteci din micropython-lib, precum și de fișiere Python din sistemul de fișiere, și de asemenea de alte fișiere manifest.
Scrierea fișierelor manifest¶
Un fișier manifest este un fișier Python care conține o serie de apeluri de funcții. Consultați funcțiile disponibile definite mai jos.
Orice cale folosită în fișierele manifest poate include următoarele variabile. Toate acestea se rezolvă în căi absolute.
$(MPY_DIR)– calea către repozitoriul micropython.$(MPY_LIB_DIR)– calea către submodulul micropython-lib. Preferați să folosițirequire().$(PORT_DIR)– calea către portul curent (de exempluports/stm32)$(BOARD_DIR)– calea către placa curentă (de exempluports/stm32/boards/OPENMV4)
Fișierele manifest personalizate nu ar trebui să se afle în repozitoriul principal MicroPython. Ar trebui să le păstrați sub control de versiune împreună cu restul proiectului dumneavoastră.
De obicei, un manifest folosit pentru compilarea firmware-ului va trebui să includă manifestul portului, care ar putea include module înghețate necesare pentru funcționarea plăcii. Dacă doriți doar să adăugați module suplimentare la o placă existentă, atunci includeți manifestul plăcii (care la rândul său va include manifestul portului).
Compilarea cu un manifest personalizat¶
Manifestul dumneavoastră poate fi specificat în linia de comandă make cu:
$ make BOARD=MYBOARD FROZEN_MANIFEST=/path/to/my/project/manifest.py
Acest lucru se aplică tuturor porturilor, inclusiv celor bazate pe CMake (de exemplu rp2), deoarece wrapper-ul Makefile va transmite acest lucru către compilarea CMake.
Adăugarea unui manifest la o definiție de placă¶
Dacă aveți o definiție de placă personalizată, puteți face ca aceasta să includă automat manifestul dumneavoastră personalizat. Pe porturile bazate pe make (majoritatea porturilor), în fișierul mpconfigboard.mk setați variabila FROZEN_MANIFEST.
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
Pe porturile bazate pe CMake (de exemplu rp2), folosiți în schimb mpconfigboard.cmake
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
Funcții de nivel înalt¶
Acestea sunt funcțiile pe care le veți folosi în mod normal. Ele adaugă cod la setul care este precompilat în bytecode și înghețat în imaginea firmware-ului:
moduleșipackageîngheață sursa locală proprie — un singur fișier, respectiv un întreg director de pachet.requireîngheață un pachet publicat (și dependențele sale) din micropython-lib, după nume.includeaduce un alt manifest, astfel încât modulele sale înghețate să fie adăugate și ele.add_libraryșimetadatasunt funcții de suport (înregistrarea de căi de căutare suplimentare pentrurequireși declararea metadatelor pachetului).
Un manifest tipic de firmware mai întâi includemanifestul portului sau al plăcii (astfel încât modulele de care are nevoie placa să rămână înghețate), apoi adaugă propriile linii module/package/require.
Notă: Argumentul-cuvânt-cheie opt poate fi setat pe diverse funcții; acesta controlează nivelul de optimizare folosit de compilatorul încrucișat. Consultați micropython.opt_level().
- add_library(library, library_path, prepend=False)¶
Înregistrează calea către o bibliotecă externă cu nume.
Folosiți acest lucru atunci când doriți ca
requiresă rezolve pachete dintr-un director diferit de micropython-lib — de exemplu propria dumneavoastră colecție de drivere sau o copie a unei biblioteci terțe.Calea library_path va fi căutată automat la utilizarea lui
require. În mod implicit, biblioteca adăugată este adăugată la sfârșitul listei de biblioteci de căutat. TransmitețiTruepentru a o prepune, adică pentru a o adăuga la începutul listei.În plus, biblioteca adăugată poate fi solicitată explicit folosind
require("name", library="library").
- package(package_path, files=None, base_path='.', opt=None)¶
Îngheață un întreg pachet — un director de fișiere
.py(opțional cu subpachete) — astfel încât să poată fi importat caimport <package>. Folosițimoduleîn schimb pentru un singur fișier de sine stătător.Acest lucru este echivalent cu copierea directorului „package_path” pe dispozitiv (cu excepția faptului că este cod înghețat).
În cel mai simplu caz, pentru a îngheța un pachet „foo” din directorul curent:
package("foo")va include recursiv toate fișierele .py din foo și va fi înghețat ca
foo/**/*.py.Dacă pachetul nu se află în același director ca fișierul manifest, folosiți
base_path:package("foo", base_path="path/to/libraries")Puteți folosi variabilele de mai sus, cum ar fi
$(PORT_DIR)înbase_path.Pentru a restrânge la anumite fișiere din pachet, folosiți
files(notă: căile ar trebui să fie relative la pachet):package("foo", files=["bar/baz.py"]).
- module(module_path, base_path='.', opt=None)¶
Îngheață un singur fișier
.pyde sine stătător, astfel încât să poată fi importat după numele său (module("foo.py")face caimport foosă funcționeze). Folosițipackagepentru un director/pachet.Dacă fișierul se află în directorul curent:
module("foo.py")În caz contrar, folosiți base_path pentru a localiza fișierul:
module("foo.py", base_path="src/drivers")Puteți folosi variabilele de mai sus, cum ar fi
$(PORT_DIR)înbase_path.
- require(name, library=None)¶
Solicită un pachet după nume (și dependențele sale) din micropython-lib.
Astfel sunt înghețate extensiile bibliotecii standard și driverele comunitare: pachetul cu numele dat este preluat din submodulul micropython-lib și înghețat împreună cu tot ceea ce depinde de el. Folosiți
modulesaupackageîn schimb pentru a îngheța propria sursă în loc de un pachet publicat.Opțional, specificați library (un șir de caractere) pentru a referi un pachet dintr-o bibliotecă care a fost înregistrată anterior cu
add_library. În caz contrar, va fi folosită lista de căi de biblioteci.
- include(manifest_path)¶
Include un alt manifest. Astfel se compun manifestele: un manifest de firmware personalizat ar trebui să
includemanifestul portului (sau al plăcii), astfel încât modulele de care are nevoie placa să rămână înghețate, și apoi să adauge propriile intrări.De obicei, un manifest folosit pentru compilarea firmware-ului va trebui să includă manifestul portului, care ar putea include module înghețate necesare pentru funcționarea plăcii.
Argumentul manifest poate fi un șir de caractere (nume de fișier) sau un obiect iterabil de șiruri de caractere.
Căile relative sunt rezolvate în raport cu fișierul manifest curent.
Dacă calea duce către un director, atunci include implicit fișierul manifest.py din acel director.
Puteți folosi variabilele de mai sus, cum ar fi
$(PORT_DIR)înmanifest_path.
- metadata(description=None, version=None, license=None, author=None)¶
Definește metadatele pentru acest fișier manifest. Acest lucru este util pentru manifestele pachetelor micropython-lib.
Aceste câmpuri sunt consumate atunci când un pachet este publicat în / instalat din micropython-lib prin mip; ele nu sunt necesare într-un manifest de firmware al unei plăci.
Funcții de nivel scăzut¶
Aceste funcții sunt documentate pentru completitudine, dar cu excepția lui freeze_as_str toată funcționalitatea poate fi accesată prin intermediul funcțiilor de nivel înalt.
Funcțiile freeze* diferă doar prin modul în care este stocat codul:
freeze_as_mpy/freeze_mpystochează bytecode precompilat (.mpy) în memoria flash. Codul rulează direct din memoria flash, folosește un minim de RAM și se importă rapid. Acest lucru este utilizat intern demodule,packageșirequire.freeze_as_strîngheață în schimb sursa Python, care este compilată în bytecode la momentul importului (folosind RAM și necesitând compilatorul de pe dispozitiv). Aceasta este singura capabilitate neexpusă de funcțiile de nivel înalt, motiv pentru care reprezintă excepția menționată mai sus.
- freeze(path, script=None, opt=0)¶
Primitiva de bază pe care se construiesc funcțiile de nivel înalt; preferați-le pe acelea. Îngheață intrarea specificată de path, determinându-i automat tipul. Un script
.pyva fi mai întâi compilat într-un.mpyși apoi înghețat, iar un fișier.mpyva fi înghețat direct.path trebuie să fie un director, care este directorul de bază de la care începe căutarea fișierelor. La importul modulelor înghețate rezultate, numele modulului va începe după path, adică path este exclus din numele modulului.
Dacă path este relativ, este rezolvat în raport cu fișierul
manifest.pycurent.Dacă script este None, toate fișierele din path vor fi înghețate.
Dacă script este un obiect iterabil, atunci
freeze()este apelat pe toate elementele iterabilului (cu aceiași path și opt transmiși mai departe).Dacă script este un șir de caractere, atunci acesta specifică fișierul sau directorul de înghețat și poate include directoare suplimentare înaintea fișierului sau a ultimului director. Fișierul sau directorul va fi căutat în path. Dacă script este un director, atunci toate fișierele din acel director vor fi înghețate.
opt este nivelul de optimizare care urmează să fie transmis lui mpy-cross la compilarea
.pyîn.mpy. Aceste niveluri sunt descrise înmicropython.opt_level().
- freeze_as_str(path)¶
Îngheață path-ul dat și toate scripturile
.pydin interiorul său ca șir de caractere, care va fi compilat la import. Folosiți acest lucru doar atunci când codul înghețat trebuie să rămână sursă Python; costă RAM la momentul importului în comparație cu variantele.mpy.
- freeze_as_mpy(path, script=None, opt=0)¶
Îngheață intrarea compilând mai întâi scripturile
.pyîn fișiere.mpy, apoi înghețând fișierele.mpyrezultate. Acest lucru îl facmoduleșipackageîn fundal. Consultațifreeze()pentru detalii suplimentare despre argumente.
- freeze_mpy(path, script=None, opt=0)¶
Îngheață intrarea, care trebuie să fie fișiere
.mpyce sunt înghețate direct (fără pas de compilare). Consultațifreeze()pentru detalii suplimentare despre argumente.
Exemple¶
Pentru a îngheța un singur fișier din directorul curent care va fi disponibil ca import mydriver, folosiți:
module("mydriver.py")
Pentru a îngheța un director de fișiere dintr-un subdirector „mydriver” al directorului curent care va fi disponibil ca import mydriver, folosiți:
package("mydriver")
Pentru a îngheța biblioteca „hmac” din micropython-lib, folosiți:
require("hmac")
Un exemplu mai complet de fișier manifest.py personalizat (pentru o placă ce are propriul manifest implicit) este:
# 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")
Apoi placa poate fi compilată cu
$ cd ports/stm32
$ make BOARD=MYBOARD FROZEN_MANIFEST=~/src/myproject/manifest.py
Rețineți că majoritatea plăcilor nu au propriul manifest.py, ci folosesc direct pe cel al portului, caz în care manifestul dumneavoastră ar trebui doar să facă include("$(PORT_DIR)/boards/manifest.py") în schimb.