MicroPython-manifestfiler¶
Sammanfattning¶
MicroPython har en funktion som gör det möjligt att ”frysa” Python-kod in i den fasta programvaran, som ett alternativ till att läsa in kod från filsystemet.
Detta har följande fördelar:
koden är förkompilerad till bytekod, vilket gör att Python-källkoden inte behöver kompileras vid inläsningstillfället.
bytekoden kan köras direkt från ROM (dvs. flashminne) i stället för att kopieras till RAM. På samma sätt läses även eventuella konstanta objekt (strängar, tupler osv.) in från ROM. Detta kan leda till att betydligt mer minne blir tillgängligt för din applikation.
på enheter som inte har något filsystem är detta det enda sättet att läsa in Python-kod.
Under utvecklingen rekommenderas frysning i allmänhet inte, eftersom det avsevärt saktar ner din utvecklingscykel då varje uppdatering kräver att hela den fasta programvaran flashas om. Det kan dock fortfarande vara användbart att selektivt frysa vissa sällan ändrade beroenden (såsom tredjepartsbibliotek).
Sättet att ange vilka Python-filer som ska frysas in i den fasta programvaran är via ett ”manifest”, vilket är en Python-fil som tolkas av byggprocessen. Vanligtvis skriver du en manifestfil som en del av en kortdefinition, men du kan också skriva en fristående manifestfil och använda den med en befintlig kortdefinition.
Manifestfiler kan definiera beroenden av bibliotek från micropython-lib samt Python-filer på filsystemet, och även av andra manifestfiler.
Skriva manifestfiler¶
En manifestfil är en Python-fil som innehåller en serie funktionsanrop. Se de tillgängliga funktionerna som definieras nedan.
Alla sökvägar som används i manifestfiler kan inkludera följande variabler. Dessa löses alla upp till absoluta sökvägar.
$(MPY_DIR)– sökväg till micropython-arkivet.$(MPY_LIB_DIR)– sökväg till micropython-lib-submodulen. Föredra att användarequire().$(PORT_DIR)– sökväg till den aktuella porten (t.ex.ports/stm32)$(BOARD_DIR)– sökväg till det aktuella kortet (t.ex.ports/stm32/boards/OPENMV4)
Anpassade manifestfiler bör inte ligga i huvudarkivet för MicroPython. Du bör hålla dem under versionshantering tillsammans med resten av ditt projekt.
Vanligtvis behöver ett manifest som används för att kompilera fast programvara inkludera portmanifestet, vilket kan inkludera frysta moduler som krävs för att kortet ska fungera. Om du bara vill lägga till ytterligare moduler till ett befintligt kort inkluderar du kortmanifestet (som i sin tur inkluderar portmanifestet).
Bygga med ett anpassat manifest¶
Ditt manifest kan anges på kommandoraden för make med:
$ make BOARD=MYBOARD FROZEN_MANIFEST=/path/to/my/project/manifest.py
Detta gäller för alla portar, inklusive CMake-baserade (t.ex. rp2), eftersom Makefile-omslaget skickar in detta till CMake-bygget.
Lägga till ett manifest i en kortdefinition¶
Om du har en anpassad kortdefinition kan du få den att automatiskt inkludera ditt anpassade manifest. På make-baserade portar (de flesta portar) anger du variabeln FROZEN_MANIFEST i din mpconfigboard.mk.
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
På CMake-baserade portar (t.ex. rp2) använder du i stället mpconfigboard.cmake
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
Högnivåfunktioner¶
Detta är de funktioner du normalt använder. De lägger till kod i den uppsättning som förkompileras till bytekod och fryses in i avbilden för den fasta programvaran:
moduleochpackagefryser din egen lokala källkod — en enskild fil respektive en hel paketkatalog.requirefryser ett publicerat paket (och dess beroenden) från micropython-lib, efter namn.includedrar in ett annat manifest så att även dess frysta moduler läggs till.add_libraryochmetadataär stödfunktioner (registrering av extra sökvägar förrequire, och deklaration av paketmetadata).
Ett typiskt firmware-manifest includear först port- eller kortmanifestet (så att de moduler kortet behöver förblir frysta), och lägger sedan till sina egna module-/package-/require-rader.
Obs! Nyckelordsargumentet opt kan anges på de olika funktionerna; detta styr optimeringsnivån som korskompilatorn använder. Se micropython.opt_level().
- add_library(library, library_path, prepend=False)¶
Registrera sökvägen till ett externt namngivet library.
Använd detta när du vill att
requireska lösa upp paket från en annan katalog än micropython-lib — till exempel din egen samling drivrutiner, eller en utcheckning av ett tredjepartsbibliotek.Sökvägen library_path genomsöks automatiskt när
requireanvänds. Som standard läggs det tillagda biblioteket till i slutet av listan över bibliotek att söka i. SkickaTrueför att prepend så att det läggs till i början av listan.Dessutom kan det tillagda biblioteket begäras explicit med
require("name", library="library").
- package(package_path, files=None, base_path='.', opt=None)¶
Frys ett helt paket — en katalog med
.py-filer (eventuellt med underpaket) — så att det kan importeras somimport <package>. Användmodulei stället för en enskild fristående fil.Detta motsvarar att kopiera katalogen ”package_path” till enheten (förutom att det är som fryst kod).
I det enklaste fallet, för att frysa ett paket ”foo” i den aktuella katalogen:
package("foo")kommer rekursivt att inkludera alla .py-filer i foo, och frysas som
foo/**/*.py.Om paketet inte ligger i samma katalog som manifestfilen, använd
base_path:package("foo", base_path="path/to/libraries")Du kan använda variablerna ovan, såsom
$(PORT_DIR)ibase_path.För att begränsa till vissa filer i paketet, använd
files(obs: sökvägar ska vara relativa till paketet):package("foo", files=["bar/baz.py"]).
- module(module_path, base_path='.', opt=None)¶
Frys en enskild fristående
.py-fil så att den kan importeras med sitt namn (module("foo.py")gör attimport foofungerar). Användpackageför en katalog/ett paket.Om filen ligger i den aktuella katalogen:
module("foo.py")Använd annars base_path för att lokalisera filen:
module("foo.py", base_path="src/drivers")Du kan använda variablerna ovan, såsom
$(PORT_DIR)ibase_path.
- require(name, library=None)¶
Kräv ett paket efter namn (och dess beroenden) från micropython-lib.
Så här fryses standardbibliotekstillägg och drivrutiner från gemenskapen in: det namngivna paketet hämtas från micropython-lib-submodulen och fryses tillsammans med allt det är beroende av. Använd
moduleellerpackagei stället för att frysa din egen källkod i stället för ett publicerat paket.Ange eventuellt library (en sträng) för att referera till ett paket från ett bibliotek som tidigare har registrerats med
add_library. Annars används listan över biblioteks-sökvägar.
- include(manifest_path)¶
Inkludera ett annat manifest. Så här komponeras manifest: ett anpassat firmware-manifest bör
includeport- (eller kort-) manifestet så att de moduler kortet behöver förblir frysta, och sedan lägga till sina egna poster.Vanligtvis behöver ett manifest som används för att kompilera fast programvara inkludera portmanifestet, vilket kan inkludera frysta moduler som krävs för att kortet ska fungera.
Argumentet manifest kan vara en sträng (filnamn) eller en itererbar samling av strängar.
Relativa sökvägar löses upp i förhållande till den aktuella manifestfilen.
Om sökvägen pekar på en katalog inkluderar den implicit filen manifest.py i den katalogen.
Du kan använda variablerna ovan, såsom
$(PORT_DIR)imanifest_path.
- metadata(description=None, version=None, license=None, author=None)¶
Definiera metadata för denna manifestfil. Detta är användbart för manifest för micropython-lib-paket.
Dessa fält används när ett paket publiceras till / installeras från micropython-lib via mip; de behövs inte i ett firmware-manifest för ett kort.
Lågnivåfunktioner¶
Dessa funktioner dokumenteras för fullständighetens skull, men med undantag för freeze_as_str kan all funktionalitet nås via högnivåfunktionerna.
Funktionerna freeze* skiljer sig endast i hur koden lagras:
freeze_as_mpy/freeze_mpylagrar förkompilerad bytekod (.mpy) i flashminne. Koden körs direkt från flashminnet, använder minimalt med RAM och importeras snabbt. Detta är vadmodule,packageochrequireanvänder internt.freeze_as_strfryser i stället Python-källkoden, som kompileras till bytekod vid importtillfället (vilket använder RAM och kräver kompilatorn på enheten). Detta är den enda funktionen som inte exponeras av högnivåfunktionerna, vilket är anledningen till undantaget som noterades ovan.
- freeze(path, script=None, opt=0)¶
Den underliggande primitiven som högnivåfunktionerna bygger på; föredra dessa. Frys den indata som anges av path, och bestäm automatiskt dess typ. Ett
.py-skript kompileras först till en.mpyoch fryses sedan, medan en.mpy-fil fryses direkt.path måste vara en katalog, vilken är baskatalogen där sökningen efter filer börjar. När de resulterande frysta modulerna importeras börjar modulnamnet efter path, dvs. path utesluts från modulnamnet.
Om path är relativ löses den upp i förhållande till den aktuella
manifest.py.Om script är None fryses alla filer i path.
Om script är en itererbar samling anropas
freeze()på alla objekt i samlingen (med samma path och opt vidarebefordrade).Om script är en sträng anger den filen eller katalogen som ska frysas, och den kan inkludera extra kataloger före filen eller den sista katalogen. Filen eller katalogen söks efter i path. Om script är en katalog fryses alla filer i den katalogen.
opt är optimeringsnivån som skickas till mpy-cross vid kompilering av
.pytill.mpy. Dessa nivåer beskrivs imicropython.opt_level().
- freeze_as_str(path)¶
Frys den angivna path och alla
.py-skript inuti den som en sträng, vilken kompileras vid import. Använd detta endast när den frysta koden måste förbli Python-källkod; det kostar RAM vid importtillfället jämfört med.mpy-varianterna.
- freeze_as_mpy(path, script=None, opt=0)¶
Frys indata genom att först kompilera
.py-skripten till.mpy-filer, och sedan frysa de resulterande.mpy-filerna. Detta är vadmoduleochpackagegör under huven. Sefreeze()för ytterligare detaljer om argumenten.
- freeze_mpy(path, script=None, opt=0)¶
Frys indata, som måste vara
.mpy-filer som fryses direkt (inget kompileringssteg). Sefreeze()för ytterligare detaljer om argumenten.
Exempel¶
För att frysa en enskild fil från den aktuella katalogen som blir tillgänglig som import mydriver, använd:
module("mydriver.py")
För att frysa en katalog med filer i en underkatalog ”mydriver” till den aktuella katalogen som blir tillgänglig som import mydriver, använd:
package("mydriver")
För att frysa biblioteket ”hmac” från micropython-lib, använd:
require("hmac")
Ett mer komplett exempel på en anpassad manifest.py-fil (för ett kort som har sitt eget standardmanifest) är:
# 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")
Sedan kan kortet kompileras med
$ cd ports/stm32
$ make BOARD=MYBOARD FROZEN_MANIFEST=~/src/myproject/manifest.py
Observera att de flesta kort inte har sin egen manifest.py, utan använder portens direkt, i vilket fall ditt manifest bara bör include("$(PORT_DIR)/boards/manifest.py") i stället.