Android CMake使用prebuild .a库

时间:2018-07-05 10:12:27

标签: android c++ cmake java-native-interface

我对CMake完全陌生,并且经常使用NDK。我想出要编写我的JNI接口并使用C库中2种方法的方法。我将此库编译为静态库,并获得了.a文件。现在,我有点不知所措,因为我不明白在尝试查找被调用的函数时如何告诉Android Studio使用该库。

这是我当前的CMakeLists.txt,位于“应用”模块文件夹中。

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)

在编译时,我得到警告,找不到被调用函数的引用。我的CMakeLists.txt是否正确,如何为这些功能包括.h文件?预先感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

首先,您还需要使用以下命令指定包含目录 include_directories()命令。 其次,似乎您想将 static 库(.a)与最终的 shared 库链接。无法做到这一点。您要么需要共享库,要么需要静态库。

答案 1 :(得分:1)

  

我不明白如何在尝试查找被调用函数时告诉Android Studio使用该库

要使用您的本机库,即libmy-lib.so,您需要将此共享库加载到Java部分中,如下所示。

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

我的CMakeLists.txt是否正确?

是的,这是正确的,但不是很完美。

  

以及如何为功能添加.h文件

为了使自己更容易添加头文件包括,您需要进行一些配置CMakelists.txt。例如。您可能具有以下目录结构,如果您只有app/src/main/cpp,则可以删除那些不相关的目录和配置。

    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

然后,您需要如下配置app/CMakelists.txt

    # 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 "<your-path>/App/"
    set(APP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})

    # set your 3 other root dirs, i.e. 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}/<your-other-child-dirs>

                    ${APP_ROOT_MAIN_DIR}
                    ${APP_ROOT_MAIN_DIR}/cpp
                    # ${APP_ROOT_MAIN_DIR}/<your-other-child-dirs>

                    ${APP_ROOT_TEST_DIR}
                    # ${APP_ROOT_TEST_DIR}/<your-other-child-dirs>
                    )

    # 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)

----已编辑----

有关如何链接预构建.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)

----编辑为回答您的三个问题----

  

cpp Directoy内CMakeLists.txt的一部分是什么?   它需要在cpp目录中还是在主目录中?

从理论上讲,您可以为所有源代码目录和标头目录使用一个CMakelists.txt,但是一旦您的项目发展到非常大的规模,这个多合一的CMakelists.txt就会变得非常实用复杂且不可读和不可维护。通常,每个cmake模块都应具有自己的CMakeLists.txt文件,以便对其进行模块化和易于管理。例如。 cpp目录有一个CMakeLists.txt来管理其所有子目录(如果有),maintest“模块”也是如此。

  

以及如何包含.a lib的.h文件-#include不起作用。

如上所述,您需要配置SHARED_INCLUDES以将相对路径添加到.h的标头(.a)中,以便可以简单地使用{{1} }包含标头。

#include <xxx.h>

将包含路径设置为“ SHARED_INCLUDES”变量,以便您可以引用头文件而无需添加其相对路径。


编辑以回答有关如何配置体系结构的问题

您可以在 set(SHARED_INCLUDES ${APP_ROOT_FOO_DIR} # ${APP_ROOT_FOO_DIR}/<your-other-child-dirs> ${APP_ROOT_MAIN_DIR} ${APP_ROOT_MAIN_DIR}/cpp # ${APP_ROOT_MAIN_DIR}/<your-other-child-dirs> ${APP_ROOT_TEST_DIR} # ${APP_ROOT_TEST_DIR}/<your-other-child-dirs> ) 内部配置目标,如下所示:

build.gradle

CMake的构建过程将逐个处理每个ABI。 defaultConfig { externalNativeBuild { cmake { ... abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' ... } } } 中的变量${ANDROID_ABI}可以告诉您它正在构建的当前ABI(体系结构)。并且,如果需要,您还可以使用此变量来配置库PATH。

例如

中的CMakelists.txt变量
${ANDROID_ABI}

在构建期间将被target_link_libraries(${SHARED_LIBRARY_NAME} -Wl,--whole-archive ${CMAKE_CURRENT_SOURCE_DIR}/../libs/${ANDROID_ABI}/libmine.a -Wl,--no-whole-archive) armeabi-v7aarm64-v8ax86替换。