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

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

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

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

להכיר ארכיטקטורה שנייה של מעבד (CPU) ו-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 מתאים לארכיטקטורה הראשונה בלבד (32 ביט במכשירים של 32 ביט ו-64 ביט במכשירים של 64 ביט).

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

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

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

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

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

  • 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 לכלול אותן.