2013-07-16 28 views
17

Đã nửa ngày bị lãng phí khi cố gắng xây dựng hai thư viện được chia sẻ, ví dụ: mod1mod2 (trong đó NDK của Android biên dịch thành libmod1.solibmod2.so), từ các nguồn trong thư mục jni và các thư mục con, sau đó yêu cầu mod1 gọi hàm từ mod2. Rất nhiều câu trả lời về cách tạo công việc xây dựng, nhưng sau đó thời gian chạy liên kết động không hoạt động, ứng dụng bị lỗi khi khởi động.Android NDK - làm cho hai thư viện được chia sẻ gốc gọi nhau

Quyết định đăng câu hỏi này và ngay lập tức trả lời câu hỏi, để Q và A cho toàn bộ quá trình cùng nhau và hy vọng một người khác sẽ không lãng phí một ngày nghiên cứu lại.

Trả lời

22

Thủ tục xây dựng đúng là tương đối dễ, vấn đề của tôi là làm libmod1.so phụ thuộc vào libmod2.so gây ra các liên kết không thỏa mãn khi khởi động - mã mod1 không thể tìm thấy thư viện chia sẻ mod2, mặc dù cả hai đều có trong cùng một thư mục aPK thức, dưới libs/armeabi, libs/x86 vv Tuy nhiên, để làm cho câu trả lời hoàn chỉnh của tôi:

  • Đặt C hoặc C++ nguồn và các tập tin tiêu đề dưới thư mục con của JNI dir trong dự án Android của bạn, ví dụ thư mục mod1/và mod2/

  • Theo hướng dẫn NDK, hãy tạo tệp Application.mk, ví dụ: tôi là:

NDK_TOOLCHAIN_VERSION = 4,7
APP_PLATFORM: = android-8
APP_ABI: = armeabi armeabi-v7a x86

  • Tạo Android.mk sau mẫu này:

LOCAL_PATH: = $ (gọi my-dir)
bao gồm $ (CLEAR_VARS)
LOCAL_SHARED_LIBRARIES: = mod2       # điều này làm cho libmod1.so phụ thuộc vào libmod2.so
LOCAL_MODULE: = mod1
LOCAL_SRC_FILES: = mod1 /file1.c
LOCAL_SRC_FILES + = mod1/file2.cpp
...
bao gồm $ (BUILD_SHARED_LIBRARY)       # này thực sự xây dựng libmod1.so

bao gồm $ (CLEAR_VARS)
LOCAL_MODULE: = mod2
LOCAL_SRC_FILES: = mod2/file1.cc
LOCAL_SRC_FILES + = mod2/file2.cc
...
bao gồm $ (BUILD_SHARED_LIBRARY)       # này được xây dựng libmod2 .so

đó là về nó, tất cả được xây dựng mà không phàn nàn với kịch bản ndkbuild. Bạn chỉ cần một trình bao bọc C để gọi một số hàm từ Java. Và đây là vấn đề của tôi. Vì tôi có các hàm có thể gọi từ Java chỉ trong libmod1.như vậy, C lớp wrapper của tôi trong Java giống như:

public class CWrapper { 
    static { 
     System.loadLibrary("mod1"); 
    } 
    public static native int func1(String aParam); 
    ... 
} 

Điều này dường như hoàn toàn hợp lý với tôi - Tôi gọi điện để libmod1.so từ Java, vì vậy tôi đã sử dụng System.loadLibrary ("mod1"), và kể từ libmod1. Vì vậy, biết nó phụ thuộc vào libmod2.so, và cả hai tập tin trong cùng một thư mục, libmod1 sẽ biết làm thế nào để tìm và tải libmod2, phải không? Sai rồi! Nó đã bị treo khi khởi động ứng dụng với "liên kết không hài lòng". Thông báo lỗi chính xác là:

java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library "libmod2.so" needed by "libmod1.so"; caused by load_library(linker.cpp:745): library "libmod2.so" not found 

Tôi đã tìm kiếm ở khắp mọi nơi để thêm một số mã để thêm vào Android.mk để giải quyết vấn đề này vô ích. Cuối cùng là Eureka! Tôi đổi lớp CWrapper của tôi như sau:

public class CWrapper { 
    static { 
     System.loadLibrary("mod2"); // must be first, as mod1 depends on mod2! 
     System.loadLibrary("mod1"); 
    } 
    public static native int func1(String aParam); 
    ... 
} 

và những thứ bắt đầu làm việc như một nét duyên dáng ...

Greg

+1

Từ đây chúng ta có thể kết luận rằng séc của hệ thống động nạp cho và tải phụ thuộc (tiêu chuẩn hành vi), trong khi trình tải Java thì không. – Samveen

+0

Đây là một quan sát tốt, @Samveen. Có lẽ tôi nên kiểm tra lại điều này trong các phiên bản Android mới hơn, để xem liệu họ có cải thiện điều gì gần đây không. – gregko

Các vấn đề liên quan