MicroPython .mpy datoteke¶
MicroPython definira koncept .mpy datoteke, koja je binarni spremnički format datoteke koji sadrži prethodno prevedeni kod i koja se može uvesti poput uobičajenog .py modula. Datoteka foo.mpy može se uvesti pomoću import foo, sve dok mehanizam uvoza može pronaći foo.mpy na uobičajeni način. Obično se svaki direktorij naveden u sys.path pretražuje redom. Pri pretraživanju određenog direktorija prvo se traži foo.py, a ako se ne pronađe, tada se traži foo.mpy, te se pretraga nastavlja u sljedećem direktoriju ako se nijedna ne pronađe. Zbog toga foo.py ima prednost pred foo.mpy.
Te .mpy datoteke mogu sadržavati bytecode koji se obično generira iz Python izvornih datoteka (.py datoteka) pomoću programa mpy-cross. Za neke arhitekture .mpy datoteka može sadržavati i izvorni strojni kod, koji se može generirati na razne načine, najčešće iz C izvornog koda.
Prevoditelj mpy-cross¶
mpy-cross je unakrsni prevoditelj koji pretvara .py izvornu datoteku u .mpy binarni spremnik spreman za uvoz na kameru. Dio je MicroPython izvornog stabla (istog onog koje se koristi za izgradnju firmwarea kamere), a objavljen je i kao pip paket za korištenje na strani domaćina bez potpunog preuzimanja firmwarea:
$ pip install --user mpy-cross
Ili putem pipx:
$ pipx install mpy-cross
Nakon instalacije, pozovite ga na pojedinačnoj izvornoj datoteci:
$ mpy-cross foo.py
Time se stvara foo.mpy u trenutnom direktoriju, spreman za kopiranje na datotečni sustav kamere uz druge module ili za umetanje u ROMFS sliku.
Najkorisnije opcije naredbenog retka:
-o <path>– izlazna putanja za generirani.mpy(zadano je naziv ulazne datoteke s promijenjenom ekstenzijom;-o -zapisuje na stdout).-O<n>– razina optimizacije od0do3. Zadana vrijednost0zadržava tvrdnje i potpune lokacije izvornog koda;3uklanja tvrdnje i dokumentacijske nizove te prepisujeif __debug__blokove. Razina upravlja istommicropython.opt_levelpovršinom koju izlaže izvršno okruženje.-march=<arch>– ciljna izvorna arhitektura za funkcije označene s@nativei@viper. Obavezno kada izvorni kod koristi te dekoratore. Vrijednost mora odgovarati klasi MCU-a kamere: odaberite je s popisa koji ispisujempy-cross --helpili je pročitajte s kamere u izvođenju pomoćusys.implementation._mpy.-s <path>– niz izvorne putanje ugrađen u informacije za otklanjanje pogrešaka u.mpy. Korisno kada se putanja na disku razlikuje od putanje uvoza pod kojom bi se datoteka trebala prikazivati u tragovima poziva.-X emit=bytecode|native|viper– odabir zadanog emitera za cijeli modul (alternativa po funkciji dekoratorima@native/@viper).--version– ispisuje verziju.mpyformata koju emitira ovaj binarni program. Taj se broj mora podudarati s verzijom koju podržava izvršno okruženje kamere (vidi tablicu izdanja u nastavku) ili će uvoz izazvatiValueError('incompatible .mpy file').
Pokrenite mpy-cross --help za potpuni popis zastavica.
Pip paket također izlaže mali Python modul API tako da skripte za izgradnju mogu pokretati prevoditelj unutar procesa umjesto ručnog grananja podprocesa:
import mpy_cross
mpy_cross.compile('foo.py', dest='build/foo.mpy', opt=3,
march=mpy_cross.NATIVE_ARCH_ARMV7EMSP)
mpy_cross.compile, mpy_cross.run i mpy_cross.mpy_version tri su ulazne točke; mpy_cross.CrossCompileError nosi stderr prevoditelja kada nešto pođe po zlu. Konstante arhitekture (NATIVE_ARCH_ARMV7EMSP, NATIVE_ARCH_ARMV7EMDP itd.) odgovaraju nizovima koje prihvaća zastavica -march.
Verzioniranje i kompatibilnost .mpy datoteka¶
Dana .mpy datoteka može, ali i ne mora biti kompatibilna s danim MicroPython sustavom. Kompatibilnost se temelji na sljedećem:
Verzija .mpy datoteke: verzija datoteke mora odgovarati verziji koju podržava sustav koji je učitava.
Pod-verzija .mpy datoteke: ako .mpy datoteka sadrži izvorni strojni kod, tada pod-verzija datoteke mora odgovarati verziji koju podržava sustav koji je učitava. U suprotnom, ako u .mpy datoteci nema izvornog strojnog koda, tada se pod-verzija pri učitavanju zanemaruje.
Bitovi malog cijelog broja: .mpy datoteka zahtijevat će minimalni broj bitova u small integer, a sustav koji je učitava mora podržavati barem toliko bitova.
Izvorna arhitektura: ako .mpy datoteka sadrži izvorni strojni kod, tada će odrediti arhitekturu tog strojnog koda, a sustav koji je učitava mora podržavati izvršavanje koda te arhitekture.
Ako MicroPython sustav podržava uvoz .mpy datoteka, tada će polje sys.implementation._mpy postojati i vraćati cijeli broj koji kodira verziju (donjih 8 bitova), značajke i izvornu arhitekturu.
Pokušaj uvoza .mpy datoteke koja ne prođe jedan od prva četiri testa izazvat će ValueError('incompatible .mpy file'). Pokušaj uvoza .mpy datoteke koja ne prođe test izvorne arhitekture (ako sadrži izvorni strojni kod) izazvat će ValueError('incompatible .mpy arch').
Ako uvoz .mpy datoteke ne uspije, pokušajte sljedeće:
Utvrdite .mpy verziju i zastavice koje podržava vaš MicroPython sustav izvođenjem:
import sys sys_mpy = sys.implementation._mpy arch = [None, 'x86', 'x64', 'armv6', 'armv6m', 'armv7m', 'armv7em', 'armv7emsp', 'armv7emdp', 'xtensa', 'xtensawin', 'rv32imc', 'rv64imc'][(sys_mpy >> 10) & 0x0F] print('mpy version:', sys_mpy & 0xff) print('mpy sub-version:', sys_mpy >> 8 & 3) print('mpy flags:', end='') if arch: print(' -march=' + arch, end='') if (sys_mpy >> 16) != 0: print(' -march-flags=' + (sys_mpy >> 16), end='') print()
Provjerite valjanost .mpy datoteke pregledom prva dva bajta datoteke. Prvi bajt trebao bi biti veliko slovo ‘M’, a drugi bajt bit će broj verzije, koji bi se trebao podudarati s gornjom verzijom sustava. Ako se ne podudara, ponovno izgradite .mpy datoteku.
Provjerite podudara li se .mpy verzija sustava s verzijom koju emitira
mpy-crosskorišten za izgradnju .mpy datoteke, koja se pronalazi pomoćumpy-cross --version. Ako se ne podudara, ponovno preveditempy-crossiz Git repozitorija preuzetog na oznaci (ili hashu) koju prijavljujempy-cross --version.Provjerite koristite li ispravne
mpy-crosszastavice, pronađene pomoću gornjeg koda ili pregledom Makefile varijableMPY_CROSS_FLAGSza port koji koristite.Ako treći bajt .mpy datoteke ima postavljen bit #6, tada provjerite je li kodirani vuint zastavica specifičnih za arhitekturu kompatibilan s ciljem na koji uvozite datoteku.
Sljedeća tablica prikazuje korespondenciju između MicroPython izdanja i .mpy verzije.
MicroPython izdanje |
.mpy verzija |
|---|---|
v1.23.0 i novije |
6.3 |
v1.22.x |
6.2 |
v1.20 - v1.21.0 |
6.1 |
v1.19.x |
6 |
v1.12 - v1.18 |
5 |
v1.11 |
4 |
v1.9.3 - v1.10 |
3 |
v1.9 - v1.9.2 |
2 |
v1.5.1 - v1.8.7 |
0 |
Radi potpunosti, sljedeća tablica prikazuje Git commit glavnog MicroPython repozitorija u kojem je promijenjena .mpy verzija.
promjena .mpy verzije |
Git commit |
|---|---|
6.2 na 6.3 |
bdbc869f9ea200c0d28b2bc7bfb60acd9d884e1b |
6.1 na 6.2 |
6967ff3c581a66f73e9f3d78975f47528db39980 |
6 na 6.1 |
d94141e1473aebae0d3c63aeaa8397651ad6fa01 |
5 na 6 |
f2040bfc7ee033e48acef9f289790f3b4e6b74e5 |
4 na 5 |
5716c5cf65e9b2cb46c2906f40302401bdd27517 |
3 na 4 |
9a5f92ea72754c01cc03e5efcdfe94021120531e |
2 na 3 |
ff93fd4f50321c6190e1659b19e64fef3045a484 |
1 na 2 |
dd11af209d226b7d18d5148b239662e30ed60bad |
0 na 1 |
6a11048af1d01c78bdacddadd1b72dc7ba7c6478 |
početna verzija 0 |
d8c834c95d506db979ec871417de90b7951edc30 |
Binarno kodiranje .mpy datoteka¶
MicroPython .mpy datoteke binarni su spremnički format s objektima koda (bytecode i izvorni strojni kod) pohranjenima interno u ugniježđenoj hijerarhiji. Kod za vanjski modul pohranjuje se prvi, a zatim slijede njegova djeca. Svako dijete može imati daljnju djecu, na primjer u slučaju klase koja ima metode ili funkcije koja definira lambdu ili razumijevanje. Kako bi datoteke ostale male, a istovremeno omogućile širok raspon mogućih vrijednosti, na mnogim mjestima koristi koncept varijabilno kodiranog nepredznačenog cijelog broja (vuint). Slično UTF-8 kodiranju, ovo kodiranje pohranjuje 7 bitova po bajtu, pri čemu je 8. bit (MSB) postavljen ako slijedi jedan ili više bajtova. Bitovi nepredznačenog cijelog broja pohranjuju se u vuint u LSB obliku.
Najviša razina .mpy datoteke sastoji se od tri dijela:
Zaglavlje.
Globalne tablice qstr i konstanti.
Sirovi kod za vanjski opseg modula. Taj se vanjski opseg izvršava kada se .mpy datoteka uveze.
Sadržaj .mpy datoteke možete pregledati pomoću mpy-tool.py, na primjer (pokrenuto iz korijena glavnog MicroPython repozitorija):
$ ./tools/mpy-tool.py -xd myfile.mpy
Zaglavlje¶
.mpy zaglavlje je:
veličina |
polje |
|---|---|
bajt |
vrijednost 0x4d (ASCII ‘M’) |
bajt |
.mpy broj glavne verzije |
bajt |
zastavice značajki, izvorna arhitektura, broj sporedne verzije (u starijim verzijama bile su zastavice značajki) |
bajt |
broj bitova u malom cijelom broju |
Treći bajt podijeljen je kako slijedi (prvo MSB):
bit |
značenje |
|---|---|
7 |
rezervirano, mora biti 0 |
6 |
vuint zastavica specifičnih za arhitekturu slijedi nakon zaglavlja |
5..2 |
broj izvorne arhitekture |
1..0 |
broj sporedne verzije |
Zastavice specifične za arhitekturu¶
Ako je postavljen bit #6 bajta zastavica značajki u zaglavlju, tada će nakon zaglavlja slijediti vuint koji sadrži opcionalne informacije specifične za arhitekturu. Sadržaj ovog cijelog broja ovisi o tome za koju je izvornu arhitekturu datoteka namijenjena.
Ovo se trenutno koristi za pohranu toga koja RISC-V procesorska proširenja MPY datoteka treba za ispravan rad osim I, M, C i Zicsr. Različite varijante ArmV7 identificiraju se svojim brojem izvorne arhitekture, ali ponovno korištenje tog mehanizma zakompliciralo bi stvari za RV32 i RV64.
MPY datoteke namijenjene za RV32 ili RV64 koje ne trebaju nikakva posebna procesorska proširenja ne moraju pružati cijeli broj zastavica (uz postavljanje odgovarajućeg bita u zaglavlju). Nepostojanje vrijednosti zastavica za RV32 i RV64 MPY datoteke koristi se za označavanje da nisu potrebna nikakva posebna proširenja te štedi jedan bajt u konačnom izlaznom binarnom programu.
Vidi također opciju naredbenog retka -march-flags u mpy-tool.py i mpy-cross, te opciju naredbenog retka --arch-flags u mpy_ld.py za postavljanje ove vrijednosti pri stvaranju MPY datoteka.
Globalne tablice qstr i konstanti¶
.mpy datoteka sadrži jednu qstr tablicu i jednu tablicu konstantnih objekata. One su globalne za .mpy datoteku, referenciraju ih svi ugniježđeni objekti sirovog koda. qstr tablica preslikava interni qstr broj (interni za .mpy datoteku) na razriješeni qstr broj izvršnog okruženja u koje se .mpy datoteka uvozi. Time se .mpy datoteka povezuje s ostatkom sustava unutar kojeg se izvršava. Tablica konstantnih objekata popunjava se referencama na sve konstantne objekte koji su .mpy datoteci potrebni.
veličina |
polje |
|---|---|
vuint |
broj qstr-ova |
vuint |
broj konstantnih objekata |
… |
qstr podaci |
… |
kodirani konstantni objekti |
Elementi sirovog koda¶
Element sirovog koda sadrži kod, bilo bytecode ili izvorni strojni kod. Njegov sadržaj je:
veličina |
polje |
|---|---|
vuint |
tip, veličina i postoje li podelementi sirovog koda |
… |
kod (bytecode ili strojni kod) |
vuint |
broj podelemenata sirovog koda (samo ako je različit od nule) |
… |
podelementi sirovog koda |
Prvi vuint u elementu sirovog koda kodira tip koda pohranjenog u ovom elementu (dva najmanje značajna bita), ima li ovaj sirovi kod djece (treći najmanje značajan bit) i duljinu koda koji slijedi (količinu RAM-a koju treba dodijeliti za njega).
Nakon vuinta dolazi sam kod. Osim ako je tip koda viper kod s relokacijama, taj je kod konstantni podatak i ne treba ga mijenjati.
Ako ovaj sirovi kod ima djece (kako je naznačeno bitom u prvom vuintu), nakon koda dolazi vuint koji broji podelemente sirovog koda.
Konačno se rekurzivno pohranjuju svi podelementi sirovog koda.