天天看點

Android Studio上Cmake的搭建與使用—以生成動态/靜态庫1、什麼是Cmake?2、什麼是NDK?3、如何導入NDK與Cmake環境?4、如何在已有AS項目中導入Cmake?5、Cmake常用文法介紹6、簡單寫個JNI驗證目标庫是否生成可用

1、什麼是Cmake?

​ C/C++ 的編譯檔案在不同平台是不一樣的。Unix 下使用 makefile 檔案編譯,Windows 下使用 project 檔案編譯。而 CMake 則是一個跨平台的編譯工具,它并不會直接編譯出對象,而是根據自定義的語言規則(CMakeLists.txt)生成 對應 makefile 或 project 檔案,然後再調用底層的編譯.

​ 谷歌從AndroidStudio2.2以上就添加了Cmake方式來編譯NDK代碼,相較之前複雜的NDK-BUILDE方式,Cmake則簡單很多。

2、什麼是NDK?

​ NDK全名Native Develop Kit,andriod本地開發工具,是Google開發的一套友善開發者在Android 平台上開發Native 代碼的工具;

​ 使用NDK自帶的工具,可快速對C/C++代碼進行建構、編譯和打包,最終生成動态/靜态庫供開發者使用,且不容易被反編譯;

3、如何導入NDK與Cmake環境?

3.1在Setting的Android SDK中勾選以下配置;

Android Studio上Cmake的搭建與使用—以生成動态/靜态庫1、什麼是Cmake?2、什麼是NDK?3、如何導入NDK與Cmake環境?4、如何在已有AS項目中導入Cmake?5、Cmake常用文法介紹6、簡單寫個JNI驗證目标庫是否生成可用

3.2 因為Cmake要用到NDK,是以Android NDK location需要指定本地NDK路徑;

Android Studio上Cmake的搭建與使用—以生成動态/靜态庫1、什麼是Cmake?2、什麼是NDK?3、如何導入NDK與Cmake環境?4、如何在已有AS項目中導入Cmake?5、Cmake常用文法介紹6、簡單寫個JNI驗證目标庫是否生成可用

4、如何在已有AS項目中導入Cmake?

4.1導入Cmake相關檔案;

​ 路徑可以自定義,這裡選擇的是"app/src/main/cpp/",其中CMakeLists.txt是Cmake的執行腳本, test-jni.c是Jni檔案,用于編譯生成so庫;

Android Studio上Cmake的搭建與使用—以生成動态/靜态庫1、什麼是Cmake?2、什麼是NDK?3、如何導入NDK與Cmake環境?4、如何在已有AS項目中導入Cmake?5、Cmake常用文法介紹6、簡單寫個JNI驗證目标庫是否生成可用

4.2. app工程關聯Cmake

​ 打開app目錄下的build.gradle(見上圖紅框),添加以下語句,使AS工程關聯上Cmake用于編譯;

​ 參考網址: https://www.cnblogs.com/qcjd/p/9324903.html

android{
 	...
     defaultConfig {
     	...
         externalNativeBuild {
            cmake {
                cppFlags ""
       			
			  // Passes optional arguments to CMake.//編譯選項,與makefile類似
	           //arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"

			  // Sets optional flags for the C compiler.預置C的宏
			  //cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"

			  // Sets a flag to enable format macro constants for the C++ compiler.預置C++的宏
			  //cppFlags "-D__STDC_FORMAT_MACROS"
            }
        }
        ndk {//編譯生成哪個CPU平台的庫
            abiFilters 'armeabi-v7a','x86_64'
            //    ARMv5——armeabi
            //    ARMv7 ——armeabi-v7a
            //    ARMv8——arm64- v8a
            //    x86——x86
            //    MIPS ——mips
            //    MIPS64——mips64
            //    x86_64——x86_64
        }
    }
    ...
    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')  //CMakeLists.txt存放路徑
            version "3.10.2"
        }
   }
   ...
}
           

5、Cmake常用文法介紹

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

project(NDK)
###############參考網址:https://www.cnblogs.com/qcjd/p/9324903.html


# ==========================================文法知識(start)=====================================
# 0==================<多檔案編譯生成庫>=============================
#1、 設定多檔案目錄---方法1: (常用)
#1.1查找src/main/cpp目錄下所有以*./c *.cpp檔案并儲存到DIR_SRCS變量裡
file(GLOB DIR_SRCS “src/main/cpp/*.c” “src/main/cpp/*.cpp”)

#1.2不同級目錄下的指定
file(GLOB DIR_SRCS “../src2/main/cpp/*.c” “../src3/main/cpp/*.cpp”)

#1.3如果cpp目錄下還有别的子目錄,但又不想每個子目錄路徑都制定過來,則可以用到遞歸查找
file(GLOB_RECURSE SRC_FILES "src/hello*")#注意:這裡的目錄不能有特殊字元,例如:<SerialPort_c>

#2、設定多檔案目錄---方法2:指定目前目錄下的源檔案,儲存到<DIR_SRCS>變量中
aux_source_directory(. DIR_SRCS)

#3、關聯1或2中的DIR_SRCS變量,生成庫
# # SHARED: 動态庫  STATIC:靜态庫、
add_library(hello-jni SHARED ${DIR_SRCS})

# 制定生成目标(可忽略)
add_executable(mathPowerDemo2 ${ALL_SRCS})

# ==================<引入已有預編譯好的靜态庫/動态庫>=========================
# 1.1、引入已有的預編譯好的靜态庫
# StaticTest 可以随便起名字(原名:libStaticTest.a)
# IMPORTED: 表示靜态庫是以導入的形式添加進來(預編譯靜态庫)
add_library(StaticTest STATIC IMPORTED)

# 1.2、引入已有的預編譯好的動态庫
# SharedTest 可以随便起名字(原名:libSharedTest.so)
# IMPORTED: 表示靜态庫是以導入的形式添加進來(預編譯靜态庫)
add_library(SharedTest SHARED IMPORTED)

# 2.1、設定1.1/1.2中指定的動态庫/靜态庫的導入路徑
# 下面CMAKE_SOURCE_DIR 是系統預定義好的變量,代表目前CMakeLists.txt所在的目錄
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/static/armeabi-v7a/libStaticTest.a)

#下面${ANDROID_ABI}中的ANDROID_ABI應該指各個ABI版本的目錄
# othermodule為庫名稱
set_target_properties(othermodule  PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libothermodule.so)

#    各個ABI版本
#    ARMv5——armeabi
#    ARMv7 ——armeabi-v7a
#    ARMv8——arm64- v8a
#    x86——x86
#    MIPS ——mips
#    MIPS64——mips64
#    x86_64——x86_64

# 2.2、設定動态庫的導入路徑
# 下面CMAKE_SOURCE_DIR 是系統預定義好的變量,代表目前CMakeLists.txt所在的目錄
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/static/armeabi-v7a/libSharedTest.so)


# 3.1 額外頭檔案查找路徑設定 相當于makefile中的-I
include_directories(src/main/include)//本地或者外部庫需要的頭檔案路徑指定

# 3.2 使用其餘CMakeLists.txt配置
# 額外引入src/main/subcmakelist目錄的cmakelist
add_subdirectory(src/main/subcmakelist)

# 3.3 增加指定的宏定義 相當于-D
add_definitions(-D_LINUX -D_ANDROID)

     

# 4、配置動态庫連結,生成native-lib動态庫需要用到StaticTest log動态或者靜态庫
target_link_libraries( # Specifies the target library.
                        native-lib
                        # libTest.so 可以去掉lib與.so
                        StaticTest
                        SharedTest
                        log )

# 動态庫這樣引入沒有版本差異,如果像上面那樣引入會有版本問題
# CMAKE_CXX_FLAGS 會傳給c++編譯器
# CMAKE_C_FLAGS 會傳給c編譯器
# CMAKE_SOURCE_DIR 的值是目前CMakelist.txt所在目錄
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a")
# ===========================================文法知識(end)========================================



# ===========================================使用範本========================================
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

# 配置so庫資訊
add_library( # Sets the name of the library.
            # 生成的so庫名稱,此處生成的so檔案名稱是libnative-lib.so
             native-lib

             # Sets the library as a shared library.
             # STATIC:靜态庫,是目标檔案的歸檔檔案,在連結其它目标的時候使用
             # SHARED:動态庫,會被動态連結,在運作時被加載
             # MODULE:子產品庫,是不會被連結到其它目标中的插件,但是可能會在運作時使用dlopen-系列的函數動态連結
             SHARED

             # Provides a relative path to your source file(s).
             # 資源檔案,可以多個,
             # 資源路徑是相對路徑,相對于本CMakeLists.txt所在目錄
             src/maind/jni/XJni.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

# 從系統查找依賴庫
find_library( # Sets the name of the path variable.
              # android系統每個類型的庫會存放一個特定的位置,而log庫存放在log-lib中
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              # android系統在c環境下打log到logcat的庫
              log )

# 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( # Specifies the target library.

                       # 目标庫
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       # 依賴于
                       ${log-lib} )
           

6、簡單寫個JNI驗證目标庫是否生成可用

6.1在cpp目錄下簡單寫個jni

Android Studio上Cmake的搭建與使用—以生成動态/靜态庫1、什麼是Cmake?2、什麼是NDK?3、如何導入NDK與Cmake環境?4、如何在已有AS項目中導入Cmake?5、Cmake常用文法介紹6、簡單寫個JNI驗證目标庫是否生成可用

6.2 點選make project(Ctrl+F9)後檢視目标庫是否生成

Android Studio上Cmake的搭建與使用—以生成動态/靜态庫1、什麼是Cmake?2、什麼是NDK?3、如何導入NDK與Cmake環境?4、如何在已有AS項目中導入Cmake?5、Cmake常用文法介紹6、簡單寫個JNI驗證目标庫是否生成可用

6.3 更多技術文章可關注本人公衆号

Android Studio上Cmake的搭建與使用—以生成動态/靜态庫1、什麼是Cmake?2、什麼是NDK?3、如何導入NDK與Cmake環境?4、如何在已有AS項目中導入Cmake?5、Cmake常用文法介紹6、簡單寫個JNI驗證目标庫是否生成可用