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

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

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

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

זיהוי ארכיטקטורת CPU ו-ABI שנייה

BoardConfig.mk כולל את המשתנים הבאים להגדרת ארכיטקטורת ה-CPU השנייה וממשק ה-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.

ב-multilib build, שמות המודולים ב-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 יוצר גרסאות של 32 ביט ו-64 ביט.
  • 32 builds only 32 bit.
  • 64 builds only 64 bit.
  • first builds רק לארכיטקטורה הראשונה (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.

אבל ב-multilib build, צריך להשתמש ב-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 - מציין את נתיב ההתקנה.

קבלת ספריית ביניים לקובצי מקור

ב-multilib build, אם יוצרים קובצי מקור ל-$(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 ביט בגרסה מרובת ספריות.

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

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

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

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

מוודאים שנוצר קובץ ODEX ב-32 ביט וב-64 ביט

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