เอกสารนี้เป็นรายการบางส่วนของปัญหาที่ไม่ใช่ข้อบกพร่องที่พบบ่อยที่สุดซึ่งคุณอาจพบเมื่อใช้ 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++
ข้อผิดพลาด: ใช้ตัวระบุ "mmap" ที่ไม่ได้ประกาศ
หรือข้อผิดพลาดต่อไปนี้ใน C
คำเตือน: การประกาศฟังก์ชัน "mmap" โดยนัยไม่ถูกต้องใน 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 ไม่ได้ หากมีการอ้างอิงถึง จะต้องระบุไว้
ปัญหา: ระดับ NDK API สูงกว่า API ที่อุปกรณ์รองรับ
วิธีแก้ปัญหา: ตั้งค่าระดับ NDK API (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 โดยละเอียดนี้
การอ้างอิงถึง __atomic_*
ที่ไม่ได้กำหนด
ปัญหา: ABI บางรายการต้องมี libatomic
เพื่อให้การใช้งานบางอย่างสำหรับ
การดำเนินการแบบอะตอม
วิธีแก้ไข: เพิ่ม -latomic
เมื่อลิงก์
สำหรับข้อความแสดงข้อผิดพลาดต่อไปนี้
ข้อผิดพลาด: ไม่ได้กำหนดการอ้างอิงถึง "
__atomic_exchange_4
"
สัญลักษณ์จริงที่นี่อาจเป็นอะไรก็ได้ที่ขึ้นต้นด้วย __atomic_
RTTI/ข้อยกเว้นไม่ทำงานข้ามขอบเขตของไลบรารี
ปัญหา: ระบบไม่ตรวจพบข้อยกเว้นเมื่อข้อยกเว้นเกิดขึ้นในขอบเขตของไลบรารีที่ใช้ร่วมกัน
หรือ dynamic_cast
ล้มเหลว
วิธีแก้ปัญหา: เพิ่มฟังก์ชันคีย์ลงในประเภท ฟังก์ชันคีย์คือ ฟังก์ชันเสมือนที่ไม่ใช่ฟังก์ชันบริสุทธิ์และอยู่นอกบรรทัดแรกสำหรับประเภทหนึ่งๆ ดูตัวอย่างได้ที่การสนทนาในปัญหา 533
C++ ABI ระบุว่าออบเจ็กต์ 2 รายการมีประเภทเดียวกันก็ต่อเมื่อพอยน์เตอร์ type_info
ของออบเจ็กต์ทั้ง 2 รายการเหมือนกัน ระบบจะตรวจพบข้อยกเว้นได้ก็ต่อเมื่อtype_info
ของ catch ตรงกับข้อยกเว้นที่ส่งมาเท่านั้น กฎเดียวกันนี้
ใช้กับ dynamic_cast
เมื่อประเภทไม่มีฟังก์ชันคีย์ ระบบจะปล่อย typeinfo
เป็นสัญลักษณ์ที่อ่อนแอ
และผสานข้อมูลประเภทที่ตรงกันเมื่อโหลดไลบรารี เมื่อโหลดไลบรารีแบบไดนามิกหลังจากโหลดไฟล์ที่เรียกใช้งานได้แล้ว (กล่าวคือ ผ่าน dlopen
หรือ System.loadLibrary
) ตัวโหลดอาจผสานข้อมูลประเภทสำหรับไลบรารีที่โหลดไม่ได้ เมื่อเกิดกรณีนี้ขึ้น ระบบจะไม่ถือว่า
ข้อมูลทั้ง 2 ประเภทเท่ากัน
การใช้ไลบรารีที่สร้างไว้ล่วงหน้าซึ่งไม่ตรงกัน
การใช้ไลบรารีที่สร้างไว้ล่วงหน้า ซึ่งโดยปกติแล้วจะเป็นไลบรารีของบุคคลที่สามในแอปพลิเคชันของคุณต้องใช้ความระมัดระวังเป็นพิเศษ โดยทั่วไปแล้ว โปรด ทราบกฎต่อไปนี้
ระดับ API ขั้นต่ำของแอปที่ได้คือระดับสูงสุดของ
minSdkVersion
ของไลบรารีทั้งหมดของแอปหาก
minSdkVersion
คือ 16 แต่คุณใช้ไลบรารีที่สร้างไว้ล่วงหน้าซึ่งสร้างขึ้นสำหรับ 21 ระดับ API ขั้นต่ำของแอปที่ได้จะเป็น 21 หากไม่ปฏิบัติตามข้อกำหนดนี้ คุณจะเห็นข้อผิดพลาดในเวลาที่สร้างหากไลบรารีที่สร้างไว้ล่วงหน้าเป็นแบบคงที่ แต่ข้อผิดพลาดอาจไม่ปรากฏจนกว่าจะถึงรันไทม์สำหรับไลบรารีที่ใช้ร่วมกันที่สร้างไว้ล่วงหน้าควรสร้างไลบรารีทั้งหมดด้วย NDK เวอร์ชันเดียวกัน
กฎนี้มีความยืดหยุ่นมากกว่ากฎอื่นๆ เนื่องจากไม่ค่อยเกิดการหยุดทำงาน แต่เราไม่รับประกัน ความเข้ากันได้ระหว่างไลบรารีที่สร้างขึ้นด้วย NDK เวอร์ชันหลักที่แตกต่างกัน ABI ของ C++ ไม่เสถียรและมีการเปลี่ยนแปลงในอดีต
แอปที่มีไลบรารีที่ใช้ร่วมกันหลายรายการต้องใช้ STL ที่ใช้ร่วมกัน
เช่นเดียวกับ STL ที่ไม่ตรงกัน คุณจะหลีกเลี่ยงปัญหาที่เกิดจากสิ่งนี้ได้หากใช้ความระมัดระวังเป็นอย่างมาก แต่ทางที่ดีควรหลีกเลี่ยงปัญหาไปเลย วิธีที่ดีที่สุดในการ หลีกเลี่ยงปัญหานี้คือการหลีกเลี่ยงการมีไลบรารีที่ใช้ร่วมกันหลายรายการในแอป