MicroPython manifest-bestanden¶
Samenvatting¶
MicroPython beschikt over een functie waarmee Python-code in de firmware kan worden “bevroren”, als alternatief voor het laden van code vanaf het bestandssysteem.
Dit heeft de volgende voordelen:
de code wordt vooraf gecompileerd naar bytecode, waardoor de Python-broncode niet bij het laden hoeft te worden gecompileerd.
de bytecode kan rechtstreeks vanuit ROM (d.w.z. flashgeheugen) worden uitgevoerd in plaats van naar RAM te worden gekopieerd. Op vergelijkbare wijze worden ook eventuele constante objecten (strings, tuples, enz.) vanuit ROM geladen. Dit kan ervoor zorgen dat er aanzienlijk meer geheugen beschikbaar is voor uw applicatie.
op apparaten die geen bestandssysteem hebben, is dit de enige manier om Python-code te laden.
Tijdens de ontwikkeling wordt bevriezen over het algemeen afgeraden, omdat het uw ontwikkelcyclus aanzienlijk vertraagt: elke update vereist dan het opnieuw flashen van de volledige firmware. Toch kan het nuttig zijn om selectief enkele zelden veranderende afhankelijkheden te bevriezen (zoals externe bibliotheken).
De manier om de Python-bestanden op te sommen die in de firmware moeten worden bevroren, is via een “manifest”: een Python-bestand dat door het bouwproces wordt geïnterpreteerd. Doorgaans schrijft u een manifest-bestand als onderdeel van een bordefinitie, maar u kunt ook een op zichzelf staand manifest-bestand schrijven en dit gebruiken met een bestaande bordefinitie.
Manifest-bestanden kunnen afhankelijkheden definiëren van bibliotheken uit micropython-lib, evenals van Python-bestanden op het bestandssysteem, en ook van andere manifest-bestanden.
Manifest-bestanden schrijven¶
Een manifest-bestand is een Python-bestand dat een reeks functieaanroepen bevat. Zie de hieronder gedefinieerde beschikbare functies.
Alle paden die in manifest-bestanden worden gebruikt, kunnen de volgende variabelen bevatten. Deze worden allemaal omgezet naar absolute paden.
$(MPY_DIR)– pad naar de micropython-repo.$(MPY_LIB_DIR)– pad naar de micropython-lib-submodule. Gebruik bij voorkeurrequire().$(PORT_DIR)– pad naar de huidige port (bijv.ports/stm32)$(BOARD_DIR)– pad naar het huidige bord (bijv.ports/stm32/boards/OPENMV4)
Aangepaste manifest-bestanden horen niet thuis in de hoofd-MicroPython-repository. U dient ze samen met de rest van uw project in versiebeheer te houden.
Doorgaans moet een manifest dat wordt gebruikt voor het compileren van firmware het port-manifest opnemen, dat bevroren modules kan bevatten die vereist zijn om het bord te laten functioneren. Als u alleen extra modules aan een bestaand bord wilt toevoegen, neem dan het bordmanifest op (dat op zijn beurt het port-manifest opneemt).
Bouwen met een aangepast manifest¶
Uw manifest kan op de make-opdrachtregel worden opgegeven met:
$ make BOARD=MYBOARD FROZEN_MANIFEST=/path/to/my/project/manifest.py
Dit geldt voor alle ports, ook voor de CMake-gebaseerde (bijv. rp2), aangezien de Makefile-wrapper dit doorgeeft aan de CMake-build.
Een manifest toevoegen aan een bordefinitie¶
Als u een aangepaste bordefinitie hebt, kunt u deze uw aangepaste manifest automatisch laten opnemen. Stel op make-gebaseerde ports (de meeste ports) in uw mpconfigboard.mk de variabele FROZEN_MANIFEST in.
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
Gebruik op CMake-gebaseerde ports (bijv. rp2) in plaats daarvan mpconfigboard.cmake
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
Functies op hoog niveau¶
Dit zijn de functies die u normaal gesproken zult gebruiken. Ze voegen code toe aan de verzameling die wordt voorgecompileerd naar bytecode en bevroren in de firmware-image:
moduleenpackagebevriezen uw eigen lokale broncode — respectievelijk een enkel bestand of een hele package-directory.requirebevriest een gepubliceerd package (en zijn afhankelijkheden) uit micropython-lib, op naam.includehaalt een ander manifest binnen, zodat ook zijn bevroren modules worden toegevoegd.add_libraryenmetadatazijn ondersteunende functies (het registreren van extra zoekpaden voorrequireen het declareren van package-metadata).
Een typisch firmware-manifest doet eerst een include van het port- of bordmanifest (zodat de modules die het bord nodig heeft bevroren blijven), en voegt vervolgens zijn eigen module/package/require-regels toe.
Opmerking: het sleutelwoordargument opt kan op de verschillende functies worden ingesteld; dit bepaalt het optimalisatieniveau dat de cross-compiler gebruikt. Zie micropython.opt_level().
- add_library(library, library_path, prepend=False)¶
Registreer het pad naar een externe genaamde library.
Gebruik dit wanneer u wilt dat
requirepackages oplost vanuit een andere directory dan micropython-lib — bijvoorbeeld uw eigen verzameling drivers of een uitgecheckte externe bibliotheek.Het pad library_path wordt automatisch doorzocht bij het gebruik van
require. Standaard wordt de toegevoegde bibliotheek aan het einde van de lijst met te doorzoeken bibliotheken geplaatst. GeefTruemee om te prepend en deze aan het begin van de lijst toe te voegen.Bovendien kan de toegevoegde bibliotheek expliciet worden opgevraagd met
require("name", library="library").
- package(package_path, files=None, base_path='.', opt=None)¶
Bevries een volledig package — een directory met
.py-bestanden (optioneel met sub-packages) — zodat het kan worden geïmporteerd alsimport <package>. Gebruik in plaats daarvanmodulevoor een enkel op zichzelf staand bestand.Dit komt overeen met het kopiëren van de “package_path”-directory naar het apparaat (behalve dan als bevroren code).
In het eenvoudigste geval, om een package “foo” in de huidige directory te bevriezen:
package("foo")neemt recursief alle .py-bestanden in foo op, die worden bevroren als
foo/**/*.py.Als het package niet in dezelfde directory staat als het manifest-bestand, gebruik dan
base_path:package("foo", base_path="path/to/libraries")U kunt de bovenstaande variabelen gebruiken, zoals
$(PORT_DIR)inbase_path.Om de selectie te beperken tot bepaalde bestanden in het package, gebruikt u
files(let op: paden moeten relatief zijn ten opzichte van het package):package("foo", files=["bar/baz.py"]).
- module(module_path, base_path='.', opt=None)¶
Bevries een enkel op zichzelf staand
.py-bestand, zodat het op naam kan worden geïmporteerd (module("foo.py")zorgt ervoor datimport foowerkt). Gebruikpackagevoor een directory/package.Als het bestand zich in de huidige directory bevindt:
module("foo.py")Gebruik anders base_path om het bestand te lokaliseren:
module("foo.py", base_path="src/drivers")U kunt de bovenstaande variabelen gebruiken, zoals
$(PORT_DIR)inbase_path.
- require(name, library=None)¶
Vereis een package op naam (en zijn afhankelijkheden) uit micropython-lib.
Zo worden uitbreidingen van de standaardbibliotheek en community-drivers ingebracht: het genoemde package wordt opgehaald uit de micropython-lib-submodule en bevroren samen met alles waarvan het afhankelijk is. Gebruik in plaats daarvan
moduleofpackageom uw eigen broncode te bevriezen in plaats van een gepubliceerd package.Geef optioneel library op (een string) om te verwijzen naar een package uit een bibliotheek die eerder is geregistreerd met
add_library. Anders wordt de lijst met bibliotheekpaden gebruikt.
- include(manifest_path)¶
Neem een ander manifest op. Zo worden manifests samengesteld: een aangepast firmware-manifest moet het port- (of bord-)manifest
includezodat de modules die het bord nodig heeft bevroren blijven, en voegt vervolgens zijn eigen items toe.Doorgaans moet een manifest dat wordt gebruikt voor het compileren van firmware het port-manifest opnemen, dat bevroren modules kan bevatten die vereist zijn om het bord te laten functioneren.
Het manifest-argument kan een string (bestandsnaam) zijn of een itereerbare reeks strings.
Relatieve paden worden opgelost ten opzichte van het huidige manifest-bestand.
Als het pad naar een directory verwijst, dan neemt het impliciet het bestand manifest.py in die directory op.
U kunt de bovenstaande variabelen gebruiken, zoals
$(PORT_DIR)inmanifest_path.
- metadata(description=None, version=None, license=None, author=None)¶
Definieer metadata voor dit manifest-bestand. Dit is nuttig voor manifests van micropython-lib-packages.
Deze velden worden gebruikt wanneer een package wordt gepubliceerd naar / geïnstalleerd vanuit micropython-lib via mip; ze zijn niet nodig in een firmware-manifest voor een bord.
Functies op laag niveau¶
Deze functies worden voor de volledigheid gedocumenteerd, maar met uitzondering van freeze_as_str is alle functionaliteit toegankelijk via de functies op hoog niveau.
De freeze*-functies verschillen alleen in hoe de code wordt opgeslagen:
freeze_as_mpy/freeze_mpyslaan voorgecompileerde bytecode (.mpy) op in flashgeheugen. De code draait rechtstreeks vanuit flashgeheugen, gebruikt minimaal RAM en importeert snel. Dit is watmodule,packageenrequireintern gebruiken.freeze_as_strbevriest in plaats daarvan de Python-broncode, die bij het importeren naar bytecode wordt gecompileerd (waarbij RAM wordt gebruikt en de on-device compiler vereist is). Dit is de enige mogelijkheid die niet door de functies op hoog niveau wordt blootgesteld, wat de reden is voor de hierboven genoemde uitzondering.
- freeze(path, script=None, opt=0)¶
De onderliggende primitieve waarop de functies op hoog niveau voortbouwen; gebruik bij voorkeur die. Bevries de invoer die wordt opgegeven door path, waarbij het type automatisch wordt bepaald. Een
.py-script wordt eerst naar een.mpygecompileerd en daarna bevroren, en een.mpy-bestand wordt rechtstreeks bevroren.path moet een directory zijn, namelijk de basisdirectory waar het zoeken naar bestanden begint. Bij het importeren van de resulterende bevroren modules begint de naam van de module na path, d.w.z. path wordt uitgesloten van de modulenaam.
Als path relatief is, wordt het opgelost ten opzichte van de huidige
manifest.py.Als script None is, worden alle bestanden in path bevroren.
Als script een itereerbare reeks is, dan wordt
freeze()aangeroepen op alle items van de reeks (met dezelfde path en opt doorgegeven).Als script een string is, dan geeft deze het te bevriezen bestand of de te bevriezen directory aan, en kan deze extra directories vóór het bestand of de laatste directory bevatten. Er wordt in path gezocht naar het bestand of de directory. Als script een directory is, dan worden alle bestanden in die directory bevroren.
opt is het optimalisatieniveau dat aan mpy-cross wordt doorgegeven bij het compileren van
.pynaar.mpy. Deze niveaus worden beschreven inmicropython.opt_level().
- freeze_as_str(path)¶
Bevries het opgegeven path en alle
.py-scripts erin als een string, die bij het importeren wordt gecompileerd. Gebruik dit alleen wanneer de bevroren code Python-broncode moet blijven; het kost RAM tijdens het importeren in vergelijking met de.mpy-varianten.
- freeze_as_mpy(path, script=None, opt=0)¶
Bevries de invoer door eerst de
.py-scripts naar.mpy-bestanden te compileren en vervolgens de resulterende.mpy-bestanden te bevriezen. Dit is watmoduleenpackageonder de motorkap doen. Ziefreeze()voor meer details over de argumenten.
- freeze_mpy(path, script=None, opt=0)¶
Bevries de invoer, die moet bestaan uit
.mpy-bestanden die rechtstreeks worden bevroren (geen compilatiestap). Ziefreeze()voor meer details over de argumenten.
Voorbeelden¶
Om een enkel bestand uit de huidige directory te bevriezen dat beschikbaar zal zijn als import mydriver, gebruikt u:
module("mydriver.py")
Om een directory met bestanden te bevriezen in een subdirectory “mydriver” van de huidige directory, die beschikbaar zal zijn als import mydriver, gebruikt u:
package("mydriver")
Om de “hmac”-bibliotheek uit micropython-lib te bevriezen, gebruikt u:
require("hmac")
Een vollediger voorbeeld van een aangepast manifest.py-bestand (voor een bord dat zijn eigen standaardmanifest heeft) is:
# 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")
Vervolgens kan het bord worden gecompileerd met
$ cd ports/stm32
$ make BOARD=MYBOARD FROZEN_MANIFEST=~/src/myproject/manifest.py
Houd er rekening mee dat de meeste borden geen eigen manifest.py hebben, maar in plaats daarvan rechtstreeks die van de port gebruiken; in dat geval zou uw manifest gewoon include("$(PORT_DIR)/boards/manifest.py") moeten doen.