【Android NDK 開發】Android Studio 使用 CMake 導入靜態庫 ( CMake 簡介 | 構建腳本路徑配置 | 引入靜態庫 | 指定靜態庫路徑 | 鏈接動態庫 )



I . CMake 簡介



1 . CMake 簡介 :


① 構建工具 : CMake 是 Android 中使用 C/C++ 構建原生庫的默認工具 ;

② 跨平臺 : CMake 是跨平臺的構建工具 , 其可以根據不同類型的平臺 , 不同類型的編譯器 , 生成對應的 Makefile ;

③ 本質 : CMake 不是直接編譯項目的 , 而是生成 make 對應的構建腳本 Makefile 文件 , 還是使用 make 進行構建項目 ;

③ Android 中生成的腳本 : Android Studio 中 , CMake 生成 ninja 腳本 , ninja 是一種輕量級快速構建工具 ; ( 僅做參考 )


2 . CMake 與 Android.mk : Google 逐漸放棄了對 Android.mk 的支持 , 目前新項目推薦使用 CMake 構建本地庫 , 舊的項目建議將 Android.mk 轉爲 CMake 構建 , 以獲取更好的代碼維護 ;



II . Android Studio 中 CMake 引入靜態庫流程



Android Studio 中 CMake 引入靜態庫流程 :


1 . build.gradle 配置 CMake 編譯選項 : 在 Module 級別的 build.gradle 腳本中配置 CMake 編譯選項 ;

        // I . NDK 配置 1 : 配置 AS 工程中的 C/C++ 源文件的編譯


        //     defaultConfig 內部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件編譯參數
        //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 構建腳本的路徑
        externalNativeBuild {
            cmake {
                cppFlags ""

                //配置編譯 C/C++ 源文件爲哪幾個 CPU 指令集的函數庫 (arm , x86 等)
                abiFilters "armeabi-v7a"
            }
            /*ndkBuild{
                abiFilters "armeabi-v7a" *//*, "arm64-v8a", "x86", "x86_64"*//*
            }*/
        }

2 . build.gradle 配置 NDK 打包選項 : 在 Module 級別的 build.gradle 腳本中配置 NDK 打包選項 ;

        // II . NDK 配置 2 : 配置 AS 工程中的 C/C++ 源文件的編譯


        //配置 APK 打包 哪些動態庫
        //  示例 : 如在工程中集成了第三方庫 , 其提供了 arm, x86, mips 等指令集的動態庫
        //        那麼爲了控制打包後的應用大小, 可以選擇性打包一些庫 , 此處就是進行該配置
        ndk{
            // 打包生成的 APK 文件指揮包含 ARM 指令集的動態庫
            abiFilters "armeabi-v7a" /*, "arm64-v8a", "x86", "x86_64"*/
        }

3 . build.gradle 配置 CMake 構建腳本 CMakeList.txt 路徑 : 在 Module 級別的 build.gradle 腳本中配置 Android.mk 構建腳本的路徑 ;

    // III . NDK 配置  : 配置 AS 工程中的 C/C++ 源文件的編譯構建腳本


    // 配置 NDK 的編譯腳本路徑
    // 編譯腳本有兩種 ① CMakeList.txt ② Android1.mk
    //     defaultConfig 內部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件編譯參數
    //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 構建腳本的路徑
    externalNativeBuild {

        // 配置 CMake 構建腳本 CMakeLists.txt 腳本路徑
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }

        // 配置 Android1.mk 構建腳本路徑
        /*ndkBuild{
            //path "src/main/ndkBuild_Shared/Android.mk"
            path "src/main/ndkBuild_Static/Android.mk"
        }*/
    }

4 . CMake 構建腳本 CMakeList.txt 引入靜態庫 :

# 引入靜態庫
#       ① 參數 1 ( add ) : 設置引入的靜態庫名稱
#       ② 參數 2 ( SHARED ) : 設置引入的函數庫類型 : ① 靜態庫 STATIC ② 動態庫 SHARED
#       ③ 參數 3 ( IMPORTED ) : 表示引入第三方靜態庫 , 導入靜態庫 , 相當於預編譯靜態庫
#                                   後續還需要設置導入路徑 , 配合該配置使用
add_library(
        # 設置引入的靜態庫名稱
        add

        # 設置引入的函數庫類型爲靜態庫
        STATIC

        # 表示引入第三方靜態庫
        IMPORTED)

5 . CMake 構建腳本 CMakeList.txt 設置靜態庫路徑 :

# 設置上述靜態庫的導入路徑
#       設置目標屬性參數 :
#           ① 參數 1 ( add ) : 要設置哪個函數庫的屬性
#           ② 參數 2 ( PROPERTIES ) : 設置目標屬性
#           ③ 參數 3 ( IMPORTED_LOCATION ) : 設置導入路徑
#           ④ 參數 4 : 配置靜態庫的文件路徑
set_target_properties(
        # 設置目標
        add

        # 設置屬性
        PROPERTIES

        # 導入路徑
        IMPORTED_LOCATION

        # ${CMAKE_SOURCE_DIR} 是本 CMakeList.txt 構建腳本的路徑 , 是 CMake 工具內置的變量
        #       Android CMake 也內置了一些變量 , 如 ANDROID_ABI
        ${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a/libadd.a)

6 . CMake 構建腳本 CMakeList.txt 鏈接靜態庫 :

# 鏈接函數庫
#       參數 1 : 本構建腳本要生成的動態庫目 標
#       參數 2 ~ ... : 後面是之前預編譯的動態庫或靜態庫 , 或引入的動態庫
target_link_libraries(
        native-lib

        # 表示 編譯 native-lib 模塊, 要鏈接 add 模塊
        add

        ${log-lib})


III . 指定 CMake 最小版本號



指定 CMake 最低版本 : 在 CMake 構建腳本 CMakeList.txt 文件中 , 第一行一定要先指定 CMake 最小版本號 ;

cmake_minimum_required(VERSION 3.4.1)


IV . 導入函數庫 ( 靜態庫 / 動態庫 ) 編譯配置



函數庫 ( 靜態庫 / 動態庫 ) 編譯配置 : 函數庫編譯需要傳入 3 個參數 ;


① 參數 1 : 設置生成的動態庫名稱 ;

② 參數 2 : 設置生成的函數庫類型 : a . 靜態庫 STATIC , b . 動態庫 SHARED ;

③ 參數 3 : 配置要編譯的源文件 ;

# 引入靜態庫
#       ① 參數 1 ( add ) : 設置引入的靜態庫名稱
#       ② 參數 2 ( SHARED ) : 設置引入的函數庫類型 : ① 靜態庫 STATIC ② 動態庫 SHARED
#       ③ 參數 3 ( IMPORTED ) : 表示引入第三方靜態庫 , 導入靜態庫 , 相當於預編譯靜態庫
#                                   後續還需要設置導入路徑 , 配合該配置使用
add_library(
        # 設置引入的靜態庫名稱
        add

        # 設置引入的函數庫類型爲靜態庫
        STATIC

        # 表示引入第三方靜態庫
        IMPORTED)

2 . 特別注意 : 使用這種方法引入動態庫 , 在 6.0 以上的系統是無法使用的 , 推薦使用 set() 設置 -L 參數的方式引入動態庫 ;

# 設置變量
# CMAKE_CXX_FLAGS 表示會將 C++ 的參數傳給編譯器
# CMAKE_C_FLAGS 表示會將 C 參數傳給編譯器

# 參數設置 : 傳遞 CMAKE_CXX_FLAGS C+= 參數給編譯器時 , 在 該參數後面指定庫的路徑
#   CMAKE_SOURCE_DIR 指的是當前的文件地址
#   -L 參數指定動態庫的查找路徑
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a")


V . 導入第三方函數庫路徑配置



導入第三方函數庫路徑配置 : 通過調用 set_target_properties () 設置第三方庫路徑 ;


① 參數 1 ( add ) : 要設置哪個函數庫的屬性 ;

② 參數 2 ( PROPERTIES ) : 設置目標屬性 ;

③ 參數 3 ( IMPORTED_LOCATION ) : 設置導入路徑 ;

④ 參數 4 : 配置靜態庫的文件路徑 ;

# 設置上述靜態庫的導入路徑
#       設置目標屬性參數 :
#           ① 參數 1 ( add ) : 要設置哪個函數庫的屬性
#           ② 參數 2 ( PROPERTIES ) : 設置目標屬性
#           ③ 參數 3 ( IMPORTED_LOCATION ) : 設置導入路徑
#           ④ 參數 4 : 配置靜態庫的文件路徑
set_target_properties(
        # 設置目標
        add

        # 設置屬性
        PROPERTIES

        # 導入路徑
        IMPORTED_LOCATION

        # ${CMAKE_SOURCE_DIR} 是本 CMakeList.txt 構建腳本的路徑 , 是 CMake 工具內置的變量
        #       Android CMake 也內置了一些變量 , 如 ANDROID_ABI
        ${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a/libadd.a)


VI . 輸出日誌信息



調用 message() 方法可以輸出日誌信息 :

# 打印日誌信息
#       ${ANDROID_ABI} 的作用是獲取當前的 CPU 指令集架構
#           當本次編譯 armeabi-v7a CPU 架構時 , ${ANDROID_ABI} 值爲 armeabi-v7a
#           當本次編譯 x86 CPU 架構時 , ${ANDROID_ABI} 值爲 x86
message("CMAKE_SOURCE_DIR : ${CMAKE_SOURCE_DIR}, ANDROID_ABI : ${ANDROID_ABI}")


VII . 鏈接函數庫



鏈接函數庫 : 這裏注意第一個參數必須是要生成的動態庫模塊 ;

# 鏈接函數庫
#       參數 1 : 本構建腳本要生成的動態庫目標
#       參數 2 ~ ... : 後面是之前預編譯的動態庫或靜態庫 , 或引入的動態庫
target_link_libraries(
        native-lib

        # 表示 編譯 native-lib 模塊, 要鏈接 add 模塊
        add

        ${log-lib})


VIII . Module 級別的 build.gradle 完整配置代碼



apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.0"
    defaultConfig {
        applicationId "kim.hsl.cmake"
        minSdkVersion 15
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"



        // I . NDK 配置 1 : 配置 AS 工程中的 C/C++ 源文件的編譯


        //     defaultConfig 內部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件編譯參數
        //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 構建腳本的路徑
        externalNativeBuild {
            cmake {
                cppFlags ""

                //配置編譯 C/C++ 源文件爲哪幾個 CPU 指令集的函數庫 (arm , x86 等)
                abiFilters "armeabi-v7a"
            }
            /*ndkBuild{
                abiFilters "armeabi-v7a" *//*, "arm64-v8a", "x86", "x86_64"*//*
            }*/
        }



        // II . NDK 配置 2 : 配置 AS 工程中的 C/C++ 源文件的編譯


        //配置 APK 打包 哪些動態庫
        //  示例 : 如在工程中集成了第三方庫 , 其提供了 arm, x86, mips 等指令集的動態庫
        //        那麼爲了控制打包後的應用大小, 可以選擇性打包一些庫 , 此處就是進行該配置
        ndk{
            // 打包生成的 APK 文件指揮包含 ARM 指令集的動態庫
            abiFilters "armeabi-v7a" /*, "arm64-v8a", "x86", "x86_64"*/
        }

    }



    // III . NDK 配置  : 配置 AS 工程中的 C/C++ 源文件的編譯構建腳本


    // 配置 NDK 的編譯腳本路徑
    // 編譯腳本有兩種 ① CMakeList.txt ② Android1.mk
    //     defaultConfig 內部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件編譯參數
    //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 構建腳本的路徑
    externalNativeBuild {

        // 配置 CMake 構建腳本 CMakeLists.txt 腳本路徑
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }

        // 配置 Android1.mk 構建腳本路徑
        /*ndkBuild{
            //path "src/main/ndkBuild_Shared/Android.mk"
            path "src/main/ndkBuild_Static/Android.mk"
        }*/
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}



IX . CMakeList.txt 完整配置代碼




# 指定 CMake 最低版本
cmake_minimum_required(VERSION 3.4.1)

# 設置函數庫編譯
add_library( # 參數 1 : 設置生成的動態庫名稱
        native-lib

        # 參數 2 : 設置生成的函數庫類型 : ① 靜態庫 STATIC ② 動態庫 SHARED
        SHARED

        # 參數 3 : 配置要編譯的源文件
        native-lib.cpp)


# 引入靜態庫
#       ① 參數 1 ( add ) : 設置引入的靜態庫名稱
#       ② 參數 2 ( SHARED ) : 設置引入的函數庫類型 : ① 靜態庫 STATIC ② 動態庫 SHARED
#       ③ 參數 3 ( IMPORTED ) : 表示引入第三方靜態庫 , 導入靜態庫 , 相當於預編譯靜態庫
#                                   後續還需要設置導入路徑 , 配合該配置使用
add_library(
        # 設置引入的靜態庫名稱
        add

        # 設置引入的函數庫類型爲靜態庫
        STATIC

        # 表示引入第三方靜態庫
        IMPORTED)

# 設置上述靜態庫的導入路徑
#       設置目標屬性參數 :
#           ① 參數 1 ( add ) : 要設置哪個函數庫的屬性
#           ② 參數 2 ( PROPERTIES ) : 設置目標屬性
#           ③ 參數 3 ( IMPORTED_LOCATION ) : 設置導入路徑
#           ④ 參數 4 : 配置靜態庫的文件路徑
set_target_properties(
        # 設置目標
        add

        # 設置屬性
        PROPERTIES

        # 導入路徑
        IMPORTED_LOCATION

        # ${CMAKE_SOURCE_DIR} 是本 CMakeList.txt 構建腳本的路徑 , 是 CMake 工具內置的變量
        #       Android CMake 也內置了一些變量 , 如 ANDROID_ABI
        ${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a/libadd.a)

# 打印日誌信息
#       ${ANDROID_ABI} 的作用是獲取當前的 CPU 指令集架構
#           當本次編譯 armeabi-v7a CPU 架構時 , ${ANDROID_ABI} 值爲 armeabi-v7a
#           當本次編譯 x86 CPU 架構時 , ${ANDROID_ABI} 值爲 x86
message("CMAKE_SOURCE_DIR : ${CMAKE_SOURCE_DIR}, ANDROID_ABI : ${ANDROID_ABI}")


# 到預設的目錄查找 log 庫 , 將找到的路徑賦值給 log-lib
#   這個路徑是 NDK 的 ndk-bundle\platforms\android-29\arch-arm\usr\lib\liblog.so
#   不同的 Android 版本號 和 CPU 架構 需要到對應的目錄中查找 , 此處是 29 版本 32 位 ARM 架構的日誌庫
find_library(
        log-lib

        log)


# 設置變量
# CMAKE_CXX_FLAGS 表示會將 C++ 的參數傳給編譯器
# CMAKE_C_FLAGS 表示會將 C 參數傳給編譯器

# 參數設置 : 傳遞 CMAKE_CXX_FLAGS C+= 參數給編譯器時 , 在 該參數後面指定庫的路徑
#   CMAKE_SOURCE_DIR 指的是當前的文件地址
#   -L 參數指定動態庫的查找路徑
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a")

# 鏈接函數庫
#       參數 1 : 本構建腳本要生成的動態庫目 標
#       參數 2 ~ ... : 後面是之前預編譯的動態庫或靜態庫 , 或引入的動態庫
target_link_libraries(
        native-lib

        # 表示 編譯 native-lib 模塊, 要鏈接 add 模塊
        add

        ${log-lib})


X . 博客資源



CSDN 博客地址 : 【Android NDK 開發】Android Studio 使用 CMake 導入靜態庫 ( CMake 簡介 | 構建腳本路徑配置 | 引入靜態庫 | 指定靜態庫路徑 | 鏈接動態庫 )

博客資源下載地址 : https://download.csdn.net/download/han1202012/12162132

示例代碼 GitHub 地址 : https://github.com/han1202012/008_NDK_CMake_Static

發佈了274 篇原創文章 · 獲贊 1018 · 訪問量 168萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章