29、Android配置CMake

CMake 構建腳本是一個純文本文件,您必須將其命名爲 CMakeLists.txt,並在其中包含 CMake 構建您的 C/C++ 庫時需要使用的命令。如果您的原生源代碼文件還沒有 CMake 構建腳本,您需要自行創建一個,並在其中包含適當的 CMake 命令。

本部分將介紹您應該在構建腳本中包含哪些基本命令,以便指示 CMake 在創建原生庫時使用哪些源代碼文件。要了解詳情,請參閱介紹 CMake 命令的官方文檔。

在配置新的 CMake 構建腳本後,您需要配置 Gradle 以將 CMake 項目作爲構建依賴項包含在內,從而讓 Gradle 構建原生庫,並將其與應用的 APK 打包在一起。

注意:如果項目使用的是 ndk-build,您不需要創建 CMake 構建腳本。您只需配置 Gradle 以包含現有的原生庫項目即可;爲此,您需要提供 Android.mk 文件的路徑。

創建 CMake 構建腳本

要創建一個可以用作 CMake 構建腳本的純文本文件,請按以下步驟操作:

  1. 從 IDE 的左側打開 Project 窗格,然後從下拉菜單中選擇 Project 視圖。
  2. 右鍵點擊 your-module 的根目錄,然後依次選擇 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 )

提示:與指示 CMake 根據源代碼文件創建原生庫的方式一樣,您可以使用 add_executable() 命令指示 CMake 改爲根據這些源代碼文件來創建可執行文件。不過,根據原生源代碼文件構建可執行文件是可選操作,構建原生庫以將其打包到 APK 中即可滿足大多數項目的要求。

在使用 add_library() 向 CMake 構建腳本添加源代碼文件或庫時,Android Studio 還會在您同步項目後在 Project 視圖中顯示相關的頭文件。不過,爲了讓 CMake 能夠在編譯時找到頭文件,您需要向 CMake 構建腳本添加 include_directories() 命令,並指定頭文件的路徑:

    add_library(...)

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

CMake 使用以下規範來爲庫文件命名:

liblibrary-name.so

例如,如果您在構建腳本中指定“native-lib”作爲共享庫的名稱,CMake 就會創建一個名爲 libnative-lib.so 的文件。不過,在 Java 或 Kotlin 代碼中加載此庫時,請使用您在 CMake 構建腳本中指定的名稱:

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

注意:如果重命名或移除了 CMake 構建腳本中的庫,您需要在 Gradle 實施相關更改或從 APK 中移除舊版庫之前清理您的項目。要清理項目,請在菜單欄中依次選擇 Build > Clean Project

Android Studio 會自動向 Project 窗格中的 cpp 羣組添加源代碼文件和頭文件。通過使用多個 add_library() 命令,您可以爲 CMake 定義要根據其他源代碼文件構建的更多庫。

添加 NDK API

Android NDK 提供了一套您可能會覺得非常實用的原生 API 和庫。通過在項目的 CMakeLists.txt 腳本文件中包含 NDK 庫,您可以使用其中任何 API。

Android 平臺上已存在預構建的 NDK 庫,因此您無需構建它們或將它們打包到 APK 中。由於這些 NDK 庫已位於 CMake 搜索路徑中,因此您甚至無需指定本地安裝的 NDK 庫的位置,您只需爲 CMake 提供您想要使用的庫的名稱,並將其與您自己的原生庫相關聯即可。

向 CMake 構建腳本添加 find_library() 命令以找到 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 Studio 自動爲您定義的 ANDROID_NDK 路徑變量。

以下命令告訴 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} )

要將預構建庫打包到 APK 中,您需要使用 sourceSets 塊手動配置 Gradle 以包含 .so 文件的路徑。構建 APK 後,您可以使用 APK 分析器驗證 Gradle 會將哪些庫打包到您的 APK 中。

包含其他 CMake 項目

如果想要構建多個 CMake 項目並在 Android 項目中包含它們的輸出,您可以使用一個 CMakeLists.txt 文件(即您關聯到 Gradle 的那個文件)作爲頂級 CMake 構建腳本,並添加其他 CMake 項目作爲此構建腳本的依賴項。以下頂級 CMake 構建腳本會使用 add_subdirectory() 命令將另一個 CMakeLists.txt 文件指定爲構建依賴項,然後關聯其輸出,就像處理任何其他預構建庫一樣。

    # Sets lib_src_DIR to the path of the target CMake project.
    set( lib_src_DIR ../gmath )

    # Sets lib_build_DIR to the path of the desired output directory.
    set( lib_build_DIR ../gmath/outputs )
    file(MAKE_DIRECTORY ${lib_build_DIR})

    # Adds the CMakeLists.txt file located in the specified directory
    # as a build dependency.
    add_subdirectory( # Specifies the directory of the CMakeLists.txt file.
                      ${lib_src_DIR}

                      # Specifies the directory for the build outputs.
                      ${lib_build_DIR} )

    # Adds the output of the additional CMake build as a prebuilt static
    # library and names it lib_gmath.
    add_library( lib_gmath STATIC IMPORTED )
    set_target_properties( lib_gmath PROPERTIES IMPORTED_LOCATION
                           ${lib_build_DIR}/${ANDROID_ABI}/lib_gmath.a )
    include_directories( ${lib_src_DIR}/include )

    # Links the top-level CMake build output against lib_gmath.
    target_link_libraries( native-lib ... lib_gmath )

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章