קובצי manifest של MicroPython¶
תקציר¶
ל-MicroPython יש יכולת המאפשרת ”להקפיא“ קוד Python בתוך הקושחה, כחלופה לטעינת קוד ממערכת הקבצים.
לכך יש את היתרונות הבאים:
הקוד מהודר מראש ל-bytecode, מה שמייתר את הצורך בהידור קוד המקור של Python בזמן הטעינה.
ניתן להריץ את ה-bytecode ישירות מ-ROM (כלומר מזיכרון פלאש (flash)) במקום להעתיק אותו ל-RAM. באופן דומה, גם אובייקטים קבועים (מחרוזות, tuples וכדומה) נטענים מ-ROM. הדבר עשוי להוביל לכך שכמות זיכרון גדולה משמעותית תהיה זמינה ליישום שלך.
בהתקנים שאין בהם מערכת קבצים, זוהי הדרך היחידה לטעון קוד Python.
במהלך הפיתוח בדרך כלל לא מומלץ להקפיא, מכיוון שהדבר יאט משמעותית את מחזור הפיתוח שלך, שכן כל עדכון ידרוש הבזקה מחדש של הקושחה כולה. עם זאת, עדיין יכול להיות שימושי להקפיא באופן סלקטיבי תלויות מסוימות שמשתנות לעיתים רחוקות (כגון ספריות צד שלישי).
הדרך לרשום את קובצי ה-Python שיוקפאו לתוך הקושחה היא באמצעות ”manifest“, שהוא קובץ Python שיפורש על ידי תהליך הבנייה. בדרך כלל תכתוב קובץ manifest כחלק מהגדרת לוח, אך תוכל גם לכתוב קובץ manifest עצמאי ולהשתמש בו עם הגדרת לוח קיימת.
קובצי manifest יכולים להגדיר תלויות בספריות מ-micropython-lib וכן בקובצי Python במערכת הקבצים, וגם בקובצי manifest אחרים.
כתיבת קובצי manifest¶
קובץ manifest הוא קובץ Python המכיל סדרה של קריאות לפונקציות. ראה את הפונקציות הזמינות המוגדרות להלן.
כל נתיב שמשמש בקובצי manifest יכול לכלול את המשתנים הבאים. כולם מתורגמים לנתיבים מוחלטים.
$(MPY_DIR)– נתיב למאגר micropython.$(MPY_LIB_DIR)– נתיב לתת-מודול micropython-lib. עדיף להשתמש ב-require().$(PORT_DIR)– נתיב ל-port הנוכחי (לדוגמהports/stm32)$(BOARD_DIR)– נתיב ללוח הנוכחי (לדוגמהports/stm32/boards/OPENMV4)
קובצי manifest מותאמים אישית לא צריכים להימצא במאגר הראשי של MicroPython. עליך לשמור אותם בבקרת גרסאות יחד עם שאר הפרויקט שלך.
בדרך כלל manifest המשמש להידור קושחה יצטרך לכלול את ה-manifest של ה-port, שעשוי לכלול מודולים מוקפאים הנדרשים לתפקוד הלוח. אם אתה רק רוצה להוסיף מודולים נוספים ללוח קיים, כלול את ה-manifest של הלוח (שבתורו יכלול את ה-manifest של ה-port).
בנייה עם manifest מותאם אישית¶
ניתן לציין את ה-manifest שלך בשורת הפקודה של make באמצעות:
$ make BOARD=MYBOARD FROZEN_MANIFEST=/path/to/my/project/manifest.py
הדבר חל על כל ה-ports, כולל אלה המבוססים על CMake (לדוגמה rp2), שכן עוטף ה-Makefile יעביר זאת לבניית CMake.
הוספת manifest להגדרת לוח¶
אם יש לך הגדרת לוח מותאמת אישית, תוכל לגרום לה לכלול את ה-manifest המותאם אישית שלך באופן אוטומטי. ב-ports המבוססים על make (רוב ה-ports), הגדר את המשתנה FROZEN_MANIFEST בקובץ mpconfigboard.mk שלך.
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
ב-ports המבוססים על CMake (לדוגמה rp2), השתמש במקום זאת ב-mpconfigboard.cmake
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
פונקציות ברמה גבוהה¶
אלו הפונקציות שבהן בדרך כלל תשתמש. הן מוסיפות קוד לקבוצה המהודרת מראש ל-bytecode ומוקפאת בתוך דמות הקושחה:
moduleו-packageמקפיאים את קוד המקור המקומי שלך — קובץ בודד או ספריית package שלמה בהתאמה.requireמקפיא package שפורסם (ואת התלויות שלו) מ-micropython-lib, לפי שם.includeמושך פנימה manifest אחר כך שגם המודולים המוקפאים שבו מתווספים.add_libraryו-metadataהן פונקציות עזר (רישום נתיבי חיפוש נוספים עבורrequire, והכרזה על מטא-נתונים של package).
manifest טיפוסי של קושחה ראשית includeמבצע include ל-manifest של ה-port או הלוח (כך שהמודולים שהלוח זקוק להם נשארים מוקפאים), ולאחר מכן מוסיף את שורות ה-module/package/require שלו.
הערה: ניתן להגדיר את ארגומנט המילת-מפתח opt בפונקציות השונות, והוא שולט ברמת האופטימיזציה שבה משתמש המהדר הצולב. ראה micropython.opt_level().
- add_library(library, library_path, prepend=False)¶
רושם את הנתיב ל-library חיצונית בעלת שם.
השתמש בזה כאשר אתה רוצה ש-
requireיפתור packages מספרייה שאינה micropython-lib — לדוגמה אוסף מנהלי ההתקנים שלך, או checkout של ספריית צד שלישי.הנתיב library_path יחופש אוטומטית בעת שימוש ב-
require. כברירת מחדל הספרייה שנוספה מתווספת לסוף רשימת הספריות לחיפוש. העברTrueכדי להקדים ולהוסיף אותה לתחילת הרשימה.בנוסף, ניתן לבקש במפורש את הספרייה שנוספה באמצעות
require("name", library="library").
- package(package_path, files=None, base_path='.', opt=None)¶
מקפיא package שלם — ספרייה של קובצי
.py(אופציונלית עם תת-packages) — כך שניתן לייבא אותו כ-import <package>. השתמש ב-moduleבמקום זאת עבור קובץ עצמאי בודד.הדבר שקול להעתקת ספריית ”package_path“ להתקן (פרט לכך שכקוד מוקפא).
במקרה הפשוט ביותר, כדי להקפיא package בשם ”foo“ בספרייה הנוכחית:
package("foo")יכלול באופן רקורסיבי את כל קובצי ה-.py ב-foo, ויוקפא כ-
foo/**/*.py.אם ה-package אינו נמצא באותה ספרייה כמו קובץ ה-manifest, השתמש ב-
base_path:package("foo", base_path="path/to/libraries")תוכל להשתמש במשתנים שלעיל, כגון
$(PORT_DIR)ב-base_path.כדי להגביל לקבצים מסוימים ב-package השתמש ב-
files(הערה: הנתיבים צריכים להיות יחסיים ל-package):package("foo", files=["bar/baz.py"]).
- module(module_path, base_path='.', opt=None)¶
מקפיא קובץ
.pyעצמאי בודד כך שניתן לייבא אותו לפי שמו (module("foo.py")גורם ל-import fooלעבוד). השתמש ב-packageעבור ספרייה/package.אם הקובץ נמצא בספרייה הנוכחית:
module("foo.py")אחרת השתמש ב-base_path כדי לאתר את הקובץ:
module("foo.py", base_path="src/drivers")תוכל להשתמש במשתנים שלעיל, כגון
$(PORT_DIR)ב-base_path.
- require(name, library=None)¶
דורש package לפי שם (ואת התלויות שלו) מ-micropython-lib.
כך מורחבות הספרייה הסטנדרטית ומנהלי התקנים מהקהילה מוקפאים פנימה: ה-package בעל השם מאוחזר מתת-המודול micropython-lib ומוקפא יחד עם כל מה שהוא תלוי בו. השתמש ב-
moduleאו ב-packageבמקום זאת כדי להקפיא את קוד המקור שלך במקום package שפורסם.אופציונלית ציין library (מחרוזת) כדי להפנות ל-package מספרייה שנרשמה קודם לכן באמצעות
add_library. אחרת תשמש רשימת נתיבי הספריות.
- include(manifest_path)¶
כלול manifest אחר. כך מורכבים קובצי manifest: manifest מותאם אישית של קושחה צריך לבצע
includeל-manifest של ה-port (או הלוח) כך שהמודולים שהלוח זקוק להם נשארים מוקפאים, ולאחר מכן להוסיף את הרשומות שלו.בדרך כלל manifest המשמש להידור קושחה יצטרך לכלול את ה-manifest של ה-port, שעשוי לכלול מודולים מוקפאים הנדרשים לתפקוד הלוח.
הארגומנט manifest יכול להיות מחרוזת (שם קובץ) או איטרבל של מחרוזות.
נתיבים יחסיים נפתרים ביחס לקובץ ה-manifest הנוכחי.
אם הנתיב מצביע על ספרייה, אזי הוא כולל באופן מרומז את קובץ ה-manifest.py שבתוך אותה ספרייה.
תוכל להשתמש במשתנים שלעיל, כגון
$(PORT_DIR)ב-manifest_path.
- metadata(description=None, version=None, license=None, author=None)¶
מגדיר מטא-נתונים עבור קובץ manifest זה. הדבר שימושי עבור קובצי manifest של packages של micropython-lib.
שדות אלה נצרכים כאשר package מפורסם אל / מותקן מ-micropython-lib באמצעות mip; הם אינם נדרשים ב-manifest של קושחת לוח.
פונקציות ברמה נמוכה¶
פונקציות אלה מתועדות לשם השלמות, אך למעט freeze_as_str ניתן לגשת לכל הפונקציונליות באמצעות הפונקציות ברמה הגבוהה.
פונקציות ה-freeze* נבדלות זו מזו רק ב-אופן שבו הקוד מאוחסן:
freeze_as_mpy/freeze_mpyמאחסנות bytecode מהודר מראש (.mpy) בזיכרון פלאש (flash). הקוד רץ ישירות מהפלאש (flash), משתמש ב-RAM מינימלי, ומיובא במהירות. זה מה ש-module,packageו-requireמשתמשים בו באופן פנימי.freeze_as_strבמקום זאת מקפיאה את קוד המקור של Python, המהודר ל-bytecode בזמן הייבוא (תוך שימוש ב-RAM, ובדרישה למהדר שעל ההתקן). זוהי היכולת האחת שאינה נחשפת על ידי הפונקציות ברמה הגבוהה, ולכן היא היוצא מן הכלל שצוין לעיל.
- freeze(path, script=None, opt=0)¶
הפרימיטיב הבסיסי שעליו נבנות הפונקציות ברמה הגבוהה; העדף את אלה. מקפיא את הקלט שצוין על ידי path, ומזהה אוטומטית את סוגו. סקריפט
.pyיהודר תחילה ל-.mpyואז יוקפא, וקובץ.mpyיוקפא ישירות.path חייב להיות ספרייה, שהיא ספריית הבסיס שממנה מתחיל החיפוש אחר קבצים. בעת ייבוא המודולים המוקפאים המתקבלים, שם המודול יתחיל אחרי path, כלומר path מוחרג משם המודול.
אם path הוא יחסי, הוא נפתר ביחס ל-
manifest.pyהנוכחי.אם script הוא None, כל הקבצים ב-path יוקפאו.
אם script הוא איטרבל אזי
freeze()נקראת על כל הפריטים של האיטרבל (עם אותם path ו-opt שמועברים).אם script הוא מחרוזת אזי הוא מציין את הקובץ או הספרייה להקפאה, ויכול לכלול ספריות נוספות לפני הקובץ או הספרייה האחרונה. הקובץ או הספרייה יחופשו ב-path. אם script הוא ספרייה אזי כל הקבצים באותה ספרייה יוקפאו.
opt היא רמת האופטימיזציה שמועברת ל-mpy-cross בעת הידור
.pyל-.mpy. רמות אלה מתוארות ב-micropython.opt_level().
- freeze_as_str(path)¶
מקפיא את ה-path הנתון ואת כל סקריפטי ה-
.pyשבתוכו כמחרוזת, אשר תהודר בעת הייבוא. השתמש בזה רק כאשר הקוד המוקפא חייב להישאר כקוד מקור של Python; הדבר עולה ב-RAM בזמן הייבוא בהשוואה לגרסאות ה-.mpy.
- freeze_as_mpy(path, script=None, opt=0)¶
מקפיא את הקלט על ידי הידור תחילה של סקריפטי ה-
.pyלקובצי.mpy, ואז הקפאת קובצי ה-.mpyהמתקבלים. זה מה ש-moduleו-packageעושים מאחורי הקלעים. ראהfreeze()לפרטים נוספים על הארגומנטים.
- freeze_mpy(path, script=None, opt=0)¶
מקפיא את הקלט, שחייב להיות קובצי
.mpyשמוקפאים ישירות (ללא שלב הידור). ראהfreeze()לפרטים נוספים על הארגומנטים.
דוגמאות¶
כדי להקפיא קובץ בודד מהספרייה הנוכחית שיהיה זמין כ-import mydriver, השתמש:
module("mydriver.py")
כדי להקפיא ספריית קבצים בתת-ספרייה ”mydriver“ של הספרייה הנוכחית שתהיה זמינה כ-import mydriver, השתמש:
package("mydriver")
כדי להקפיא את ספריית ”hmac“ מ-micropython-lib, השתמש:
require("hmac")
דוגמה מלאה יותר לקובץ manifest.py מותאם אישית (עבור לוח שיש לו manifest ברירת מחדל משלו) היא:
# 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")
אז ניתן להדר את הלוח באמצעות
$ cd ports/stm32
$ make BOARD=MYBOARD FROZEN_MANIFEST=~/src/myproject/manifest.py
שים לב שלרוב הלוחות אין manifest.py משלהם, אלא הם משתמשים ישירות בזה של ה-port, ובמקרה כזה ה-manifest שלך צריך פשוט לבצע include("$(PORT_DIR)/boards/manifest.py") במקום זאת.