פיתוח גרסאות build לארכיטקטורות של 32 ו-64 ביט

מערכת ה-build תומכת ביצירת קבצים בינאריים לשתי ארכיטקטורות של מעבדים (CPU) ייעודיים, 32 ביט ו-64 ביט, באותו build. הגרסה הזו עם שני היעדים נקראת build של multilib.

עבור ספריות סטטיות מובנות וספריות משותפות, מערכת ה-build מגדירה כללים ליצירת קובצי בינארי בשתי הארכיטקטורות. הגדרות המוצר (PRODUCT_PACKAGES) יחד עם תרשים יחסי התלות קובעים אילו קובצי בינארי ייוצרו ויוטמעו בקובץ האימג' של המערכת.

לגבי קובצי הפעלה ואפליקציות, מערכת ה-build יוצרת רק את הגרסה ל-64 ביט כברירת מחדל, אבל אפשר לשנות את ההגדרה הזו באמצעות משתנה BoardConfig.mk גלובלי או משתנה ברמת המודול.

זיהוי ארכיטקטורה ו-ABI של מעבד שני

BoardConfig.mk כולל את המשתנים הבאים להגדרת הארכיטקטורה השנייה של המעבד ואת ממשק ה-Application Binary Interface ‏ (ABI):

  • TARGET_2ND_ARCH
  • TARGET_2ND_ARCH_VARIANT
  • TARGET_2ND_CPU_VARIANT
  • TARGET_2ND_CPU_ABI
  • TARGET_2ND_CPU_ABI2

דוגמה לקובץ makefile שמשתמש במשתנים האלה מופיעה בקובץ build/make/target/board/generic_arm64/BoardConfig.mk.

ב-build של multilib, שמות המודולים ב-PRODUCT_PACKAGES מכסים גם את הקבצים הבינאריים של 32 סיביות וגם את הקבצים הבינאריים של 64 סיביות, כל עוד הם מוגדרים על ידי מערכת ה-build. בספריות שכלולות ביחסי תלות, ספרייה של 32 או 64 סיביות מותקנת רק אם היא נדרשת על ידי ספרייה או קובץ הפעלה אחרים של 32 או 64 סיביות.

עם זאת, שמות המודולים בשורת הפקודה make מכסים רק את הגרסה של 64 ביט. לדוגמה, אחרי שמריצים את lunch aosp_arm64-eng, הפקודה make libc יוצרת רק את libc של 64 ביט. כדי ליצור את libc של 32 ביט, מריצים את make libc_32.

הגדרת ארכיטקטורת המודול בקובץ Android.mk

אפשר להשתמש במשתנה LOCAL_MULTILIB כדי להגדיר את ה-build ל-32 ביט ול-64 ביט ולשנות את ברירת המחדל של המשתנה הגלובלי TARGET_PREFER_32_BIT.

כדי לשנות את TARGET_PREFER_32_BIT, מגדירים את LOCAL_MULTILIB לאחת מהאפשרויות הבאות:

  • both יוצר גרסאות build ב-32 ביט וב-64 ביט.
  • 32 יוצר רק 32 ביט.
  • 64 יוצר רק גרסת build של 64 ביט.
  • first יוצר גרסאות build רק לארכיטקטורה הראשונה (32 ביט במכשירים של 32 ביט ו-64 ביט במכשירים של 64 ביט).

כברירת מחדל, הערך של LOCAL_MULTILIB לא מוגדר, ומערכת ה-build מחליטה איזו ארכיטקטורה לפתח על סמך סוג המודול ומשתני LOCAL_* אחרים, כמו LOCAL_MODULE_TARGET_ARCH ו-LOCAL_32_BIT_ONLY.

אם רוצים לפתח את המודול לארכיטקטורות ספציפיות, צריך להשתמש במשתנים הבאים:

  • LOCAL_MODULE_TARGET_ARCH – מגדירים את המשתנה הזה לרשימה של ארכיטקטורות, למשל arm x86 arm64. אם הארכיטקטורה שנוצרת נמצאת ברשימה הזו, המערכת לכלול את המודול הנוכחי.

  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH – המשתנה הזה הוא ההיפך מ-LOCAL_MODULE_TARGET_ARCH. אם הארכיטקטורה שנוצרת היא not ברשימה הזו, המערכת תיצור את המודול הנוכחי.

יש וריאציות קלות לשני המשתנים האלה:

  • LOCAL_MODULE_TARGET_ARCH_WARN
  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH_WARN

מערכת ה-build תזהיר אם המודול הנוכחי ידלג בגלל הארכיטקטורות שמפורטות.

כדי להגדיר דגלי build לארכיטקטורה מסוימת, משתמשים במשתני LOCAL_* ספציפיים לארכיטקטורה, כאשר * הוא סיומת ספציפית לארכיטקטורה. לדוגמה:

  • LOCAL_SRC_FILES_arm, LOCAL_SRC_FILES_x86,
  • LOCAL_CFLAGS_arm, LOCAL_CFLAGS_arm64,
  • LOCAL_LDFLAGS_arm, LOCAL_LDFLAGS_arm64,

המשתנים האלה חלים רק אם מתבצע פיתוח של קובץ בינארי לארכיטקטורה הזו.

לפעמים קל יותר להגדיר דגלים על סמך העובדה שהקובץ הבינארי נוצר ל-32 ביט או ל-64 ביט. משתמשים במשתנה LOCAL_* עם סיומת _32 או _64, לדוגמה:

  • LOCAL_SRC_FILES_32, LOCAL_SRC_FILES_64,
  • LOCAL_CFLAGS_32, LOCAL_CFLAGS_64,
  • LOCAL_LDFLAGS_32, LOCAL_LDFLAGS_64,

הגדרת נתיב ההתקנה של הספרייה

לגרסה ללא multilib, אפשר להשתמש ב-LOCAL_MODULE_PATH כדי להתקין ספרייה במיקום אחר מלבד מיקום ברירת המחדל. לדוגמה, LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw.

עם זאת, ב-build של multilib, צריך להשתמש ב-LOCAL_MODULE_RELATIVE_PATH במקום:

LOCAL_MODULE_RELATIVE_PATH := hw

בפורמט הזה, גם הספריות של 64 ביט וגם הספריות של 32 ביט מותקנות במיקום הנכון.

אם אתם יוצרים קובץ הפעלה גם ב-32 ביט וגם ב-64 ביט, תוכלו להשתמש באחד מהמשתנים הבאים כדי להבדיל בין נתיב ההתקנה:

  • LOCAL_MODULE_STEM_32, LOCAL_MODULE_STEM_64 – מציין את שם הקובץ שמותקן.
  • LOCAL_MODULE_PATH_32, LOCAL_MODULE_PATH_64 – מציין את נתיב ההתקנה.

אחזור של ספרייה ביניים לקובצי המקור

ב-build של multilib, אם יוצרים קובצי מקור ל-$(local-intermediates-dir) (או ל-$(intermediates-dir-for) עם משתנים מפורשים), המערכת לא פועלת בצורה מהימנה. הסיבה לכך היא שהמקורות שנוצרו בשלב הביניים נדרשים גם ל-build של 32 סיביות וגם ל-build של 64 סיביות, אבל $(local-intermediates-dir) מפנה רק לאחד משני הספריות הבינוניות.

מערכת ה-build מספקת ספרייה ביניים ייעודית שתומכת ב-multilib ליצירת מקורות. כדי לאחזר את הנתיב של הספרייה הביניים, משתמשים במאקרו $(local-generated-sources-dir) או $(generated-sources-dir-for). השימושים במאקרואים האלה דומים ל-$(local-intermediates-dir) ול-$(intermediates-dir-for).

אם קובץ מקור נוצר בתיקייה הייעודית הזו ונאסף על ידי LOCAL_GENERATED_SOURCES, הוא נוצר גם ל-32 ביט וגם ל-64 ביט ב-build של multilib.

ציון ארכיטקטורת המערכת של יעדים בינאריים מוכנים מראש

ב-build של multilib, אי אפשר להשתמש ב-TARGET_ARCH או ב-TARGET_ARCH בשילוב עם TARGET_2ND_ARCH כדי לציין את ארכיטקטורת המערכת של יעדי הבינארי שנוצרו מראש. במקום זאת, צריך להשתמש במשתני LOCAL_*LOCAL_MODULE_TARGET_ARCH או LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH.

בעזרת המשתנים האלה, מערכת ה-build יכולה לבחור את קובץ ה-binary המבוסס מראש של 32 ביט התואם, גם אם היא פועלת על build של multilib ב-64 ביט.

כדי להשתמש בארכיטקטורה שנבחרה כדי לחשב את נתיב המקור של הקובץ הבינארי שנוצר מראש, צריך להפעיל את הפונקציה $(get-prebuilt-src-arch).

מוודאים שייווצרו קובצי ODEX ב-32 סיביות וב-64 סיביות

במכשירים של 64 ביט, Google יוצרת כברירת מחדל קובצי ODEX של 32 ביט ושל 64 ביט לתמונת האתחול ולספריות Java. כברירת מחדל, Google יוצרת קובצי ODEX רק לארכיטקטורה הראשית של 64 סיביות בחבילות APK. אם אפליקציה מופעלת גם בתהליכים של 32 ביט וגם בתהליכים של 64 ביט, צריך להשתמש ב-LOCAL_MULTILIB := both כדי לוודא שנוצרים גם קובצי ODEX של 32 ביט וגם קובצי ODEX של 64 ביט. אם יש באפליקציה ספריות JNI של 32 ביט או 64 ביט, הדגל הזה גם מורה למערכת ה-build לכלול אותן.