NDK תומך במספר ספריות זמן ריצה של C++. במסמך הזה אנחנו מספקים מידע על הספריות האלה, היתרונות שלהן ואיך להשתמש בהן.
ספריות זמן ריצה של C++
טבלה 1. זמני ריצה ותכונות של NDK++
שם | תכונות |
---|---|
libc++ | תמיכת C++ מודרנית. |
system | new וגם delete (הוצא משימוש ב-r18.) |
ללא | ללא כותרות, מוגבל C++. |
אפשר להשתמש ב-libc++ כספרייה סטטית וגם כספרייה משותפת.
libc++
libc++ של LLVM הוא תקן C++ שבה נמצאת מערכת ההפעלה Android OS מאז Lollipop, והחל מ-NDK r18 הוא ה-STL היחיד שזמין ב-NDK.
CMake משמש כברירת מחדל לגרסה של C++ שמוגדרת כברירת מחדל (כרגע C++14),
לכן צריך להגדיר את CMAKE_CXX_STANDARD
הרגיל לערך המתאים
בקובץ CMakeLists.txt
כדי להשתמש בתכונות של C++17 ואילך. לצפייה ב-CMake
מסמכי התיעוד של CMAKE_CXX_STANDARD
אפשר לקבל פרטים נוספים.
ndk-build משאיר גם את ההחלטה ל-clang כברירת מחדל, לכן ndk-build
עליהם להשתמש בפונקציה APP_CPPFLAGS
כדי להוסיף את -std=c++17
או מה שהם רוצים.
הספרייה המשותפת של libc++ היא libc++_shared.so
, והספרייה הסטטית
הספרייה היא libc++_static.a
. במקרים אופייניים, מערכת ה-build תטפל
באמצעות ספריות אלה ואריזות אותן בהתאם לצורך עבור המשתמש. למקרים לא אופייניים
או במהלך הטמעה של מערכת build משלכם, עיינו בתחזוקה של מתחזקים של מערכות Build.
המדריך או המדריך לשימוש במערכות build אחרות.
פרויקט LLVM נמצא ברישיון Apache גרסה 2.0, עם חריגים ל-LLVM. לקבלת מידע נוסף מידע נוסף, ראו קובץ הרישיון.
מערכת
זמן הריצה של המערכת מתייחס ל-/system/lib/libstdc++.so
. אין להשתמש בספרייה הזו
צריך להתבלבל עם libstdc++ של GNU עם כל התכונות. ב-Android, libstdc++ פשוט
new
וגם delete
כדי להשתמש בכל התכונות הרגילות של C++ אפשר להשתמש ב-libc++.
זמן הריצה של המערכת C++ תומך בממשק ה-ABI הבסיסי של C++ זמן ריצה.
בעיקרון, הספרייה הזו מספקת את new
ואת delete
. בניגוד למודל אחר
הזמינות ב-NDK, אין תמיכה בטיפול חריג או
RTTI.
אין תמיכה רגילה בספרייה מלבד wrappers של C++ עבור C
כותרות של ספריות כמו <cstdio>
. אם רוצים להשתמש ב-STL, צריך להשתמש באחד
האפשרויות האחרות שמופיעות בדף הזה.
ללא
אפשר גם לא להשתמש ב-STL. אין קישור או רישוי בדרישות האלה. אין כותרות סטנדרטיות של C++ זמינות.
בחירת סביבת זמן ריצה של C++
CMake
ברירת המחדל ל-CMake היא c++_static
.
אפשר לציין את c++_shared
, c++_static
, none
או system
באמצעות
משתנה ANDROID_STL
בקובץ build.gradle
ברמת המודול. למידע נוסף,
עיין בתיעוד עבור ANDROID_STL ב-
CMake.
ndk-build
ברירת המחדל ל-ndk-build היא none
.
אפשר לציין את c++_shared
, c++_static
, none
או system
באמצעות
משתנה APP_STL
בקובץ Application.mk. לדוגמה:
APP_STL := c++_shared
ndk-build מאפשר לבחור סביבת זמן ריצה אחת בלבד לאפליקציה, ואפשר לעשות זאת רק Application.mk
שימוש ישיר ב-clang
אם אתם משתמשים ב-clang ישירות במערכת ה-build שלכם, clang++ ישתמש
c++_shared
כברירת מחדל. כדי להשתמש בווריאנט הסטטי, צריך להוסיף את -static-libstdc++
אל
הדגלים של המנגנון לקישור חשוב לשים לב שלמרות שהאפשרות משתמשת בשם 'libstdc++ ' עבור
מסיבות היסטוריות, הדבר נכון גם עבור libc++.
שיקולים חשובים
זמני ריצה סטטיים
אם כל הקוד המקורי של האפליקציה נמצא בקובץ משותף אחד אנחנו ממליצים להשתמש בסביבת זמן הריצה הסטטית. זה מאפשר ל-linker להטביע ולהסיר כמה שיותר קוד שאינו בשימוש, והתוצאה שמתקבלת היא וביישום קטן ככל האפשר. הוא גם מונע שימוש ב-PackageManager ובדינמית באגים מקושרים בגרסאות ישנות של Android שגורמים לטיפול בכמה משחקים משותפים ספריות קשות יותר ומסוגלות לשגיאות.
עם זאת, ב-C++ לא בטוח להגדיר יותר מעותק אחד של אותו בפונקציה אחת או באובייקט בתוכנית אחת. זה היבט אחד כלל הגדרה אחת קיים בתקן C++.
כשמשתמשים בסביבת זמן ריצה סטטית (ובספריות סטטיות באופן כללי), קל מאוד להפר בטעות את הכלל הזה. לדוגמה, האפליקציה הבאה מבטלת את כלל:
# Application.mk
APP_STL := c++_static
# Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.cpp
LOCAL_SHARED_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
במצב כזה, ה-STL, כולל נתונים גלובליים ונתונים סטטיים, יהיו בשתי הספריות. ההתנהגות של האפליקציה בסביבת זמן הריצה היא ולכן קריסות בפועל הן נפוצות מאוד. בעיות אפשריות אחרות כוללים:
- זיכרון מוקצה בספרייה אחת ומשוחרר בספרייה השנייה, מה שגורם לזיכרון דליפה או פגיעה בערימה.
- חריגות שהועלו ב
libfoo.so
שלא נלמדות בlibbar.so
, וגורמות ל לקרוס. - תהליך אגירת הנתונים של
std::cout
לא פועל כמו שצריך.
מעבר לבעיות ההתנהגותיות המעורבות, קישור של סביבת זמן הריצה הסטטית יש עותקים כפולים של הקוד בכל ספרייה משותפת, דבר שיגדיל את את האפליקציה שלך.
באופן כללי, אפשר להשתמש בווריאנט סטטי של סביבת זמן הריצה של C++ רק אם יש ורק ספרייה משותפת אחת באפליקציה.
זמני ריצה משותפים
אם האפליקציה שלך כוללת מספר ספריות משותפות, עליך להשתמש
libc++_shared.so
ב-Android, הקישור libc++ שמשמש את NDK הוא לא אותו חלק
של מערכת ההפעלה. כך תהיה למשתמשי NDK גישה לתכונות ולבאג הכי חדשים של libc++
שצריך לתקן גם כשמטרגטים גרסאות ישנות של Android. ההבדל הוא שאם
להשתמש ב-libc++_shared.so
, חובה לכלול אותו באפליקציה. אם אתם בונים
ב-Gradle, זה מטופל באופן אוטומטי.
בגרסאות ישנות של Android היו באגים ב-PackageManager וב-ה-Linker הדינמי
שגרמה להתקנה, לעדכון ולטעינה של ספריות נייטיב
אמינה. באופן ספציפי, אם האפליקציה מטרגטת גרסת Android מוקדם יותר
מאשר ב-Android 4.3 (Android API ברמה 18), ומשתמשים ב-libc++_shared.so
,
חייבים לטעון את הספרייה המשותפת לפני כל ספרייה אחרת שתלויה בה.
פרויקט ReLinker מציע פתרונות אפשריים לכל הבעיות הידועות בטעינה של ספריות נייטיב, ובדרך כלל היא דרך טובה יותר מאשר כתיבת פתרונות משלכם.
STL אחד לכל אפליקציה
בעבר, NDK תמך ב-GNU libstdc++ ו-STLport בנוסף ל-libc++. אם האפליקציה מסתמכת על ספריות מוכנות מראש שפותחו על NDK שונה מזה ששימש לפיתוח האפליקציה, צריך לוודא שהוא עושה זאת באופן תואם.
אפליקציה לא יכולה להשתמש ביותר מסביבת זמן ריצה אחת של C++ אחת. רשימות ה-STL השונות
לא תואמים זה לזה. לדוגמה, הפריסה של std::string
ב-libc++ לא זהה ל-gnustl. קוד שנכתב ב-STL אחד
הם לא יכולים להשתמש באובייקטים שנכתבו נגד אחר. זו רק דוגמה אחת.
יש הרבה אי התאמות.
כלל זה חל גם מעבר לקוד. כל יחסי התלות צריכים להשתמש STL שבחרת. הסתמכות על צד שלישי במקור סגור של התלות שמשתמשת ב-STL ולא מספקת ספרייה לכל STL, יש בחירה ב-STL. עליכם להשתמש באותו STL כמו תלויה.
ייתכן שתסתמך על שתי ספריות שאינן תואמות זו לזו. לחשבון במצב הזה הפתרונות היחידים הם לשחרר את אחד מיחסי התלות או לשאול לספק ספרייה שנבנתה כנגד ה-STL האחר.
חריגים של C++
חריגים ב-C++ נתמכים על ידי libc++, אבל הם מושבתים כברירת מחדל ב- ndk-build. הסיבה לכך היא שבעבר חריגים מ-C++ לא היו זמינים NDK. ל-CMake ולצרות כלים עצמאיים יש חריגים מ-C++ שמופעלים כברירת מחדל.
כדי להפעיל חריגים בכל האפליקציה ב-ndk-build, צריך להוסיף את את השורה הבאה לקובץ Application.mk:
APP_CPPFLAGS := -fexceptions
כדי להפעיל חריגים למודול ndk-build יחיד, מוסיפים את השורה הבאה ל- למודול הנתון ב-Android.mk שלו:
LOCAL_CPP_FEATURES := exceptions
לחלופין, אפשר להשתמש ב:
LOCAL_CPPFLAGS := -fexceptions
RTTI
בדומה לחריגים, RTTI נתמך על ידי libc++ אבל הוא מושבת כברירת מחדל ב- ndk-build. RTTI מופעלת כברירת מחדל ב-CMake ובצרוי כלים עצמאיים.
כדי להפעיל RTTI בכל האפליקציה ב-ndk-build, צריך להוסיף את הפרטים הבאים שורה לקובץ Application.mk:
APP_CPPFLAGS := -frtti
כדי להפעיל RTTI במודול ndk-build יחיד, צריך להוסיף את השורה הבאה למודול נתון ב-Android.mk שלו:
LOCAL_CPP_FEATURES := rtti
לחלופין, אפשר להשתמש ב:
LOCAL_CPPFLAGS := -frtti