Android JNI—Android.mk詳解

看一個(gè)簡(jiǎn)單的Android.mk的例子:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello-jni

LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

例子說(shuō)明

LOCAL_PATH:=$(call my-dir)

Android.mk文件首先必須要指定LOCAL_PATH變量,用于查找源文件。一般情況下Android.mk和需要編譯的源文件在同一目錄下。上面的語(yǔ)句的意思是將LOCAL_PATH變量定義成本文件所在目錄路徑。

**include (CLEAR_VARS)**<br> Android.mk中可以定義多個(gè)編譯模塊,每個(gè)編譯模塊都是以include(CLEAR_VARS)開(kāi)始,以include $(BUILD_XXX)結(jié)束。

CLEAR_VARS由編譯系統(tǒng)提供,指定讓GNU MAKEFILE為你清除除LOCAL_PATH以外的所有LOCAL_XXX變量,清除它們可以避免沖突,每一個(gè)原生組件被稱(chēng)為一個(gè)模塊。如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_SHARED_LIBRARIES,LOCAL_STATIC_LIBRARIES等。

LOCAL_MODULE := hello-jni

LOCAL_MODULE模塊必須定義,以表示Android.mk中的每一個(gè)模塊。名字必須唯一且不包含空格。Build System會(huì)自動(dòng)添加適當(dāng)?shù)那熬Y和后綴。例如,foo,要產(chǎn)生動(dòng)態(tài)庫(kù),則生成libfoo.so. 但請(qǐng)注意:如果模塊名被定為:libfoo.則生成libfoo.so. 不再加前綴。

LOCAL_SRC_FILES:= hello-jni.c

LOCAL_SRC_FILES變量必須包含將要打包如模塊的C/C++ 源碼。不必列出頭文件,build System 會(huì)自動(dòng)幫我們找出依賴(lài)文件。缺省的C++源碼的擴(kuò)展名為.cpp. 也可以修改,通過(guò)LOCAL_CPP_EXTENSION。

**include (BUILD_XXX)**<br> BUILD_XXX是Build System提供的一個(gè)變量,指向一個(gè)GNU Makefile Script。它負(fù)責(zé)收集自從上次調(diào)用 include(CLEAR_VARS)后的所有LOCAL_XXX信息。并決定編譯為什么。

BUILD_SHARED_LIBRARY:將你列出的Source編譯成一個(gè)動(dòng)態(tài)庫(kù)。注意,在包含此文件前,至少應(yīng)該包含:LOCAL_MODULE and LOCAL_SRC_FILES 。

BUILD_STATIC_LIBRARY:將你列出的Source編譯成一個(gè)靜態(tài)庫(kù)。靜態(tài)庫(kù)不能夠加入到Project 或者APK中。但它可以用來(lái)生成動(dòng)態(tài)庫(kù)。。

BUILD_EXECUTABLE:編譯為Native C可執(zhí)行程序

變量說(shuō)明


NDK Build System變量

CLEAR_VARS

指向一個(gè)編譯腳本。必須在新模塊前包含之。

include $(CLEAR_VARS)

BUILD_SHARED_LIBRARY

指向一個(gè)編譯腳本,它收集自從上次調(diào)用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。
并決定如何將你列出的Source編譯成一個(gè)動(dòng)態(tài)庫(kù)。 注意,在包含此文件前,至少應(yīng)該包含:LOCAL_MODULE and LOCAL_SRC_FILES 例如:

include $(BUILD_SHARED_LIBRARY)

BUILD_STATIC_LIBRARY

與前面類(lèi)似,它也指向一個(gè)編譯腳本,
收集自從上次調(diào)用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。
并決定如何將你列出的Source編譯成一個(gè)靜態(tài)庫(kù)。 靜態(tài)庫(kù)不能夠加入到Project 或者APK中。但它可以用來(lái)生成動(dòng)態(tài)庫(kù)。
LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES將描述之。

include $(BUILD_STATIC_LIBRARY)

BUILD_EXECUTABLE

與前面類(lèi)似,它也指向一個(gè)編譯腳本,收集自從上次調(diào)用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。
并決定如何將你列出的Source編譯成一個(gè)可執(zhí)行Native程序。

include $(BUILD_EXECUTABLE)

PREBUILT_SHARED_LIBRARY

把這個(gè)共享庫(kù)聲明為 “一個(gè)” 獨(dú)立的模塊。
指向一個(gè)build 腳本,用來(lái)指定一個(gè)預(yù)先編譯好多動(dòng)態(tài)庫(kù)。 與BUILD_SHARED_LIBRARY and BUILD_STATIC_LIBRARY不同,
此時(shí)模塊的LOCAL_SRC_FILES應(yīng)該被指定為一個(gè)預(yù)先編譯好的動(dòng)態(tài)庫(kù),而非source file. LOCAL_PATH := $(call my-dir)

include (CLEAR_VARS)<br> <br> LOCAL_MODULE := foo-prebuilt # 模塊名<br> LOCAL_SRC_FILES := libfoo.so # 模塊的文件路徑(相對(duì)于 LOCAL_PATH)<br> <br> include(PREBUILT_SHARED_LIBRARY) # 注意這里不是 BUILD_SHARED_LIBRARY

這個(gè)共享庫(kù)將被拷貝到 PROJECT/obj/local 和PROJECT/libs/<abi> (stripped) 主要是用在將已經(jīng)編譯好的第三方庫(kù)
使用在本Android Project中。為什么不直接將其COPY到libs/armabi目錄呢?因?yàn)檫@樣做缺陷很多。下一節(jié)再詳細(xì)說(shuō)明。

PREBUILT_STATIC_LIBRARY

預(yù)先編譯的靜態(tài)庫(kù)。同上。

TARGET_ARCH

目標(biāo)CPU架構(gòu)名。如果為“arm” 則聲稱(chēng)ARM兼容的指令。與CPU架構(gòu)版本無(wú)關(guān)。

TARGET_PLATFORM

目標(biāo)平臺(tái)的名字。

TARGET_ARCH_ABI

Name of the target CPU+ABI
armeabi For ARMv5TE armeabi-v7a

TARGET_ABI

目標(biāo)平臺(tái)和 ABI 的組合



NDK提供的功能宏

GNU Make 提供的功能宏,只有通過(guò)類(lèi)似: $(call function) 的方式來(lái)得到其值,它將返回文本化的信息。

my-dir: $(call my-dir)

返回最近一次include的Makefile的路徑。通常返回Android.mk所在的路徑。它用來(lái)作為Android.mk的開(kāi)頭來(lái)定義LOCAL_PATH.

LOCAL_PATH := $(call my-dir)

請(qǐng)注意:返回的是最近一次include的Makefile的路徑。所以在Include其它Makefile后,再調(diào)用$(call my-dir)會(huì)返回其它Android.mk 所在路徑。例如:

LOCAL_PATH := (call my-dir) ... declare one module <br> include(LOCAL_PATH)/foo/Android.mk

LOCAL_PATH := $(call my-dir) ... declare another module

則第二次返回的LOCAL_PATH 為:PATH/foo。 而非PATH.

all-subdir-makefiles

返回一個(gè)列表,包含'my-dir'中所有子目錄中的Android.mk。如結(jié)構(gòu)如下:

sources/foo/Android.mk sources/foo/lib1/Android.mk sources/foo/lib2/Android.mk

在If sources/foo/Android.mk 中, include $(call all-subdir-makefiles) 那則自動(dòng)include 了sources/foo/lib1/Android.mk and sources/foo/lib2/Android.mk。

this-makefile

當(dāng)前Makefile的路徑。

parent-makefile

返回include tree中父Makefile 路徑。 也就是include 當(dāng)前Makefile的Makefile Path。

import-module

允許尋找并inport其它modules到本Android.mk中來(lái)。 它會(huì)從NDK_MODULE_PATH尋找指定的模塊名。
$(call import-module,<name>)



模塊描述變量

此類(lèi)變量用來(lái)給Build System描述模塊信息。在'include (CLEAR_VARS)' 和 'include(BUILD_XXXXX)'之間。必須定義此類(lèi)變量。
include (CLEAR_VARS) script用來(lái)清空這些變量。 include(BUILD_XXXXX)收集和使用這些變量。

LOCAL_PATH

這個(gè)值用來(lái)給定當(dāng)前目錄。必須在Android.mk的開(kāi)是位置定義之。
例如: LOCAL_PATH := (call my-dir) LOCAL_PATH不會(huì)被include(CLEAR_VARS) 清理。

LOCAL_MODULE

modules名。在include $(BUILD_XXXXX)之前,必須定義這個(gè)變量。此變量必須唯一且不能有空格。
通常,由此變量名決定最終生成的目標(biāo)文件名。

LOCAL_MODULE_FILENAME

可選。用來(lái)override LOCAL_MODULE. 即允許用戶重新定義最終生成的目標(biāo)文件名。
LOCAL_MODULE := foo-version-1 LOCAL_MODULE_FILENAME := libfoo

LOCAL_SRC_FILES

為Build Modules而提供的Source 文件列表。不需要列出依賴(lài)文件。 注意:文件相對(duì)于LOCAL_PATH存放,
且可以提供相對(duì)路徑。 例如:
LOCAL_SRC_FILES := foo.c \ toto/bar.c

LOCAL_CPP_EXTENSION

指出C++ 擴(kuò)展名。(可選)
LOCAL_CPP_EXTENSION := .cxx 從NDK R7后,可以寫(xiě)多個(gè):
LOCAL_CPP_EXTENSION := .cxx .cpp .cc

LOCAL_CPP_FEATURES

可選。用來(lái)指定C++ features。
LOCAL_CPP_FEATURES := rtti
LOCAL_CPP_FEATURES := exceptions

LOCAL_C_INCLUDES

一個(gè)可選的path列表。相對(duì)于NDK ROOT 目錄。編譯時(shí),將會(huì)把這些目錄附上。
LOCAL_C_INCLUDES := sources/foo LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

LOCAL_CFLAGS

一個(gè)可選的設(shè)置,在編譯C/C++ source 時(shí)添加如Flags。
用來(lái)附加編譯選項(xiàng)。 注意:不要嘗試在此處修改編譯的優(yōu)化選項(xiàng)和Debug等級(jí)。它會(huì)通過(guò)您Application.mk中的信息自動(dòng)指定。
也可以指定include 目錄通過(guò):LOCAL_CFLAGS += -I<path>。 這個(gè)方法比使用LOCAL_C_INCLUDES要好。因?yàn)檫@樣也可以被ndk-debug使用。

LOCAL_CXXFLAGS

LOCAL_CPPFLAGS的別名。

LOCAL_CPPFLAGS

C++ Source 編譯時(shí)添加的C Flags。這些Flags將出現(xiàn)在LOCAL_CFLAGS flags 的后面。

LOCAL_STATIC_LIBRARIES

要鏈接到本模塊的靜態(tài)庫(kù)list。(built with BUILD_STATIC_LIBRARY)

LOCAL_SHARED_LIBRARIES

要鏈接到本模塊的動(dòng)態(tài)庫(kù)。

LOCAL_WHOLE_STATIC_LIBRARIES

靜態(tài)庫(kù)全鏈接。 不同于LOCAL_STATIC_LIBRARIES,類(lèi)似于使用--whole-archive

LOCAL_LDLIBS

linker flags。 可以用它來(lái)添加系統(tǒng)庫(kù)。 如 -lz:
LOCAL_LDLIBS := -lz

LOCAL_ALLOW_UNDEFINED_SYMBOLS

LOCAL_ARM_MODE

缺省模式下,ARM目標(biāo)代碼被編譯為thumb模式。每個(gè)指令16位。如果指定此變量為:arm。 則指令為32位。
LOCAL_ARM_MODE := arm 其實(shí)也可以指定某一個(gè)或者某幾個(gè)文件的ARM指令模式。

LOCAL_ARM_NEON

設(shè)置為true時(shí),會(huì)講浮點(diǎn)編譯成neon指令。這會(huì)極大地加快浮點(diǎn)運(yùn)算(前提是硬件支持)
只有targeting 為 'armeabi-v7a'時(shí)才可以。

LOCAL_DISABLE_NO_EXECUTE

LOCAL_EXPORT_CFLAGS

定義這個(gè)變量用來(lái)記錄C/C++編譯器標(biāo)志集合,
并且會(huì)被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模塊的LOCAL_CFLAGS定義中
LOCAL_SRC_FILES := foo.c bar.c.arm

Application.mk變量

用于描述app需要的native model。

APP_PROJECT_PATH

這個(gè)變量存儲(chǔ)應(yīng)用程序的項(xiàng)目根目錄的絕對(duì)路徑。

APP_OPTIM

配置release和debug

APP_CFLAGS

這個(gè)變量存儲(chǔ)一組構(gòu)建系統(tǒng)的C編譯器標(biāo)志傳遞給編譯器編譯任何C或c++源代碼的任何模塊,可以修改應(yīng)用需要的構(gòu)建模塊而不用修改Android.mk文件

APP_CPPFLAGS

和 APP_CFLAGS類(lèi)似

APP_LDFLAGS

A set of linker flags that the build system passes when linking the application,只對(duì) shared libraries 和 executables有效

APP_BUILD_SCRIPT

指定Android.mk文件

APP_ABI

指定abi

APP_PLATFORM

指定android api版本

APP_STL

鏈接其他的c++支持

NDK_TOOLCHAIN_VERSION

gcc編譯版本

APP_PIE

APP_THIN_ARCHIVE

常用構(gòu)建系統(tǒng)變量

構(gòu)建共享庫(kù)

為了建立可供主應(yīng)用程序使用的模塊,必須將該模塊變成共享庫(kù)。Android NDK構(gòu)建系統(tǒng)將BUILD_STATIC_LIBRARY變量設(shè)置成build-shared-library.mk文件的保存位置。

include $(BUILD_STATIC_LIBRARY)

構(gòu)建多個(gè)共享庫(kù)

基于不同應(yīng)用程序的體系結(jié)構(gòu),一個(gè)單獨(dú)的Android.mk文件可能產(chǎn)生多個(gè)共享庫(kù)模塊,為了達(dá)到這個(gè)目的,需要在Android.mk文檔中定義多個(gè)模塊。例如:

LOCAL_PATH := $(call my-dir)


模塊1



include (CLEAR_VARS)<br> LOCAL_MODULE := hello-jni1<br> LOCAL_SRC_FILES := hello-jni1.c<br> <br> include(BUILD_SHARED_LIBRARY)


模塊2



include (CLEAR_VARS)<br> LOCAL_MODULE := hello-jni2<br> LOCAL_SRC_FILES := hello-jni2.c<br> <br> include(BUILD_SHARED_LIBRARY)

在處理完這個(gè)Android.mk構(gòu)建文檔之后,Android NDK構(gòu)建系統(tǒng)會(huì)產(chǎn)生libhello-jni1.so和libhello-jni2.so兩個(gè)共享庫(kù)。

構(gòu)建靜態(tài)庫(kù)

Android NDK構(gòu)建系統(tǒng)也支持靜態(tài)庫(kù),靜態(tài)庫(kù)可以用來(lái)構(gòu)建共享庫(kù),例如,在將第三方代碼添加到現(xiàn)有原生項(xiàng)目中,不用直接將第三方源代碼包括在原生項(xiàng)目中,而是將第三方代碼編譯成靜態(tài)庫(kù),然后并入共享庫(kù)。

LOCAL_PATH := $(call my-dir)


第三方AVI庫(kù)

include (CLEAR_VARS) <br> <br> LOCAL_MODULE := avilib <br> LOCAL_SRC_FILES := avilib.c <br> <br> include(BUILD_SHARED_LIBRARY)


原生模塊

include (CLEAR_VARS) <br> <br> LOCAL_MODULE := hello-jni <br> LOCAL_SRC_FILES := hello-jni.c <br> <br> LOCAL_SHARED_LIBRARIES:=avilib <br> <br> include(BUILD_SHARED_LIBRARY)

將第三方代碼模塊生成靜態(tài)庫(kù)后,共享庫(kù)就可以通過(guò)將它的模塊名稱(chēng)添加到LOCAL_SHARED_LIBRARIES變量中來(lái)使用該模塊。

用公共庫(kù)共享通用模塊

靜態(tài)庫(kù)可以保證源代碼模塊化,但是,當(dāng)靜態(tài)庫(kù)與共享庫(kù)相連接時(shí),就變成了共享庫(kù)的一部分。在多個(gè)共享庫(kù)的情況下,多個(gè)共享庫(kù)與同一個(gè)靜態(tài)庫(kù)連接時(shí),需要將通用模塊的多個(gè)副本與不同共享庫(kù)重復(fù)連接,這樣就增加了應(yīng)用程序的大小,在這種情況下,我們不用構(gòu)建靜態(tài)庫(kù),而是將通用模塊作為共享庫(kù)建立起來(lái),而動(dòng)態(tài)連接依賴(lài)模塊以便消除重復(fù)的副本。

LOCAL_PATH := $(call my-dir)


第三方AVI庫(kù)

include (CLEAR_VARS) <br> <br> LOCAL_MODULE := avilib <br> LOCAL_SRC_FILES := avilib.c <br> include(BUILD_SHARED_LIBRARY)


原生模塊1

<br>

include (CLEAR_VARS) <br> LOCAL_MODULE := hello-jni1 <br> LOCAL_SRC_FILES := hello-jni1.c <br> LOCAL_SHARED_LIBRARIES:=avilib <br> <br> include(BUILD_SHARED_LIBRARY)


原生模塊2

<br>

include (CLEAR_VARS) <br> LOCAL_MODULE := hello-jni2 <br> LOCAL_SRC_FILES := hello-jni2.c <br> LOCAL_SHARED_LIBRARIES:=avilib <br> <br> include(BUILD_SHARED_LIBRARY)

在多個(gè)NDK項(xiàng)目間共享模塊

同時(shí)使用靜態(tài)庫(kù)和共享庫(kù)時(shí),可以在模塊間共享通用模塊。但是要注意的是,所有這些模塊必須屬于同一個(gè)NDK項(xiàng)目。

1.首先將avilib源代碼移動(dòng)到當(dāng)前NDK項(xiàng)目以外的位置,如:D:\shared-moudles\transcode\avilib

2.作為共享模塊,avilib需要自己的Android.mk文件,具體配置如下:<br

LOCAL_PATH := $(call my-dir)


第三方AVI庫(kù)

include (CLEAR_VARS) <br> <br> LOCAL_MODULE := avilib <br> LOCAL_SRC_FILES := avilib.c <br> include(BUILD_SHARED_LIBRARY)

3.現(xiàn)在可以將avilib模塊從當(dāng)前NDK項(xiàng)目的Android.mk文件中移除。通常,為了避免沖突,我們將以transcode/avilib為參數(shù)調(diào)用函數(shù)宏import-module不分添加在構(gòu)建文檔的末尾。

原生模塊

include (CLEAR_VARS) <br> <br> LOCAL_MODULE := hello-jni1 <br> LOCAL_SRC_FILES := hello-jni1.c <br> LOCAL_SHARED_LIBRARIES:=avilib <br> <br> include(BUILD_SHARED_LIBRARY)



$(call import-module,transcode/avilib)

4.import-module函數(shù)宏需要先定位共享模塊,然后將它導(dǎo)入到NDK項(xiàng)目中。默認(rèn)情況下,import-module函數(shù)宏只搜索/sources目錄。為了搜索D:\shared-moudles目錄,定義一個(gè)名為NDK_MODULE_PATH的新環(huán)境變量并將它設(shè)置成共享模塊的根目錄,例如D:\shared-moudles。

用Prebuilt庫(kù)

prebulit庫(kù)有兩大作用:
1.想在不發(fā)布源代碼的情況下將你的模塊發(fā)布給他人
2.想使用共享模塊的預(yù)建版來(lái)加速構(gòu)建過(guò)程

LOCAL_PATH := $(call my-dir)


第三方AVI庫(kù)

include (CLEAR_VARS)<br> <br> LOCAL_MODULE := avilib<br> LOCAL_SRC_FILES := libavilib.so<br> include(PREBUILT_SHARED_LIBRARY)

其中,LOCAL_SRC_FILES 變量指向的不是源文件,而是實(shí)際Prebuild庫(kù)相對(duì)于LOCAL_PATH的位置。

構(gòu)建獨(dú)立的可執(zhí)行文件

有時(shí)候?yàn)榱朔奖憧焖贉y(cè)試和原型設(shè)計(jì),我們可能會(huì)需要Android NDK構(gòu)建獨(dú)立的可執(zhí)行文件,它們不用打包成APK文件既可以賦值到android設(shè)備上的常規(guī)Linux應(yīng)用程序,而且它們可以直接執(zhí)行,而不通過(guò)java應(yīng)用程序加載。生成獨(dú)立的可以執(zhí)行文件需要再Android.mk構(gòu)建文檔中導(dǎo)入BUILD_EXECUTABLE變量。

獨(dú)立可執(zhí)行的原生模塊

include (CLEAR_VARS)<br> <br> LOCAL_MODULE := moudles<br> LOCAL_SRC_FILES := moudles.c<br> LOCAL_SHARED_LIBRARIES:=avilib<br> <br> include(BUILD_EXECUTABLE)

獨(dú)立的可執(zhí)行文件以與模塊相同的名稱(chēng)放在libs/目錄下。

定義新變量

開(kāi)發(fā)人員可以定義其他新變量來(lái)簡(jiǎn)化他們的構(gòu)建文件。以LOCAL_和NDK_前綴開(kāi)頭的名稱(chēng)預(yù)留給Android NDK構(gòu)建系統(tǒng)使用,建議大家使用MY_開(kāi)頭。例如:
MY_SRC_FILIES:=avilib.c

條件操作

Android.mk構(gòu)建文件可以包含某些關(guān)于這些變量的條件操作,例如,在某個(gè)體系結(jié)構(gòu)中包含一個(gè)不同的源文件集:

……

ifeq($(TARGET_ARCH),arm)


LOCAL_SRC_FILES += armonly.c

else

LOCAL_SRC_FILES += generic.c

endif

……

原地址:https://leach-chen.github.io/blog/android-jni-mk/
個(gè)人網(wǎng)站:https://www.leachchen.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容