Android CMake utilise la bibliothèque de pré-compilation .a

Je suis totalement nouveau à CMake et à l’utilisation de NDK en commun. J’ai imaginé écrire mon interface JNI et utiliser 2 méthodes qui font partie d’une bibliothèque C. J’ai compilé cette bibliothèque en tant que bibliothèque statique et j’ai obtenu le fichier .a. Maintenant, je suis un peu perdu car je ne comprends pas comment dire à Android Studio d’utiliser cette bibliothèque pour trouver les fonctions appelées.

Ceci est mon CMakeLists.txt actuel qui se trouve dans le dossier du module “app”.

cmake_minimum_required(VERSION 3.4.1) add_library(my-lib SHARED src/main/cpp/my-lib.cpp ) target_link_libraries(my-lib z crypto) target_link_libraries(my-lib ${CMAKE_CURRENT_SOURCE_DIR}/../libs/libmine.a) 

Lors de la compilation, je reçois l’avertissement qu’aucune référence aux fonctions appelées ne peut être trouvée. Mon fichier CMakeLists.txt est-il correct et comment puis-je inclure le fichier .h pour les fonctions? Merci d’avance pour votre aide!

Je ne comprends pas comment dire à Android Studio d’utiliser cette bibliothèque pour trouver les fonctions appelées

Pour utiliser vos libmy-lib.so natives, par exemple, libmy-lib.so , vous devez charger cette libmy-lib.so partagée dans votre partie java, comme ci-dessous.

 static { System.loadLibrary("my-lib"); } 

Mon CMakeLists.txt est-il correct?

Oui, c’est correct, mais pas vraiment parfait.

et comment puis-je inclure le fichier .h pour les fonctions

Afin de vous faciliter la tâche en ajoutant le fichier d’en-tête inclus, vous devez configurer un peu CMakelists.txt . Par exemple, vous pouvez avoir une structure de répertoires comme ci-dessous, si vous ne disposez que de app/src/main/cpp , vous pouvez simplement supprimer ces répertoires et configurations non liés.

 app ├── CMakeLists.txt └── src ├── foo │ ├── CMakeLists.txt │ ├── foo.cpp │ └── foo.h ├── main │ └── cpp │ ├── CMakeLists.txt │ └── my-lib.cpp └── test ├── CMakeLists.txt └── google_test_classXXX.cpp 

Ensuite, vous devez configurer votre app/CMakelists.txt comme app/CMakelists.txt ci-dessous.

 # set the root directory as ${CMAKE_CURRENT_SOURCE_DIR} which is a # CMAKE build-in function to return the current dir where your CMakeLists.txt is. # Specifically, it is "/App/" set(APP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # set your 3 other root dirs, ie foo, main and test under app/src. set(APP_ROOT_SRC_DIR ${APP_ROOT_DIR}/src) set(APP_ROOT_FOO_DIR ${APP_ROOT_SRC_DIR}/foo) set(APP_ROOT_MAIN_DIR ${APP_ROOT_SRC_DIR}/main) set(APP_ROOT_TEST_DIR ${APP_ROOT_SRC_DIR}/test) # set your include paths into "SHARED_INCLUDES" variable so that you can quote your header file without adding its relative paths. set(SHARED_INCLUDES ${APP_ROOT_FOO_DIR} # ${APP_ROOT_FOO_DIR}/ ${APP_ROOT_MAIN_DIR} ${APP_ROOT_MAIN_DIR}/cpp # ${APP_ROOT_MAIN_DIR}/ ${APP_ROOT_TEST_DIR} # ${APP_ROOT_TEST_DIR}/ ) # This function will have effect to all the downstream cmakelist files. include_directories(${SHARED_INCLUDES}) add_library(my-lib SHARED src/main/cpp/my-lib.cpp ) target_link_libraries(my-lib z crypto) target_link_libraries(my-lib ${CMAKE_CURRENT_SOURCE_DIR}/../libs/libmine.a) # remember to include downstream cmakelist files for foo, main and test. add_subdirectory(${APP_ROOT_FOO_DIR} bin-dir) add_subdirectory(${APP_ROOT_MAIN_DIR} bin-dir) add_subdirectory(${APP_ROOT_TEST_DIR} bin-dir) 

—-Édité—-

Pour savoir comment lier les bibliothèques pré-construites .a.

 # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries(my-lib -Wl,--whole-archive ${CMAKE_CURRENT_SOURCE_DIR}/../libs/libmine.a -Wl,--no-whole-archive) 

—- Édité pour répondre à vos trois questions —-

Qu’est-ce qui fait partie du fichier CMakeLists.txt dans le répertoire cpp? Faut-il que ce soit dans le répertoire cpp ou dans le répertoire principal?

Théoriquement, vous pouvez n’avoir qu’un seul CMakelists.txt pour tous vos CMakelists.txt de code source et d’en-tête, mais une fois que votre projet évoluera à très grande échelle, ce CMakelists.txt tout-en-un deviendra assez compliqué, illisible et non maintenable. Habituellement, chaque module cmake doit avoir son propre fichier CMakeLists.txt afin qu’il soit modulaire et plus facile à gérer. Par exemple, cpp dir a un CMakeLists.txt pour gérer tous ses sous-répertoires, le cas échéant, ainsi main et test “module”.

Et comment puis-je inclure un fichier .h de mon .a lib – #include ne fonctionne pas.

Comme je l’ai mentionné ci-dessus, vous devez configurer SHARED_INCLUDES pour append vos chemins d’access relatifs aux en-têtes ( .h ) de votre .a , de sorte que vous puissiez simplement utiliser #include pour l’inclusion d’en-tête.

 set(SHARED_INCLUDES ${APP_ROOT_FOO_DIR} # ${APP_ROOT_FOO_DIR}/ ${APP_ROOT_MAIN_DIR} ${APP_ROOT_MAIN_DIR}/cpp # ${APP_ROOT_MAIN_DIR}/ ${APP_ROOT_TEST_DIR} # ${APP_ROOT_TEST_DIR}/ ) 

Définissez vos chemins d’inclusion dans la variable “SHARED_INCLUDES” afin que vous puissiez citer votre fichier d’en-tête sans append ses chemins relatifs.


Modifier pour répondre à votre question sur la configuration des architectures

vous pouvez configurer vos cibles dans build.gradle comme ci-dessous:

 defaultConfig { externalNativeBuild { cmake { ... abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' ... } } } 

Le processus de construction de CMake prendra chaque ABI un par un. La variable ${ANDROID_ABI} dans CMakelists.txt peut vous indiquer l’ABI (architecture) en cours de construction. Et vous pouvez également utiliser cette variable pour configurer les chemins PATH de votre bibliothèque si vous en avez besoin. Par exemple, cette variable ${ANDROID_ABI} dans target_link_libraries(${SHARED_LIBRARY_NAME} -Wl,--whole-archive ${CMAKE_CURRENT_SOURCE_DIR}/../libs/${ANDROID_ABI}/libmine.a -Wl,--no-whole-archive) sera remplacé par armeabi-v7a , arm64-v8a , x86 ou x86_64 pendant la construction.

Tout d’abord, vous devez également spécifier les répertoires d’inclusion à l’aide de la commande include_directories () . Deuxièmement, il semble que vous souhaitiez lier une bibliothèque statique (.a) à votre bibliothèque partagée finale. Cela ne peut pas être fait. Vous avez besoin de bibliothèques partagées ou de bibliothèques statiques.