เอกสารนี้เป็นรายการบางส่วนของปัญหาที่ไม่ใช่ข้อบกพร่องที่พบบ่อยที่สุดซึ่งคุณอาจพบเมื่อใช้ NDK พร้อมวิธีแก้ปัญหา (หากมี)
การใช้ _FILE_OFFSET_BITS=64 กับ API ระดับเก่า
ก่อนที่จะมีส่วนหัวแบบรวม NDK ไม่รองรับ _FILE_OFFSET_BITS=64 หากคุณกำหนดค่านี้ไว้เมื่อสร้างแอป ระบบจะละเว้นค่าดังกล่าวโดยไม่มีการแจ้งเตือน ตอนนี้ตัวเลือก _FILE_OFFSET_BITS=64 ได้รับการรองรับในส่วนหัวแบบรวมแล้ว แต่ใน Android เวอร์ชันเก่า มี API off_t เพียงไม่กี่รายการเท่านั้นที่พร้อมใช้งานเป็นตัวแปร off64_t ดังนั้น การใช้ฟีเจอร์นี้กับ API ระดับเก่าจะทำให้มีฟังก์ชันพร้อมใช้งานน้อยลง
เราได้อธิบายปัญหานี้โดยละเอียดในบล็อกโพสต์ r16 และในเอกสารประกอบ ของ Bionic
ปัญหา: บิลด์ขอใช้ API ที่ไม่มีอยู่ใน
minSdkVersion
วิธีแก้ปัญหา: ปิดใช้ _FILE_OFFSET_BITS=64 หรือเพิ่ม minSdkVersion
mmap ที่ไม่ได้ประกาศหรือกำหนดไว้โดยนัย
คุณอาจเห็นข้อผิดพลาดต่อไปนี้ใน C++
error: use of undeclared identifier 'mmap'
หรือข้อผิดพลาดต่อไปนี้ใน C
warning: implicit declaration of function 'mmap' is invalid in C99
การใช้ _FILE_OFFSET_BITS=64 จะสั่งให้ไลบรารี C ใช้ mmap64 แทน
mmap mmap64 ไม่พร้อมใช้งานจนกว่าจะถึง android-21 หากค่า minSdkVersion ต่ำกว่า 21 ไลบรารี C จะไม่มี mmap ที่เข้ากันได้กับ _FILE_OFFSET_BITS=64 ฟังก์ชันจึงไม่พร้อมใช้งาน
minSdkVersion ตั้งค่าสูงกว่าระดับ API ของอุปกรณ์
API ระดับที่คุณสร้างด้วย NDK มีความหมายแตกต่างจาก compileSdkVersion สำหรับ Java มาก ระดับ API ของ NDK คือ ระดับ API ต่ำสุด ที่แอปของคุณรองรับ ใน ndk-build การตั้งค่านี้คือ APP_PLATFORM ส่วนใน CMake คือ -DANDROID_PLATFORM
เนื่องจากโดยปกติแล้วการอ้างอิงฟังก์ชันจะได้รับการแก้ไขเมื่อโหลดไลบรารี ไม่ใช่เมื่อมีการเรียกใช้ฟังก์ชันเป็นครั้งแรก คุณจึงอ้างอิง API ที่ไม่ได้มีอยู่เสมอไปและป้องกันการใช้งานด้วยการตรวจสอบระดับ API ไม่ได้ หากมีการอ้างอิง API เหล่านั้น API จะต้องมีอยู่
ปัญหา: ระดับ API ของ NDK สูงกว่า API ที่อุปกรณ์รองรับ
วิธีแก้ปัญหา: ตั้งค่าระดับ API ของ NDK (APP_PLATFORM) เป็น Android เวอร์ชันต่ำสุด
ที่แอปของคุณรองรับ
| ระบบบิลด์ | การตั้งค่า |
|---|---|
| ndk-build | APP_PLATFORM |
| CMake | ANDROID_PLATFORM |
| externalNativeBuild | android.minSdkVersion |
สำหรับระบบบิลด์อื่นๆ โปรดดู ใช้ NDK กับระบบบิลด์ อื่นๆ
หาไม่พบสัญลักษณ์ __aeabi
ข้อความต่อไปนี้
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
__aeabi_memcpy"
เป็นตัวอย่างหนึ่งของข้อผิดพลาดที่อาจเกิดขึ้น ขณะรันไทม์ ข้อผิดพลาดเหล่านี้จะปรากฏในบันทึกเมื่อคุณพยายามโหลดไลบรารีเนทีฟ สัญลักษณ์อาจเป็น __aeabi_* ใดก็ได้ โดย __aeabi_memcpy และ __aeabi_memclr ดูเหมือนจะเป็นสัญลักษณ์ที่พบบ่อยที่สุด
เราได้บันทึกปัญหานี้ไว้ใน ปัญหาที่ 126
หาไม่พบสัญลักษณ์ rand
สำหรับข้อความในบันทึกข้อผิดพลาดต่อไปนี้
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
rand"
โปรดดูคำตอบโดยละเอียดนี้ใน Stack Overflow answer
การอ้างอิง __atomic_* ที่ไม่ได้กำหนดไว้
ปัญหา: ABI บางรายการต้องใช้ libatomic เพื่อให้การใช้งานบางอย่างสำหรับการดำเนินการแบบ
อะตอมมิก
วิธีแก้ปัญหา: เพิ่ม -latomic เมื่อลิงก์
สำหรับข้อความแสดงข้อผิดพลาดต่อไปนี้
error: undefined reference to '
__atomic_exchange_4'
สัญลักษณ์จริงในที่นี้อาจเป็นสัญลักษณ์ใดก็ได้ที่ขึ้นต้นด้วย __atomic_
RTTI/ข้อยกเว้นไม่ทำงานข้ามขอบเขตของไลบรารี
ปัญหา: ระบบไม่ดักจับข้อยกเว้นเมื่อมีการส่งข้อยกเว้นข้ามขอบเขตของไลบรารีที่ใช้ร่วมกัน
หรือ dynamic_cast ล้มเหลว
วิธีแก้ปัญหา: เพิ่มฟังก์ชันหลักลงในประเภท ฟังก์ชันหลักคือฟังก์ชันเสมือนแบบอินไลน์ที่ไม่ใช่ฟังก์ชันเสมือนแบบเพียวฟังก์ชันแรกสำหรับประเภท ดูตัวอย่างได้ที่ การสนทนาใน ปัญหาที่ 533
ABI ของ C++ ระบุว่าออบเจ็กต์ 2 รายการมีประเภทเดียวกันก็ต่อเมื่อ
ตัวชี้ type_info ของออบเจ็กต์เหมือนกัน ระบบจะดักจับข้อยกเว้นได้ก็ต่อเมื่อ type_info สำหรับการดักจับตรงกับข้อยกเว้นที่ส่ง dynamic_cast ก็ใช้กฎเดียวกัน
เมื่อประเภทไม่มีฟังก์ชันหลัก ระบบจะส่ง typeinfo เป็นสัญลักษณ์แบบอ่อน และระบบจะผสานข้อมูลประเภทที่ตรงกันเมื่อโหลดไลบรารี เมื่อโหลดไลบรารีแบบไดนามิกหลังจากโหลดไฟล์ปฏิบัติการแล้ว (กล่าวคือ ผ่าน dlopen หรือ System.loadLibrary) ตัวโหลดอาจผสานข้อมูลประเภทสำหรับไลบรารีที่โหลดไม่ได้ เมื่อเกิดกรณีนี้ ระบบจะไม่ถือว่าประเภททั้ง 2 เท่ากัน
การใช้ไลบรารีที่สร้างไว้ล่วงหน้าที่ไม่ตรงกัน
การใช้ไลบรารีที่สร้างไว้ล่วงหน้า ซึ่งโดยปกติจะเป็นไลบรารีของบุคคลที่สามในแอปพลิเคชันของคุณต้องใช้ความระมัดระวังเป็นพิเศษ โดยทั่วไป ให้ระวังกฎต่อไปนี้
ระดับ API ต่ำสุดของแอปที่ได้คือค่าสูงสุดของ
minSdkVersionของไลบรารีทั้งหมดของแอปหาก
minSdkVersionของคุณคือ 16 แต่คุณใช้ไลบรารีที่สร้างไว้ล่วงหน้าที่สร้างขึ้นสำหรับ 21 ระดับ API ต่ำสุดของแอปที่ได้คือ 21 หากไม่ปฏิบัติตามกฎนี้ คุณจะเห็นข้อผิดพลาดในเวลาบิลด์หากไลบรารีที่สร้างไว้ล่วงหน้าเป็นแบบคงที่ แต่ข้อผิดพลาดอาจไม่ปรากฏจนกว่าจะถึงเวลาเรียกใช้สำหรับไลบรารีที่ใช้ร่วมกันที่สร้างไว้ล่วงหน้าควรสร้างไลบรารีทั้งหมดด้วย NDK เวอร์ชันเดียวกัน
กฎนี้มีความยืดหยุ่นมากกว่ากฎอื่นๆ เนื่องจากข้อผิดพลาดเกิดขึ้นไม่บ่อยนัก แต่เราไม่รับประกันความเข้ากันได้ระหว่างไลบรารีที่สร้างขึ้นด้วย NDK เวอร์ชันหลักที่แตกต่างกัน ABI ของ C++ ไม่เสถียรและมีการเปลี่ยนแปลงในอดีต
แอปที่มีไลบรารีที่ใช้ร่วมกันหลายรายการต้องใช้ shared STL
เช่นเดียวกับ STL ที่ไม่ตรงกัน คุณสามารถหลีกเลี่ยงปัญหาที่เกิดจากกรณีนี้ได้หากใช้ความระมัดระวังอย่างมาก แต่การหลีกเลี่ยงปัญหาตั้งแต่แรกย่อมดีกว่า วิธีที่ดีที่สุดในการหลีกเลี่ยงปัญหานี้คือการหลีกเลี่ยงการมีไลบรารีที่ใช้ร่วมกันหลายรายการในแอป