ปัญหาที่พบบ่อยและวิธีแก้ไข

เอกสารนี้เป็นรายการบางส่วนของปัญหาที่ไม่ใช่ข้อบกพร่องที่พบบ่อยที่สุดซึ่งคุณอาจพบเมื่อใช้ 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 ที่ไม่ตรงกัน คุณจะหลีกเลี่ยงปัญหาที่เกิดจากสิ่งนี้ได้หากใช้ความระมัดระวังเป็นอย่างมาก แต่ทางที่ดีควรหลีกเลี่ยงปัญหาไปเลย วิธีที่ดีที่สุดในการ หลีกเลี่ยงปัญหานี้คือการหลีกเลี่ยงการมีไลบรารีที่ใช้ร่วมกันหลายรายการในแอป