Soru Android NDK - birbirini çağıran iki yerel paylaşımlı kütüphane oluştur


Yarım günde iki paylaşılan kütüphane kurmaya çalışıyor. mod1 ve mod2 (hangi Android NDK için derler libmod1.so ve libmod2.so), bir jni klasöründeki ve alt klasörlerdeki kaynaklardan, mod1 mod2'den bir işlevi çağırır. Yapının nasıl çalışılacağına dair çok sayıda cevap var, ancak daha sonra çalışma zamanı dinamik bağlantısı çalışmıyordu, uygulama başlangıçta kilitlendi.

Bu soruyu yayınlamaya ve hemen yanıtlamaya karar verdik, böylece tüm süreçte Q ve A birlikte oldu ve umarım bir başkası tekrar araştırmayı bir gün boşa harcamaz.


17
2017-07-16 22:53


Menşei




Cevaplar:


Doğru inşa prosedürü nispeten kolay oldu, benim sorun libmod2so libmod2.so bağımlı başlangıçta tatminsiz bağlantılara neden oldu - mod1 kodu her ikisi de son APK, aynı klasör içinde mevcut olmasına rağmen mod2 paylaşılan kütüphane bulamadı libs / armeabi, libs / x86 vb. altında, cevabımı tamamlamak için:

  • Android projenizde C veya C ++ kaynaklarınızı ve başlık dosyalarınızı jni dir'in alt dizinleri altına koyun, ör. klasörler mod1 / ve mod2 /

  • NDK talimatları uyarınca Application.mk dosyası oluşturun, ör. benimki:

NDK_TOOLCHAIN_VERSION = 4.7
  APP_PLATFORM: = android-8
  APP_ABI: = armeabi armeabi-v7a x86

  • Bu şablonu takip ederek Android.mk oluşturun:

LOCAL_PATH: = $ (dir-ara)
  $ (CLEAR_VARS) dahil
  LOCAL_SHARED_LIBRARIES: = mod2 # bu libmod1.so libmod2.so'ya bağımlı yapar
  LOCAL_MODULE: = mod1
  LOCAL_SRC_FILES: = mod1 / dosya1.c
  LOCAL_SRC_FILES + = mod1 / dosya2.cpp
  ...
  dahil $ (BUILD_SHARED_LIBRARY) # bu aslında libmod1.so oluşturur

  $ (CLEAR_VARS) dahil
  LOCAL_MODULE: = mod2
  LOCAL_SRC_FILES: = mod2 / dosya1.cc
  LOCAL_SRC_FILES + = mod2 / dosya2.cc
  ...
  dahil $ (BUILD_SHARED_LIBRARY) # bu libmod2.so oluşturur

Bu konuda, tüm ndkbuild komut dosyası ile şikayet etmeden inşa edilir. Java'dan bazı işlevleri çağırmak için sadece bir C sarıcısına ihtiyacınız vardır. Ve işte benim sorunumdu. Java'dan sadece libmod1.so dosyasında callable olan fonksiyonlar olduğu için Java'daki C sarıcı sınıfım şöyle oldu:

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

Bu bana tamamen mantıklı geldi - Java'dan libmod1.so çağırdım, bu yüzden System.loadLibrary ("mod1") kullandım ve libmod1.so libmod2.so'ya bağlı olduğunu ve her iki dosyanın da aynı klasörde olduğunu bildiğinden libmod1 libmod2'yi bulup yükleyeceğini biliyor, değil mi? Yanlış! Uygulama başlatıldığında "tatmin edici bağlantı" ile çöküyordu. Tam hata mesajı şuydu:

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

Ben her yerde bu boşuna çözmek için Android.mk eklemek için biraz daha kod için arıyordum. Sonunda Eureka! CWrapper sınıfımı aşağıdaki gibi değiştirdim:

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);
    ...
}

ve işler bir çekicilik gibi çalışmaya başladı ...

Greg


23
2017-07-16 23:22



Bundan yola çıkarak, Java yükleyicisinin olmadığı durumlarda, sistemin dinamik yükleyicisinin bağımlılıkları (standart davranış) kontrol ettiği ve yüklediği sonucuna varabiliriz. - Samveen
Bu iyi bir gözlem. Belki de son zamanlarda herhangi bir şeyi geliştirip geliştirmediklerini görmek için bunu Android'in yeni sürümlerinde yeniden test etmeliyim. - gregko