MicroPython .mpy dosyaları¶
MicroPython, önceden derlenmiş kodu barındıran ve normal bir .py modülü gibi içe aktarılabilen ikili bir kapsayıcı dosya biçimi olan .mpy dosyası kavramını tanımlar. foo.mpy dosyası, import foo ile içe aktarılabilir; yeter ki foo.mpy içe aktarma mekanizması tarafından her zamanki gibi bulunabilsin. Genellikle sys.path içinde listelenen her dizin sırayla aranır. Belirli bir dizin aranırken önce foo.py aranır, bulunamazsa ardından foo.mpy aranır, ikisi de bulunamazsa arama bir sonraki dizinde devam eder. Bu nedenle foo.py, foo.mpy dosyasına göre önceliklidir.
Bu .mpy dosyaları, genellikle mpy-cross programı aracılığıyla Python kaynak dosyalarından (.py dosyaları) üretilen bytecode içerebilir. Bazı mimariler için bir .mpy dosyası, çeşitli yollarla, özellikle de C kaynak kodundan üretilebilen yerel makine kodu da içerebilir.
mpy-cross derleyicisi¶
mpy-cross, bir .py kaynak dosyasını kamera üzerinde içe aktarılmaya hazır bir .mpy ikili kapsayıcıya dönüştüren çapraz derleyicidir. MicroPython kaynak ağacının (kameranın aygıt yazılımını oluşturmak için kullanılan ağacın) bir parçasıdır ve ayrıca tam bir aygıt yazılımı kopyası olmadan ana makine tarafında kullanım için bir pip paketi olarak da yayımlanır:
$ pip install --user mpy-cross
Veya pipx aracılığıyla:
$ pipx install mpy-cross
Kurulduktan sonra, tek bir kaynak dosya üzerinde çalıştırın:
$ mpy-cross foo.py
Bu, geçerli dizinde foo.mpy dosyasını üretir; diğer modüllerin yanına kameranın dosya sistemine kopyalanmaya veya bir ROMFS imajına beslenmeye hazırdır.
En kullanışlı komut satırı seçenekleri:
-o <path>– üretilen.mpyiçin çıktı yolu (varsayılan olarak uzantısı değiştirilmiş giriş dosya adıdır;-o -stdout’a yazar).-O<n>–0ile3arası optimizasyon düzeyi. Varsayılan0değeri assertion’ları ve tam kaynak konumlarını korur;3assertion’ları ve docstring’leri kaldırır veif __debug__bloklarını yeniden yazar. Düzey, çalışma zamanının sunduğu aynımicropython.opt_levelyüzeyini denetler.-march=<arch>–@nativeve@viperile dekore edilmiş fonksiyonlar için hedef yerel mimari. Kaynak bu dekoratörleri kullandığında gereklidir. Değer kameranın MCU sınıfıyla eşleşmelidir:mpy-cross --helpçıktısındaki listeden seçin veya çalışma zamanındasys.implementation._mpyile kameradan okuyun.-s <path>–.mpydosyasının hata ayıklama bilgisine gömülen kaynak yolu dizesi. Diskteki yol, dosyanın geri izlemelerde görünmesi gereken içe aktarma yolundan farklı olduğunda kullanışlıdır.-X emit=bytecode|native|viper– tüm modül için varsayılan yayıcıyı seçer (@native/@viperdekoratörlerine fonksiyon başına bir alternatif).--version– bu ikili dosyanın yaydığı.mpybiçim sürümünü yazdırır. Bu sayı, kameranın çalışma zamanının desteklediği sürümle (aşağıdaki sürüm tablosuna bakın) eşleşmelidir, aksi takdirde içe aktarmaValueError('incompatible .mpy file')hatası verir.
Tüm bayrak listesi için mpy-cross --help komutunu çalıştırın.
pip paketi ayrıca, derleme betiklerinin derleyiciyi elle bir alt süreç çatallamak yerine süreç içinde çalıştırabilmesi için küçük bir Python modül API’si de sunar:
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 ve mpy_cross.mpy_version üç giriş noktasıdır; bir şeyler ters gittiğinde mpy_cross.CrossCompileError derleyicinin stderr çıktısını taşır. Mimari sabitleri (NATIVE_ARCH_ARMV7EMSP, NATIVE_ARCH_ARMV7EMDP vb.), -march bayrağının kabul ettiği dizelerle eşleşir.
.mpy dosyalarının sürümlemesi ve uyumluluğu¶
Belirli bir .mpy dosyası, belirli bir MicroPython sistemiyle uyumlu olabilir veya olmayabilir. Uyumluluk aşağıdakilere dayanır:
.mpy dosyasının sürümü: dosyanın sürümü, onu yükleyen sistemin desteklediği sürümle eşleşmelidir.
.mpy dosyasının alt sürümü: .mpy dosyası yerel makine kodu içeriyorsa, dosyanın alt sürümü onu yükleyen sistemin desteklediği sürümle eşleşmelidir. Aksi takdirde, .mpy dosyasında yerel makine kodu yoksa, yükleme sırasında alt sürüm yok sayılır.
Küçük tamsayı bitleri: .mpy dosyası bir small integer içinde minimum sayıda bit gerektirir ve onu yükleyen sistem en az bu kadar biti desteklemelidir.
Yerel mimari: .mpy dosyası yerel makine kodu içeriyorsa, bu makine kodunun mimarisini belirtir ve onu yükleyen sistem o mimarinin kodunun yürütülmesini desteklemelidir.
Bir MicroPython sistemi .mpy dosyalarını içe aktarmayı destekliyorsa, sys.implementation._mpy alanı mevcut olur ve sürümü (alt 8 bit), özellikleri ve yerel mimariyi kodlayan bir tamsayı döndürür.
İlk dört testten birini geçemeyen bir .mpy dosyasını içe aktarmaya çalışmak ValueError('incompatible .mpy file') hatası verir. Yerel mimari testini geçemeyen (yerel makine kodu içeriyorsa) bir .mpy dosyasını içe aktarmaya çalışmak ValueError('incompatible .mpy arch') hatası verir.
Bir .mpy dosyasını içe aktarma başarısız olursa şunları deneyin:
MicroPython sisteminizin desteklediği .mpy sürümünü ve bayraklarını şunu çalıştırarak belirleyin:
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()
.mpy dosyasının geçerliliğini, dosyanın ilk iki baytını inceleyerek kontrol edin. İlk bayt büyük harf ‘M’ olmalı, ikinci bayt ise yukarıdaki sistem sürümüyle eşleşmesi gereken sürüm numarası olmalıdır. Eşleşmiyorsa .mpy dosyasını yeniden oluşturun.
Sistem .mpy sürümünün, .mpy dosyasını oluşturmak için kullanılan
mpy-crosstarafından yayılan sürümle (mpy-cross --versionile bulunur) eşleşip eşleşmediğini kontrol edin. Eşleşmiyorsa,mpy-cross --versiontarafından bildirilen etikette (veya hash’te) çıkış yapılmış Git deposundanmpy-crossderleyicisini yeniden derleyin.Yukarıdaki kod aracılığıyla veya kullandığınız port için
MPY_CROSS_FLAGSMakefile değişkenini inceleyerek bulunan doğrumpy-crossbayraklarını kullandığınızdan emin olun..mpy dosyasının üçüncü baytında #6 bit ayarlıysa, kodlanmış mimariye özgü bayrak bitleri vuint’inin, dosyayı içe aktardığınız hedefle uyumlu olup olmadığını kontrol edin.
Aşağıdaki tablo, MicroPython sürümü ile .mpy sürümü arasındaki karşılığı gösterir.
MicroPython sürümü |
.mpy sürümü |
|---|---|
v1.23.0 ve üzeri |
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 |
Bütünlük açısından, bir sonraki tablo .mpy sürümünün değiştirildiği ana MicroPython deposunun Git commit’ini gösterir.
.mpy sürüm değişikliği |
Git commit |
|---|---|
6.2’den 6.3’e |
bdbc869f9ea200c0d28b2bc7bfb60acd9d884e1b |
6.1’den 6.2’ye |
6967ff3c581a66f73e9f3d78975f47528db39980 |
6’dan 6.1’e |
d94141e1473aebae0d3c63aeaa8397651ad6fa01 |
5’ten 6’ya |
f2040bfc7ee033e48acef9f289790f3b4e6b74e5 |
4’ten 5’e |
5716c5cf65e9b2cb46c2906f40302401bdd27517 |
3’ten 4’e |
9a5f92ea72754c01cc03e5efcdfe94021120531e |
2’den 3’e |
ff93fd4f50321c6190e1659b19e64fef3045a484 |
1’den 2’ye |
dd11af209d226b7d18d5148b239662e30ed60bad |
0’dan 1’e |
6a11048af1d01c78bdacddadd1b72dc7ba7c6478 |
ilk sürüm 0 |
d8c834c95d506db979ec871417de90b7951edc30 |
.mpy dosyalarının ikili kodlaması¶
MicroPython .mpy dosyaları, kod nesnelerinin (bytecode ve yerel makine kodu) iç içe geçmiş bir hiyerarşide dahili olarak depolandığı ikili bir kapsayıcı biçimidir. Önce dış modülün kodu depolanır, ardından alt öğeleri gelir. Her alt öğenin başka alt öğeleri olabilir; örneğin metotları olan bir sınıf veya lambda ya da comprehension tanımlayan bir fonksiyon durumunda. Dosyaları küçük tutarken yine de geniş bir olası değer aralığı sağlamak için birçok yerde değişken-kodlanmış-işaretsiz-tamsayı (vuint) kavramını kullanır. UTF-8 kodlamasına benzer şekilde, bu kodlama bayt başına 7 bit depolar ve bir veya daha fazla bayt takip ediyorsa 8. bit (MSB) ayarlanır. İşaretsiz tamsayının bitleri vuint içinde LSB biçiminde depolanır.
Bir .mpy dosyasının en üst düzeyi üç bölümden oluşur:
Başlık.
Genel qstr ve sabit tabloları.
Modülün dış kapsamı için ham kod. Bu dış kapsam, .mpy dosyası içe aktarıldığında yürütülür.
Bir .mpy dosyasının içeriğini mpy-tool.py kullanarak inceleyebilirsiniz; örneğin (ana MicroPython deposunun kök dizininden çalıştırılır):
$ ./tools/mpy-tool.py -xd myfile.mpy
Başlık¶
.mpy başlığı şöyledir:
boyut |
alan |
|---|---|
bayt |
değer 0x4d (ASCII ‘M’) |
bayt |
.mpy ana sürüm numarası |
bayt |
özellik bayrakları, yerel mimari, alt sürüm numarası (eski sürümlerde özellik bayraklarıydı) |
bayt |
küçük bir int’teki bit sayısı |
Üçüncü bayt şu şekilde bölünür (önce MSB):
bit |
anlam |
|---|---|
7 |
ayrılmış, 0 olmalı |
6 |
başlığın ardından mimariye özgü bir bayraklar vuint’i gelir |
5..2 |
yerel mimari numarası |
1..0 |
alt sürüm numarası |
Mimariye özgü bayraklar¶
Başlığın özellik bayrakları baytının #6 biti ayarlıysa, başlığın ardından isteğe bağlı mimariye özgü bilgi içeren bir vuint gelir. Bu tamsayının içeriği, dosyanın hangi yerel mimari için tasarlandığına bağlıdır.
Bu şu anda, MPY dosyasının I, M, C ve Zicsr dışında doğru çalışmak için hangi RISC-V işlemci uzantılarına ihtiyaç duyduğunu depolamak için kullanılır. ArmV7’nin farklı türevleri yerel mimari numaralarıyla tanımlanır, ancak bu mekanizmayı yeniden kullanmak RV32 ve RV64 için işleri karmaşıklaştırır.
Herhangi bir özel işlemci uzantısına ihtiyaç duymayan RV32 veya RV64 hedefli MPY dosyalarının bir bayraklar tamsayısı sağlaması gerekmez (başlıkta uygun biti ayarlamanın yanı sıra). RV32 ve RV64 MPY dosyaları için bir bayraklar değerinin bulunmaması, belirli uzantıların gerekmediğini belirtmek için kullanılır ve son çıktı ikili dosyasında bir bayt tasarruf sağlar.
MPY dosyaları oluştururken bu değeri ayarlamak için hem mpy-tool.py hem de mpy-cross içindeki -march-flags komut satırı seçeneğine ve mpy_ld.py içindeki --arch-flags komut satırı seçeneğine de bakın.
Genel qstr ve sabit tabloları¶
Bir .mpy dosyası tek bir qstr tablosu ve tek bir sabit nesne tablosu içerir. Bunlar .mpy dosyasına geneldir ve tüm iç içe geçmiş ham kod nesneleri tarafından başvurulur. qstr tablosu, dahili qstr numarasını (.mpy dosyasına dahili) .mpy dosyasının içe aktarıldığı çalışma zamanının çözümlenmiş qstr numarasıyla eşler. Bu, .mpy dosyasını içinde yürütüldüğü sistemin geri kalanıyla bağlar. Sabit nesne tablosu, .mpy dosyasının ihtiyaç duyduğu tüm sabit nesnelere yapılan başvurularla doldurulur.
boyut |
alan |
|---|---|
vuint |
qstr sayısı |
vuint |
sabit nesne sayısı |
… |
qstr verisi |
… |
kodlanmış sabit nesneler |
Ham kod öğeleri¶
Bir ham kod öğesi, bytecode veya yerel makine kodu olmak üzere kod içerir. İçeriği şöyledir:
boyut |
alan |
|---|---|
vuint |
tür, boyut ve alt ham kod öğelerinin olup olmadığı |
… |
kod (bytecode veya makine kodu) |
vuint |
alt ham kod öğelerinin sayısı (yalnızca sıfır değilse) |
… |
alt ham kod öğeleri |
Bir ham kod öğesindeki ilk vuint, bu öğede depolanan kodun türünü (en düşük anlamlı iki bit), bu ham kodun herhangi bir alt öğesi olup olmadığını (en düşük anlamlı üçüncü bit) ve ardından gelen kodun uzunluğunu (bunun için ayrılacak RAM miktarı) kodlar.
vuint’in ardından kodun kendisi gelir. Kod türü yer değiştirmeli (relocation) viper kodu olmadığı sürece, bu kod sabit veridir ve değiştirilmesi gerekmez.
Bu ham kodun herhangi bir alt öğesi varsa (ilk vuint’teki bir bitle belirtildiği gibi), kodun ardından alt ham kod öğelerinin sayısını sayan bir vuint gelir.
Son olarak, varsa tüm alt ham kod öğeleri özyinelemeli olarak depolanır.