AndroidStudio用Cmake方式编译NDK代码(cmake配置.a库)

1.cmake是什么?css

CMake是一个跨平台的安装(编译)工具,能够用简单的语句来描述全部平台的安装(编译过程)。他可以输出各类各样的makefile或者project文件,能测试编译器所支持的C++特性,相似UNIX下的automake。html

 

谷歌从AndroidStudio2.2以上就添加了Cmake方式来编译NDK代码,并从NDK例子看出,默认编译的方式就是cmake方式。java

 

2.谷歌官方的用cmake方式编译NDK的教程android

 

谷歌从AndroidStudio2.2以上就添加了Cmake方式来编译NDK代码,并从NDK例子看出,默认编译的方式就是cmake方式。json

若是您但愿向现有项目添加原生代码,请执行如下步骤:api

  1. 建立新的原生源文件并将其添加到您的 Android Studio 项目中。
    • 若是您已经拥有原生代码或想要导入预构建的原生库,则能够跳过此步骤。
  2. 建立 CMake 构建脚本,将您的原生源代码构建到库中。若是导入和关联预构建库或平台库,您也须要此构建脚本。
    • 若是您的现有原生库已经拥有 CMakeLists.txt 构建脚本或者使用 ndk-build 并包含 Android.mk 构建脚本,则能够跳过此步骤。
  3. 提供一个指向您的 CMake 或 ndk-build 脚本文件的路径,将 Gradle 关联到您的原生库。Gradle 使用构建脚本将源代码导入您的 Android Studio 项目并将原生库(SO 文件)封装到 APK 中。

配置完项目后,您可使用 JNI 框架从 Java 代码中访问您的原生函数。要构建和运行应用,只需点击 Run 从菜单栏运行应用。Gradle 会以依赖项的形式添加您的外部原生构建流程,用于编译、构建原生库并将其随 APK 一块儿封装。网络

建立新的原生源文件

要在应用模块的主源代码集中建立一个包含新建原生源文件的 cpp/ 目录,请按如下步骤操做:架构

  1. 从 IDE 的左侧打开 Project 窗格并从下拉菜单中选择 Project 视图。
  2. 导航到您的模块 > src,右键点击 main 目录,而后选择 New > Directory
  3. 为目录输入一个名称(例如 cpp)并点击 OK
  4. 右键点击您刚刚建立的目录,而后选择 New > C/C++ Source File
  5. 为您的源文件输入一个名称,例如 native-lib
  6. 从 Type 下拉菜单中,为您的源文件选择文件扩展名,例如 .cpp
    • 点击 Edit File Types ,您能够向下拉菜单中添加其余文件类型,例如 .cxx 或 .hxx。在弹出的 C/C++ 对话框中,从 Source Extension 和 Header Extension 下拉菜单中选择另外一个文件扩展名,而后点击 OK
  7. 若是您还但愿建立一个标头文件,请选中 Create an associated header 复选框。
  8. 点击 OK

建立 CMake 构建脚本

若是您的原生源文件尚未 CMake 构建脚本,则您须要自行建立一个并包含适当的 CMake 命令。CMake 构建脚本是一个纯文本文件,您必须将其命名为 CMakeLists.txt。本部分介绍了您应包含到构建脚本中的一些基本命令,用于在建立原生库时指示 CMake 应使用哪些源文件。oracle

:若是您的项目使用 ndk-build,则不须要建立 CMake 构建脚本。提供一个指向您的 Android.mk 文件的路径,将 Gradle 关联到您的原生库app

要建立一个能够用做 CMake 构建脚本的纯文本文件,请按如下步骤操做:

  1. 从 IDE 的左侧打开 Project 窗格并从下拉菜单中选择 Project 视图。
  2. 右键点击您的模块的根目录并选择 New > File

    :您能够在所需的任意位置建立构建脚本。不过,在配置构建脚本时,原生源文件和库的路径将与构建脚本的位置相关。

  3. 输入“CMakeLists.txt”做为文件名并点击 OK

如今,您能够添加 CMake 命令,对您的构建脚本进行配置。要指示 CMake 从原生源代码建立一个原生库,请将 cmake_minimum_required() 和 add_library() 命令添加到您的构建脚本中:

# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.

cmake_minimum_required(VERSION 3.4.1)

# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add.library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.

add_library( # Specifies the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )

 

使用 add_library() 向您的 CMake 构建脚本添加源文件或库时,Android Studio 还会在您同步项目后在 Project 视图下显示关联的标头文件。不过,为了确保 CMake 能够在编译时定位您的标头文件,您须要将 include_directories() 命令添加到 CMake 构建脚本中并指定标头的路径:

add_library(...)

# Specifies a path to native header files.
include_directories(src/main/cpp/include/)

CMake 使用如下规范来为库文件命名:

lib库名称.so

例如,若是您在构建脚本中指定“native-lib”做为共享库的名称,CMake 将建立一个名称为 libnative-lib.so 的文件。不过,在 Java 代码中加载此库时,请使用您在 CMake 构建脚本中指定的名称:

static {     System.loadLibrary(“native-lib”); }

:若是您在 CMake 构建脚本中重命名或移除某个库,您须要先清理项目,Gradle 随后才会应用更改或者从 APK 中移除旧版本的库。要清理项目,请从菜单栏中选择 Build > Clean Project

Android Studio 会自动将源文件和标头添加到 Project 窗格的 cpp 组中。使用多个 add_library() 命令,您能够为 CMake 定义要从其余源文件构建的更多库。

添加 NDK API

Android NDK 提供了一套实用的原生 API 和库。经过将 NDK 库包含到项目的 CMakeLists.txt 脚本文件中,您可使用这些 API 中的任意一种。

预构建的 NDK 库已经存在于 Android 平台上,所以,您无需再构建或将其封装到 APK 中。因为 NDK 库已是 CMake 搜索路径的一部分,您甚至不须要在您的本地 NDK 安装中指定库的位置 - 只须要向 CMake 提供您但愿使用的库的名称,并将其关联到您本身的原生库。

将 find_library() 命令添加到您的 CMake 构建脚本中以定位 NDK 库,并将其路径存储为一个变量。您可使用此变量在构建脚本的其余部分引用 NDK 库。如下示例能够定位 Android 特定的日志支持库并将其路径存储在 log-lib 中:

find_library( # Defines the name of the path variable that stores the
              # location of the NDK library.
              log-lib

              # Specifies the name of the NDK library that
              # CMake needs to locate.
              log )

 

为了确保您的原生库能够在 log 库中调用函数,您须要使用 CMake 构建脚本中的 target_link_libraries() 命令关联库:

find_library(...)

# Links your native library against one or more other native libraries.
target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the log library to the target library.
                       ${log-lib} )

 

NDK 还以源代码的形式包含一些库,您在构建和关联到您的原生库时须要使用这些代码。您可使用 CMake 构建脚本中的 add_library() 命令,将源代码编译到原生库中。要提供本地 NDK 库的路径,您可使用 ANDROID_NDK 路径变量,Android Studio 会自动为您定义此变量。

如下命令能够指示 CMake 构建 android_native_app_glue.c,后者会将 NativeActivity 生命周期事件和触摸输入置于静态库中并将静态库关联到 native-lib

add_library( app-glue
             STATIC
             ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c )

# You need to link static libraries against your shared native library.
target_link_libraries( native-lib app-glue ${log-lib} )

 

添加其余预构建库

添加预构建库与为 CMake 指定要构建的另外一个原生库相似。不过,因为库已经预先构建,您须要使用 IMPORTED 标志告知 CMake 您只但愿将库导入到项目中:

add_library( imported-lib
             SHARED
             IMPORTED )

而后,您须要使用 set_target_properties() 命令指定库的路径,以下所示。

某些库为特定的 CPU 架构(或应用二进制接口 (ABI))提供了单独的软件包,并将其组织到单独的目录中。此方法既有助于库充分利用特定的 CPU 架构,又能让您仅使用所需的库版本。要向 CMake 构建脚本中添加库的多个 ABI 版本,而没必要为库的每一个版本编写多个命令,您可使用 ANDROID_ABI 路径变量。此变量使用 NDK 支持的一组默认 ABI,或者您手动配置 Gradle 而让其使用的一组通过筛选的 ABI。例如:

add_library(...)
set_target_properties( # Specifies the target library.
                       imported-lib

                       # Specifies the parameter you want to define.
                       PROPERTIES IMPORTED_LOCATION

                       # Provides the path to the library you want to import.
                       imported-lib/src/${ANDROID_ABI}/libimported-lib.so )

为了确保 CMake 能够在编译时定位您的标头文件,您须要使用 include_directories() 命令,并包含标头文件的路径:

include_directories( imported-lib/include/ )

:若是您但愿封装一个并非构建时依赖项的预构建库(例如在添加属于 imported-lib 依赖项的预构建库时),则不须要执行如下说明来关联库。

要将预构建库关联到您本身的原生库,请将其添加到 CMake 构建脚本的 target_link_libraries() 命令中:

target_link_libraries( native-lib imported-lib app-glue ${log-lib} )

在您构建应用时,Gradle 会自动将导入的库封装到 APK 中。您可使用 APK 分析器验证 Gradle 将哪些库封装到您的 APK 中。如需了解有关 CMake 命令的详细信息,请参阅 CMake 文档

 

导入.a静态库

自 android studio 2.2 +后就集成了ndk开发, 自带cmake 编译器.  编写ndk时候,配置很简单。不再须要用android.mk配置文件。

新建一个带ndk开发项目的结构是这样的,

 

 

言归正传,那么要添加第三方的xx.a连接库呢?

一般咱们把第三方提供的h文件夹,放在cpp的include里面。这是规范,不是必须。而xxx.a库放在src/main/jniLibs/armeabi目录下。

本文章以添加libjsoncpp.a链接库作例子

首先在cpp目录下创建一个include文件夹,把jsoncpp官方提供的头文件文件夹拷贝到include里面(我这个项目有3个连接库,jsoncpp, curl , openssl,另外2个仅作参考做用,与其无关)

 

 

第二步, 在app的src目录的main下,创建一个文件夹,jniLibs,而后在jniLibs里面再创建一个armeabi文件夹。

而后把libjsoncpp.a连接库拷贝进去。

 

第三步, 动态库与头文件拷贝进去时候,是须要告诉编译器作关联的。在app目录的src文件夹下有个CMakeLists.txt文件,咱们经过它编写配置信息。

jsoncpp头文件所在目录告诉编译,在里面添加

  1. include_directories( src/main/cpp/include/jsoncpp)  

若是有多个连接库,那么能够这样
例若有三个连接库,jsoncpp, currl , openssl.

 
  1. include_directories( src/main/cpp/include/jsoncpp  
  2.                      src/main/cpp/include/curl  
  3.                      src/main/cpp/include/openssl  
  4.                      )  
 

而后告诉编译器,libjsoncppp.a在哪一个目录下,并指定连接库的名称

接着添加

  1. #添加json库  
  2. add_library(jsoncpp STATIC IMPORTED)  
  3. set_target_properties(jsoncpp  
  4.   PROPERTIES IMPORTED_LOCATION  
  5.   ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libjsoncpp.a)  

而后修改target_link_libraries,加多一行jsoncpp

 
  1. target_link_libraries(native-lib  
  2.                       jsoncpp  
  3.                       ${log-lib})  

若是有多个,那么能够屡次添加。如

  1. #添加json库  
  2. add_library(jsoncpp STATIC IMPORTED)  
  3. set_target_properties(jsoncpp  
  4.   PROPERTIES IMPORTED_LOCATION  
  5.   ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libjsoncpp.a)  
  6.   
  7. #添加curl网络请求  
  8. add_library(curl STATIC IMPORTED)  
  9. set_target_properties(curl  
  10.   PROPERTIES IMPORTED_LOCATION  
  11.   ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libcurl.a)  
  12.   
  13. #添加加密工具(md5, base64, des, aes , asa) part-1  
  14. add_library(crypto STATIC IMPORTED)  
  15. set_target_properties(crypto  
  16.   PROPERTIES IMPORTED_LOCATION  
  17.   ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libcrypto.a)  
  18.   
  19. #添加加密工具(md5, base64, des, aes , asa) des加密 part-2  
  20. add_library(ssl STATIC IMPORTED)  
  21. set_target_properties(ssl  
  22.   PROPERTIES IMPORTED_LOCATION  
  23.   ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libssl.a)  
 
  1. target_link_libraries(native-lib  
  2.                       jsoncpp  
  3.                       curl  
  4.                       crypto  
  5.                       ssl  
  6.                       ${log-lib})   

而后gradle编译就可使用了。是否是很简单?

 

 

要将 Gradle 关联到您的原生库,您须要提供一个指向 CMake 或 ndk-build 脚本文件的路径。在您构建应用时,Gradle 会以依赖项的形式运行 CMake 或 ndk-build,并将共享的库封装到您的 APK 中。Gradle 还使用构建脚原本了解要将哪些文件添加到您的 Android Studio 项目中,以便您能够从 Project 窗口访问这些文件。若是您的原生源文件没有构建脚本,则须要先建立 CMake 构建脚本,而后再继续。

将 Gradle 关联到原生项目后,Android Studio 会更新 Project 窗格以在 cpp 组中显示您的源文件和原生库,在 External Build Files 组中显示您的外部构建脚本。

:更改 Gradle 配置时,请确保经过点击工具栏中的 Sync Project  应用更改。此外,若是在将 CMake 或 ndk-build 脚本文件关联到 Gradle 后再对其进行更改,您应当从菜单栏中选择 Build > Refresh Linked C++ Projects,将 Android Studio 与您的更改同步。

您可使用 Android Studio UI 将 Gradle 关联到外部 CMake 或 ndk-build 项目:

  1. 从 IDE 左侧打开 Project 窗格并选择 Android 视图。
  2. 右键点击您想要关联到原生库的模块(例如 app 模块),并从菜单中选择 Link C++ Project with Gradle。您应看到一个如图 4 所示的对话框。
  3. 从下拉菜单中,选择 CMake 或 ndk-build
    1. 若是您选择 CMake,请使用 Project Path 旁的字段为您的外部 CMake 项目指定 CMakeLists.txt 脚本文件。
    2. 若是您选择 ndk-build,请使用 Project Path 旁的字段为您的外部 ndk-build 项目指定 Android.mk 脚本文件。若是 Application.mk 文件与您的 Android.mk 文件位于相同目录下,Android Studio 也会包含此文件。

    图 4.使用 Android Studio 对话框关联外部 C++ 项目。

  4. 点击 OK

手动配置 Gradle

要手动配置 Gradle 以关联到您的原生库,您须要将 externalNativeBuild {} 块添加到模块级 build.gradle 文件中,并使用 cmake {} 或 ndkBuild {}对其进行配置:

android {
  ...
  defaultConfig {...}
  buildTypes {...}

  // Encapsulates your external native build configurations.
  externalNativeBuild {

    // Encapsulates your CMake build configurations.
    cmake {

      // Provides a relative path to your CMake build script.
      path "CMakeLists.txt"
    }
  }
}

:若是您想要将 Gradle 关联到现有 ndk-build 项目,请使用 ndkBuild {} 块而不是 cmake {},并提供 Android.mk 文件的相对路径。若是 Application.mk 文件与您的 Android.mk 文件位于相同目录下,Gradle 也会包含此文件。

指定可选配置

您能够在模块级 build.gradle 文件的 defaultConfig {} 块中配置另外一个 externalNativeBuild {} 块,为 CMake 或 ndk-build 指定可选参数和标志。与 defaultConfig {} 块中的其余属性相似,您也能够在构建配置中为每一个产品风味重写这些属性。

例如,若是您的 CMake 或 ndk-build 项目定义多个原生库,您可使用 targets 属性仅为给定产品风味构建和封装这些库中的一部分。如下代码示例说明了您能够配置的部分属性:

android {
  ...
  defaultConfig {
    ...
    // This block is different from the one you use to link Gradle
    // to your CMake or ndk-build script.
    externalNativeBuild {

      // For ndk-build, instead use ndkBuild {}
      cmake {

        // Passes optional arguments to CMake.
        arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"

        // Sets optional flags for the C compiler.
        cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"

        // Sets a flag to enable format macro constants for the C++ compiler.
        cppFlags "-D__STDC_FORMAT_MACROS"
      }
    }
  }

  buildTypes {...}

  productFlavors {
    ...
    demo {
      ...
      externalNativeBuild {
        cmake {
          ...
          // Specifies which native libraries to build and package for this
          // product flavor. If you don't configure this property, Gradle
          // builds and packages all shared object libraries that you define
          // in your CMake or ndk-build project.
          targets "native-lib-demo"
        }
      }
    }

    paid {
      ...
      externalNativeBuild {
        cmake {
          ...
          targets "native-lib-paid"
        }
      }
    }
  }

  // Use this block to link Gradle to your CMake or ndk-build script.
  externalNativeBuild {
    cmake {...}
    // or ndkBuild {...}
  }
}

要详细了解配置产品风味和构建变体,请参阅配置构建变体。如需了解您可使用 arguments 属性为 CMake 配置的变量列表,请参阅使用 CMake 变量

指定 ABI

默认状况下,Gradle 会针对 NDK 支持的 ABI 将您的原生库构建到单独的 .so 文件中,并将其所有封装到您的 APK 中。若是您但愿 Gradle 仅构建和封装原生库的特定 ABI 配置,您能够在模块级 build.gradle 文件中使用 ndk.abiFilters 标志指定这些配置,以下所示:

android {
  ...
  defaultConfig {
    ...
    externalNativeBuild {
      cmake {...}
      // or ndkBuild {...}
    }

    ndk {
      // Specifies the ABI configurations of your native
      // libraries Gradle should build and package with your APK.
      abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
                   'arm64-v8a'
    }
  }
  buildTypes {...}
  externalNativeBuild {...}
}

在大多数状况下,您只须要在 ndk {} 块中指定 abiFilters(如上所示),由于它会指示 Gradle 构建和封装原生库的这些版本。不过,若是您但愿控制 Gradle 应当构建的配置,并独立于您但愿其封装到 APK 中的配置,请在 defaultConfig.externalNativeBuild.cmake {} 块(或 defaultConfig.externalNativeBuild.ndkBuild {} 块中)配置另外一个 abiFilters 标志。Gradle 会构建这些 ABI 配置,不过仅会封装您在 defaultConfig.ndk{} 块中指定的配置。

为了进一步下降 APK 的大小,请考虑配置 ABI APK 拆分,而不是建立一个包含原生库全部版本的大型 APK,Gradle 会为您想要支持的每一个 ABI 建立单独的 APK,而且仅封装每一个 ABI 须要的文件。若是您配置 ABI 拆分,但没有像上面的代码示例同样指定 abiFilters 标志,Gradle 会构建原生库的全部受支持 ABI 版本,不过仅会封装您在 ABI 拆分配置中指定的版本。为了不构建您不想要的原生库版本,请为 abiFilters 标志和 ABI 拆分配置提供相同的 ABI 列表。

 

谷歌从AndroidStudio2.2以上就添加了Cmake方式来编译NDK代码,并从NDK例子看出,默认编译的方式就是cmake方式。
相关文章
相关标签/搜索