Android-CMake語法

前言

Android NDK以前默認(rèn)使用Android.mk與Application.mk進(jìn)行構(gòu)建温峭,但是在Android Studio2.2之后推薦使用CMake進(jìn)行編譯。
CMake是跨平臺編譯工具胖秒,全稱為cross platform make,內(nèi)建c慕的、c++阎肝、java自動相依性分析功能。NDK通過工具鏈支持CMake肮街,
工具鏈文件是用于自定義交叉編譯工具鏈的CMake文件风题。用于NDK的工具鏈位于/build/cmake/android.toolchain.cmake,
關(guān)于CMake更多詳情請參考官網(wǎng):cmake官網(wǎng)嫉父。下面對比下Android.mk與CMakeLists.txt的語法沛硅。
更詳細(xì)腳本分析可查看博客:NDK編譯腳本分析

一、Android.mk語法

以動態(tài)庫編譯hello模塊為例绕辖,完整腳本如下:

WORKING_DIR := $(call my-dir)
LOCAL_PATH := $(WORKING_DIR)

include $(CLEAR_VARS)
LOCAL_ARM_MODE  := arm
LOCAL_MODULE    := libffmpeg
LOCAL_SRC_FILES := $(LOCAL_PATH)/ffmpeg/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_ARM_MODE  := arm
#模塊名稱
LOCAL_MODULE    := hello
#源文件
LOCAL_SRC_FILES := hello.c
#頭文件路徑
LOCAL_C_INCLUDES := $(LOCAL_PATH)
#系統(tǒng)庫依賴
LOCAL_LDLIBS    := -llog -lz -lm -landroid
#第三方動態(tài)庫
LOCAL_SHARED_LIBRARIES := libffmpeg
#以動態(tài)庫形式編譯
include $(BUILD_SHARED_LIBRARY)

1摇肌、LOCAL_MODULE

聲明模塊名稱,例如這里編譯出來的動態(tài)庫名稱為libhello.so仪际。

2围小、LOCAL_SRC_FILES

聲明源文件列表,文件之間用空格分開树碱,需要換行時使用''換行符肯适。

3、LOCAL_C_INCLUDES

聲明頭文件路徑成榜,例如$(LOCAL_PATH)/xxx

4疹娶、LOCAL_CPP_EXTENSION

指定C++源文件除.cpp以外的文件擴展名,例如這樣LOCAL_CPP_EXTENSION := .cpp .cxx .cc

5伦连、LOCAL_CPP_FEATURES

指定依賴c++的某些功能雨饺,例如RTTI(運行時類型信息): LOCAL_CPP_FEATURES := rtti 使用c++異常檢測: LOCAL_CPP_FEATURES := exceptions

6钳垮、LOCAL_CFLAGS

在編譯c和c++源文件時編譯系統(tǒng)要傳遞的編譯器標(biāo)記,即指定額外的宏定義或編譯選項额港。 LOCAL_CFLAGS += -I

7饺窿、LOCAL_STATIC_LIBRARIES

共享靜態(tài)庫,作為第三方庫被引用 LOCAL_STATIC_LIBRARIES := libavcodec libavutil libavformat libavfilter

8移斩、LOCAL_SHARED_LIBRARIES

共享動態(tài)庫肚医,與共享靜態(tài)庫一樣作為第三方庫被引用 LOCAL_SHARED_LIBRARIES := libffmpeg

9、LOCAL_LDLIBS

額外鏈接器向瓷,一般為系統(tǒng)庫肠套,使用-l來引用 LOCAL_LDLIBS := -lz -lm

10、 LOCAL_ARM_MODE

ndk默認(rèn)使用thumb模式來生成目標(biāo)二進(jìn)制文件猖任,每條指令為16位寬你稚。也可以指定為ARM模式,來生成32位ARM的目標(biāo)文件:
LOCAL_ARM_MODE := arm

11朱躺、LOCAL_ARM_NEON

用于開啟NEON指令加速刁赖,僅對armeabi-v7a平臺有效。為模塊開啟NEON: LOCAL_ARM_NEON := true 為單獨源文件開啟NEON: LOCAL_SRC_FILES := hello.c.neon

12长搀、TARGET_ARCH

用于指向CPU架構(gòu)宇弛,包括x86、x86_64源请、armeabi-v7a枪芒、 arm64-v8a

13、TARGET_PLATFORM

目標(biāo)平臺谁尸,對應(yīng)Android API級別號病苗,例如Android5.0系統(tǒng)鏡像對應(yīng)Android API級別21:android-21

14、打印信息

可用warning症汹、debug、info贷腕、error級別來打印信息背镇,如果是打印error信息,會終止編譯泽裳。以warning為例: $(warning 'This is a test')

15瞒斩、if條件判斷

采用ifeq關(guān)鍵字,然后左右變量放在括號體內(nèi)涮总,用逗號分隔:

ifeq($(TARGET_ABI), arm64-v8a)
$(debug 'This is arm64-v8a')
endif

二胸囱、Application.mk語法

Android.mk依賴Application.mk文件進(jìn)行編譯,一般Application.mk腳本如下所示:

APP_STL      := c++_static
APP_DEBUG    := false
APP_OPTIM    := release
APP_CPPFLAGS := -frtti
APP_PLATFORM := android-16
APP_ABI      := armeabi-v7a arm64-v8a

1瀑梗、APP_ABI

與Android.mk的TARGET_ABI對應(yīng)烹笔,包括CPU架構(gòu)有:x86裳扯、x86_64、armeabi-v7a谤职、arm64-v8a饰豺,支持所有平臺這樣表示:
APP_ABI := all

2、APP_BUILD_SCRIPT

指向編譯腳本的路徑允蜈,一般Android.mk和Application.mk都位于jni目錄冤吨,默認(rèn)指向jni/Android.mk路徑,如果是其他路徑饶套,
需要使用此變量來指定絕對路徑: APP_BUILD_SCRIPT := /xx/xx/Android.mk

3漩蟆、APP_OPTIM

編譯優(yōu)化選項,調(diào)試模式為debug妓蛮,發(fā)布模式為release怠李。在調(diào)試模式下,會保留symbol符號表仔引;在發(fā)布模式下扔仓,會開啟優(yōu)化,去掉symbol符號表咖耘。

4翘簇、APP_PLATFORM

指定編譯平臺,面向于Android API級別儿倒,對應(yīng)gradle聲明的minSdkVersion版保。如果不聲明,默認(rèn)為ndk支持的最低API版本

5夫否、APP_STL

聲明使用c++的標(biāo)準(zhǔn)庫彻犁,默認(rèn)為system STL。其他選項包括c++_static凰慈、c++_shared和none

三汞幢、CMakeLists.txt語法

以編譯hello模塊以及依賴ffmpeg模塊為例:

cmake_minimum_required(VERSION 3.4.1)
#添加動態(tài)庫,包含源文件路徑
add_library( hello
             SHARED
             src/main/jni/hello.c)
#添加第三方動態(tài)庫
add_library( ffmpeg
             SHARED
             IMPORTED )
#指定第三方庫路徑
set_target_properties( ffmpeg
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libffmpeg.so )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#指定頭文件路徑
include_directories(src/main/cpp)
if(${CMAKE_ANDROID_ARCH_ABI} MATCHES "armeabi-v7a")
    include_directories(src/main/cpp/include/armeabi-v7a)
    message("This is armeabi-v7a")
elseif(${CMAKE_ANDROID_ARCH_ABI} MATCHES "arm64-v8a")
    include_directories(src/main/cpp/include/arm64-v8a)
    message("This is arm64-v8a")
endif()
#查找系統(tǒng)庫
find_library( # Sets the name of the path variable.
              log-lib
              log )
#鏈接目標(biāo)庫
target_link_libraries( hello
                       ffmpeg
                       ${log-lib} )

1微谓、add_library

傳遞三個參數(shù)森篷,第一個參數(shù)是模塊名稱,第二個參數(shù)是SHARED或者STATIC豺型。如果是源文件模塊仲智,第三個參數(shù)是源文件列表;
如果是第三方庫姻氨,第三個參數(shù)是IMPORTED钓辆。

2、set_target_properties

用于指定第三方庫路徑,IMPORT_LOCATION一般是指向src/main/cpp目錄

3前联、include_directories

用于指定頭文件路徑功戚,頭文件路徑可以有多個

4、find_library

用于查找系統(tǒng)庫蛀恩,比如Android系統(tǒng)的log日志庫

5疫铜、target_link_libraries

鏈接目標(biāo)庫,把依賴庫都鏈接到目標(biāo)庫中

6双谆、if條件判斷

與Android.mk稍有差異壳咕,CMake采用if...MATCHES形式,例如: if(${CMAKE_ANDROID_ARCH_ABI} MATCHES "armeabi-v7a") ...... endif()

7顽馋、打印日志

與Android.mk不同的是谓厘,CMake采用message函數(shù)來打印日志,括號體傳入msg內(nèi)容 message("hello, cmake")

8寸谜、命令行參數(shù)

命令行參數(shù)前面統(tǒng)一加上-D竟稳,常用的參數(shù):

  • -DANRDOID_ABI :android的ABI架構(gòu)平臺

  • -DANDROID_NDK :ndk路徑

  • -DANDROID_ARM_MODE :arm模式/thumb模式

  • -DANDROID_ARM_NEON :是否開啟arm neon加速,針對armeabi-v7a平臺

  • -DANDROID_TOOLCHAIN :編譯工具鏈

  • -DANDROID_NATIVE_API_LEVEL :與ANDROID_PLATFORM相同熊痴,對應(yīng)minSdkVersion

  • -DCMAKE_BUILD_TYPE :編譯類型他爸,debug或release

  • -DCMAKE_MAKE_PROGRAM :編譯程序

  • -DCMAKE_TOOLCHAIN_FILE :編譯文件

9、命令行編譯

以cmake作為關(guān)鍵字果善,后面帶著指定參數(shù)诊笤,示例如下:

    cmake \
    -DANDROID_ABI=armeabi-v7a \
    -DANDROID_NDK=${HOME}/Android/Sdk/ndk-bundle \
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.6.3155560/bin/ninja \
    -DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake \
    -DANDROID_NATIVE_API_LEVEL=23 \
    -DANDROID_TOOLCHAIN=clang

四、ndk編譯配置

1巾陕、Android.mk方式配置

在gradle的defaultConfig配置ndk:

defaultConfig {
    ......
    ndk {
        moduleName "hello"
        abiFilters "armeabi-v7a", "arm64-v8a"
    }
}

然后配置jni源文件路徑:

sourceSets {
    main {
        jniLibs.srcDir 'src/main/libs' // Enable to use libs
        jni.srcDirs 'src/main/jni' // Enable the automatic ndk-build
    }
}

另外配置Android.mk文件絕對路徑:

externalNativeBuild {
    ndkBuild {
        "src/main/jni/Android.mk"
    }
}

2讨跟、CMake方式配置

前兩步與Android.mk方式一樣,配置腳本路徑稍有差異:

externalNativeBuild {
    cmake {
        path "CMakeLists.txt"
    }
}

另外在defaultConfig設(shè)置cppFlags:

externalNativeBuild {
    cmake {
        cppFlags ""
    }
}

五鄙煤、ndk編譯過程

1晾匠、ndk-build編譯

在命令行輸入ndk-build后,會根據(jù)聲明所支持的平臺依次編譯梯刚。首先是armeabi-v7a平臺架構(gòu)凉馆,把hello.c源文件編譯成hello
目標(biāo)文件,然后鏈接成libhello.so動態(tài)庫亡资,最終安裝到libs/armeabi-v7a目錄下澜共。

2、cmake在Gradle中編譯

編譯arm64-v8a平臺架構(gòu)的hello模塊沟于。首先把hello.c源文件編譯成hello.c.o目標(biāo)文件,然后鏈接成libhello.so動態(tài)庫植康。
生成的debug模式動態(tài)庫在/build/intermediates/cmake/debug/obj/arm64-v8a目錄下旷太。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子供璧,更是在濱河造成了極大的恐慌存崖,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睡毒,死亡現(xiàn)場離奇詭異来惧,居然都是意外死亡,警方通過查閱死者的電腦和手機演顾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門供搀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钠至,你說我怎么就攤上這事葛虐。” “怎么了棉钧?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵屿脐,是天一觀的道長。 經(jīng)常有香客問我宪卿,道長的诵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任佑钾,我火速辦了婚禮西疤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘次绘。我一直安慰自己瘪阁,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布邮偎。 她就那樣靜靜地躺著管跺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪禾进。 梳的紋絲不亂的頭發(fā)上豁跑,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音泻云,去河邊找鬼艇拍。 笑死,一個胖子當(dāng)著我的面吹牛宠纯,可吹牛的內(nèi)容都是我干的卸夕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼婆瓜,長吁一口氣:“原來是場噩夢啊……” “哼快集!你這毒婦竟也來了贡羔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤个初,失蹤者是張志新(化名)和其女友劉穎乖寒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體院溺,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡楣嘁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了珍逸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逐虚。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖弄息,靈堂內(nèi)的尸體忽然破棺而出痊班,到底是詐尸還是另有隱情,我是刑警寧澤摹量,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布涤伐,位于F島的核電站,受9級特大地震影響缨称,放射性物質(zhì)發(fā)生泄漏凝果。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一睦尽、第九天 我趴在偏房一處隱蔽的房頂上張望器净。 院中可真熱鬧,春花似錦当凡、人聲如沸山害。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浪慌。三九已至,卻和暖如春朴则,著一層夾襖步出監(jiān)牢的瞬間权纤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工乌妒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留汹想,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓撤蚊,卻偏偏與公主長得像古掏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子侦啸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容