MicroPython .mpy -tiedostot¶
MicroPython määrittelee .mpy-tiedoston käsitteen. Kyseessä on binäärinen säiliötiedostomuoto, joka sisältää esikäännettyä koodia ja jonka voi tuoda kuten tavallisen .py-moduulin. Tiedosto foo.mpy voidaan tuoda komennolla import foo, kunhan foo.mpy löytyy tuontikoneiston tavanomaisesta hakupaikasta. Yleensä jokainen sys.path-listassa lueteltu hakemisto käydään läpi järjestyksessä. Tiettyä hakemistoa tutkittaessa etsitään ensin tiedostoa foo.py, ja jos sitä ei löydy, etsitään tiedostoa foo.mpy. Mikäli kumpaakaan ei löydy, haku jatkuu seuraavasta hakemistosta. Näin ollen foo.py on etusijalla tiedostoon foo.mpy nähden.
Nämä .mpy-tiedostot voivat sisältää bytecode-koodia, joka tavallisesti tuotetaan Python-lähdekooditiedostoista (.py-tiedostoista) mpy-cross-ohjelmalla. Joillakin arkkitehtuureilla .mpy-tiedosto voi sisältää myös natiivia konekoodia, joka voidaan tuottaa monin eri tavoin, erityisesti C-lähdekoodista.
mpy-cross-kääntäjä¶
mpy-cross on ristikääntäjä, joka muuntaa .py-lähdekooditiedoston .mpy-binäärisäiliöksi, joka on valmis tuotavaksi kameralle. Se on osa MicroPythonin lähdekoodipuuta (samaa, jota käytetään kameran laiteohjelmiston rakentamiseen) ja se julkaistaan myös pip-pakettina isäntäkoneella käytettäväksi ilman täydellistä laiteohjelmiston kloonausta:
$ pip install --user mpy-cross
Tai pipx-työkalun kautta:
$ pipx install mpy-cross
Kun se on asennettu, suorita se yksittäiselle lähdekooditiedostolle:
$ mpy-cross foo.py
Tämä tuottaa tiedoston foo.mpy nykyiseen hakemistoon valmiina kopioitavaksi kameran tiedostojärjestelmään muiden moduulien rinnalle tai syötettäväksi ROMFS-kuvaan.
Hyödyllisimmät komentorivivalitsimet:
-o <path>– tulostuspolku luodulle.mpy-tiedostolle (oletuksena syötetiedoston nimi, jonka tarkennin on korvattu;-o -kirjoittaa vakiotulosteeseen).-O<n>– optimointitaso0–3. Oletustaso0säilyttää assertiot ja täydet lähdekoodisijainnit; taso3poistaa assertiot ja docstringit sekä uudelleenkirjoittaaif __debug__-lohkot. Taso ohjaa samaamicropython.opt_level-rajapintaa, jonka ajoympäristö tarjoaa.-march=<arch>– kohdenatiiviarkkitehtuuri@native- ja@viper-koristelluille funktioille. Vaaditaan, kun lähdekoodi käyttää näitä koristelijoita. Arvon on vastattava kameran MCU-luokkaa: valitse se listasta, jonkampy-cross --helptulostaa, tai lue se kameralta ajonaikaisesti komennollasys.implementation._mpy.-s <path>–.mpy-tiedoston virheenkorjaustietoihin upotettava lähdepolkumerkkijono. Hyödyllinen, kun levyllä oleva polku eroaa siitä tuontipolusta, jonka alla tiedoston tulisi näkyä jäljityksissä.-X emit=bytecode|native|viper– valitse oletusemitteri koko moduulille (funktiokohtainen vaihtoehto@native- /@viper-koristelijoille).--version– tulostaa.mpy-muodon version, jonka tämä binääri tuottaa. Tämän numeron on vastattava versiota, jota kameran ajoympäristö tukee (katso julkaisutaulukko alla), tai tuonti aiheuttaa virheenValueError('incompatible .mpy file').
Suorita mpy-cross --help saadaksesi täydellisen valitsinlistan.
Pip-paketti tarjoaa myös pienen Python-moduulirajapinnan, jotta rakennusskriptit voivat ajaa kääntäjää prosessin sisällä sen sijaan, että aliprosessi haarautettaisiin käsin:
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 ja mpy_cross.mpy_version ovat ne kolme aloituspistettä; mpy_cross.CrossCompileError välittää kääntäjän stderr-tulosteen, kun jokin menee vikaan. Arkkitehtuurivakiot (NATIVE_ARCH_ARMV7EMSP, NATIVE_ARCH_ARMV7EMDP jne.) vastaavat merkkijonoja, jotka -march-valitsin hyväksyy.
.mpy-tiedostojen versiointi ja yhteensopivuus¶
Tietty .mpy-tiedosto voi olla yhteensopiva tietyn MicroPython-järjestelmän kanssa tai sitten ei. Yhteensopivuus perustuu seuraaviin tekijöihin:
.mpy-tiedoston versio: tiedoston version on vastattava versiota, jota sitä lataava järjestelmä tukee.
.mpy-tiedoston aliversio: jos .mpy-tiedosto sisältää natiivia konekoodia, tiedoston aliversion on vastattava versiota, jota sitä lataava järjestelmä tukee. Muussa tapauksessa, jos .mpy-tiedostossa ei ole natiivia konekoodia, aliversio jätetään huomiotta latauksen aikana.
Pienen kokonaisluvun bitit: .mpy-tiedosto vaatii vähimmäismäärän bittejä small integer-tyypiltä, ja sitä lataavan järjestelmän on tuettava vähintään tätä bittimäärää.
Natiiviarkkitehtuuri: jos .mpy-tiedosto sisältää natiivia konekoodia, se määrittää kyseisen konekoodin arkkitehtuurin, ja sitä lataavan järjestelmän on tuettava tämän arkkitehtuurin koodin suoritusta.
Jos MicroPython-järjestelmä tukee .mpy-tiedostojen tuontia, kenttä sys.implementation._mpy on olemassa ja palauttaa kokonaisluvun, joka koodaa version (alemmat 8 bittiä), ominaisuudet ja natiiviarkkitehtuurin.
Sellaisen .mpy-tiedoston tuontiyritys, joka ei läpäise jotakin neljästä ensimmäisestä testistä, aiheuttaa virheen ValueError('incompatible .mpy file'). Sellaisen .mpy-tiedoston tuontiyritys, joka ei läpäise natiiviarkkitehtuuritestiä (jos se sisältää natiivia konekoodia), aiheuttaa virheen ValueError('incompatible .mpy arch').
Jos .mpy-tiedoston tuonti epäonnistuu, kokeile seuraavaa:
Selvitä MicroPython-järjestelmäsi tukema .mpy-versio ja liput suorittamalla:
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()
Tarkista .mpy-tiedoston kelpoisuus tutkimalla tiedoston kaksi ensimmäistä tavua. Ensimmäisen tavun tulisi olla iso ’M’-kirjain ja toisen tavun versionumero, jonka tulisi vastata edellä saatua järjestelmän versiota. Jos se ei täsmää, rakenna .mpy-tiedosto uudelleen.
Tarkista, vastaako järjestelmän .mpy-versio versiota, jonka tuotti se
mpy-cross, jota käytettiin .mpy-tiedoston rakentamiseen; tämän saa selville komennollampy-cross --version. Jos se ei täsmää, käännämpy-crossuudelleen Git-tietovarastosta, joka on otettu ulos siitä tagista (tai hajautusarvosta), jonkampy-cross --versionraportoi.Varmista, että käytät oikeita
mpy-cross-lippuja, jotka selviävät yllä olevalla koodilla tai tutkimalla käyttämäsi portinMPY_CROSS_FLAGS-Makefile-muuttujaa.Jos .mpy-tiedoston kolmannen tavun bitti #6 on asetettu, tarkista, onko koodattu arkkitehtuurikohtainen lippubittien vuint yhteensopiva sen kohteen kanssa, jolle tuot tiedostoa.
Seuraava taulukko näyttää vastaavuuden MicroPython-julkaisun ja .mpy-version välillä.
MicroPython-julkaisu |
.mpy-versio |
|---|---|
v1.23.0 ja uudemmat |
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 |
Täydellisyyden vuoksi seuraava taulukko näyttää MicroPythonin pääaariston Git-commitin, jossa .mpy-versio muuttui.
.mpy-version muutos |
Git-commit |
|---|---|
6.2 -> 6.3 |
bdbc869f9ea200c0d28b2bc7bfb60acd9d884e1b |
6.1 -> 6.2 |
6967ff3c581a66f73e9f3d78975f47528db39980 |
6 -> 6.1 |
d94141e1473aebae0d3c63aeaa8397651ad6fa01 |
5 -> 6 |
f2040bfc7ee033e48acef9f289790f3b4e6b74e5 |
4 -> 5 |
5716c5cf65e9b2cb46c2906f40302401bdd27517 |
3 -> 4 |
9a5f92ea72754c01cc03e5efcdfe94021120531e |
2 -> 3 |
ff93fd4f50321c6190e1659b19e64fef3045a484 |
1 -> 2 |
dd11af209d226b7d18d5148b239662e30ed60bad |
0 -> 1 |
6a11048af1d01c78bdacddadd1b72dc7ba7c6478 |
alkuperäinen versio 0 |
d8c834c95d506db979ec871417de90b7951edc30 |
.mpy-tiedostojen binäärikoodaus¶
MicroPython .mpy -tiedostot ovat binäärinen säiliömuoto, jossa koodiobjektit (bytecode ja natiivi konekoodi) tallennetaan sisäisesti sisäkkäiseen hierarkiaan. Uloimman moduulin koodi tallennetaan ensin, ja sitten sen lapset seuraavat. Kullakin lapsella voi olla edelleen lapsia, esimerkiksi kun luokalla on metodeja tai funktio määrittelee lambdan tai läpikäynnin. Pitääkseen tiedostot pieninä mutta tarjotakseen silti laajan mahdollisten arvojen alueen se käyttää monessa kohdassa muuttuvanmittaisesti koodatun etumerkittömän kokonaisluvun (vuint) käsitettä. UTF-8-koodauksen tapaan tämä koodaus tallentaa 7 bittiä tavua kohden siten, että 8. bitti (MSB) on asetettu, jos yksi tai useampi tavu seuraa. Etumerkittömän kokonaisluvun bitit tallennetaan vuint-muotoon LSB-muodossa.
.mpy-tiedoston ylin taso koostuu kolmesta osasta:
Otsake.
Globaalit qstr- ja vakiotaulukot.
Moduulin uloimman näkyvyysalueen raakakoodi. Tämä uloin näkyvyysalue suoritetaan, kun .mpy-tiedosto tuodaan.
.mpy-tiedoston sisältöä voi tutkia mpy-tool.py-työkalulla, esimerkiksi (suoritetaan MicroPythonin pääaariston juuresta):
$ ./tools/mpy-tool.py -xd myfile.mpy
Otsake¶
.mpy-otsake on:
koko |
kenttä |
|---|---|
tavu |
arvo 0x4d (ASCII ’M’) |
tavu |
.mpy-pääversionumero |
tavu |
ominaisuusliput, natiiviarkkitehtuuri, aliversionumero (vanhemmissa versioissa olivat ominaisuusliput) |
tavu |
pienen kokonaisluvun bittien määrä |
Kolmas tavu jakautuu seuraavasti (MSB ensin):
bitti |
merkitys |
|---|---|
7 |
varattu, oltava 0 |
6 |
arkkitehtuurikohtainen lippujen vuint seuraa otsaketta |
5..2 |
natiiviarkkitehtuurin numero |
1..0 |
aliversionumero |
Arkkitehtuurikohtaiset liput¶
Jos otsakkeen ominaisuuslippujen tavun bitti #6 on asetettu, otsaketta seuraa vuint, joka sisältää valinnaista arkkitehtuurikohtaista tietoa. Tämän kokonaisluvun sisältö riippuu siitä, mille natiiviarkkitehtuurille tiedosto on tarkoitettu.
Tätä käytetään tällä hetkellä tallentamaan, mitä RISC-V-suoritinlaajennuksia MPY-tiedosto tarvitsee toimiakseen oikein laajennusten I, M, C ja Zicsr lisäksi. Eri ArmV7-variantit tunnistetaan niiden natiiviarkkitehtuurinumeron perusteella, mutta tämän mekanismin uudelleenkäyttö mutkistaisi asioita RV32:n ja RV64:n osalta.
RV32:lle tai RV64:lle tarkoitettujen MPY-tiedostojen, jotka eivät tarvitse mitään erityisiä suoritinlaajennuksia, ei tarvitse tarjota lippukokonaislukua (otsakkeen asianmukaisen bitin asettamisen ohella). Lippuarvon puuttumista RV32- ja RV64-MPY-tiedostoissa käytetään osoittamaan, ettei erityisiä laajennuksia tarvita, ja se säästää yhden tavun lopullisessa tulostebinäärissä.
Katso myös -march-flags-komentorivivalitsin sekä työkalussa mpy-tool.py että mpy-cross-ohjelmassa, ja --arch-flags-komentorivivalitsin työkalussa mpy_ld.py tämän arvon asettamiseksi MPY-tiedostoja luotaessa.
Globaalit qstr- ja vakiotaulukot¶
.mpy-tiedosto sisältää yhden qstr-taulukon ja yhden vakio-objektitaulukon. Nämä ovat .mpy-tiedostolle globaaleja, ja kaikki sisäkkäiset raakakoodiobjektit viittaavat niihin. qstr-taulukko kuvaa sisäisen qstr-numeron (.mpy-tiedoston sisäisen) sen ajoympäristön ratkaistuun qstr-numeroon, johon .mpy-tiedosto tuodaan. Tämä linkittää .mpy-tiedoston muuhun järjestelmään, jonka sisällä se suoritetaan. Vakio-objektitaulukko täytetään viittauksilla kaikkiin vakio-objekteihin, joita .mpy-tiedosto tarvitsee.
koko |
kenttä |
|---|---|
vuint |
qstr-jonojen määrä |
vuint |
vakio-objektien määrä |
… |
qstr-data |
… |
koodatut vakio-objektit |
Raakakoodielementit¶
Raakakoodielementti sisältää koodia, joko bytecode- tai natiivia konekoodia. Sen sisältö on:
koko |
kenttä |
|---|---|
vuint |
tyyppi, koko ja se, onko ali-raakakoodielementtejä |
… |
koodi (bytecode tai konekoodi) |
vuint |
ali-raakakoodielementtien määrä (vain jos nollasta poikkeava) |
… |
ali-raakakoodielementit |
Raakakoodielementin ensimmäinen vuint koodaa tähän elementtiin tallennetun koodin tyypin (kaksi vähiten merkitsevää bittiä), onko tällä raakakoodilla lapsia (kolmas vähiten merkitsevä bitti), ja seuraavan koodin pituuden (sille varattavan RAM-muistin määrän).
vuintin jälkeen tulee itse koodi. Ellei koodityyppi ole viper-koodi uudelleensijoituksin, tämä koodi on vakiodataa eikä sitä tarvitse muokata.
Jos tällä raakakoodilla on lapsia (kuten ensimmäisen vuintin bitti osoittaa), koodin jälkeen tulee vuint, joka laskee ali-raakakoodielementtien määrän.
Lopuksi tallennetaan kaikki ali-raakakoodielementit rekursiivisesti.