2

我对 CMake 完全陌生,并且共同使用 NDK。我想出编写​​我的 JNI 接口并使用 C 库中的 2 个方法。我将此库编译为静态库并获得了 .a 文件。现在我有点迷失了,因为我不明白如何告诉 Android Studio 在尝试查找调用的函数时使用这个库。

这是我当前的 CMakeLists.txt,它位于“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)

在编译时,我收到警告说找不到对被调用函数的引用。我的 CMakeLists.txt 是否正确以及如何包含函数的 .h 文件?提前感谢您的帮助!

4

2 回答 2

2

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

于 2018-07-05T16:29:17.073 回答
2

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

为了使用您的本机库,即libmy-lib.so针对您的情况,您需要在您的 java 部分中加载此共享库,如下所示。

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

我的 CMakeLists.txt 是否正确?

是的,它是正确的,但并不完美。

以及如何包含函数的 .h 文件

为了让自己的工作更容易添加头文件includes,你需要稍微配置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 目录中的 CMakeLists.txt 的一部分是什么?它需要在cpp目录中还是在主目录中?

从理论上讲,您可以只CMakelists.txt为您的所有源代码目录和标头目录提供一个,但是一旦您的项目发展到非常大的规模,这种一体化CMakelists.txt将变得非常复杂并且不可读和不可维护。通常,每个 cmake 模块都应该有自己的CMakeLists.txt文件,以便模块化并且更易于管理。例如, cppdir 有一个CMakeLists.txt来管理其所有子目录(如果有的话),maintest模块”也是如此。

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

正如我上面提到的,您需要配置SHARED_INCLUDES将您的相对路径添加到您的标头 ( .h) .a,以便您可以简单地#include <xxx.h>用于标头包含。

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

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


编辑以回答您有关如何配置架构的问题

您可以在内部配置目标build.gradle,如下所示:

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

CMake 构建过程将逐个处理每个 ABI。${ANDROID_ABI}里面的变量CMakelists.txt可以告诉你它正在构建的当前 ABI(架构)。如果需要,您还可以使用此变量来配置库 PATH。

eg 这个变量${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-v7a, arm64-v8a,x86x86_64在构建期间。

于 2018-07-06T03:02:16.627 回答