Android.mk檔案語法規範及使用
1.概述
Android.mk編譯檔案是用來向Android NDK描述你的C,C++原始碼檔案的。具體來說:
該檔案是GNU Makefile的一小部分,會被編譯系統解析一次或更多次的build系統。因此,您應儘量減少您宣告的變數,不要認為某些變數在解析過程中不會被定義。
這個檔案的語法允許把你的原始碼組織成模組,一個模組屬下列型別之一:
靜態庫
共享庫
只有共享庫將被安裝/複製到您的應用軟體包。雖然靜態庫能被用於生成共享庫。你可以在每一個Android.mk file中定義一個或多個模組,你也可以在幾個模組中使用同一個原始碼檔案。
2.樣例簡析
在描述語法細節之前,咱們來看一個簡單的"hello world"的例子,比如,下面的檔案:
sources/helloworld/helloworld.c
sources/helloworld/Android.mk
'helloworld.c'是一個JNI共享庫,實現返回"hello world"字串的原生方法。
相應的Android.mk檔案會象下面這樣:
---------- cut here ------------------
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= helloworld
LOCAL_SRC_FILES := helloworld.c
include $(BUILD_SHARED_LIBRARY)
---------- cut here ------------------
好,我們來解釋一下這幾行程式碼:
LOCAL_PATH:= $(call my-dir)
一個Android.mk file首先必須定義好LOCAL_PATH變數。它用於在開發樹中查詢原始檔。在這個例子中,巨集函式’my-dir’, 由編譯系統提供,用於返回當前路徑(即包含Android.mk file檔案的目錄)。
include $( CLEAR_VARS)
CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變數(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),
除LOCAL_PATH 。這是必要的,因為所有的編譯控制檔案都在同一個GNU MAKE執行環境中,所有的變數都是全域性的。
LOCAL_MODULE := helloworld
LOCAL_MODULE變數必須定義,以標識你在Android.mk檔案中描述的每個模組。名稱必須是唯一的,而且不包含任何空格。注意編譯系統會自動產生合適的字首和字尾,換句話說,一個被命名為'foo'的共享庫模組,將會生成'libfoo.so'檔案。
重要注意事項
如果你把庫命名為‘libhelloworld’,編譯系統將不會新增任何的lib字首,也會生成libhelloworld.so,這是為了支援來源於Android平臺的原始碼的Android.mk檔案,如果你確實需要這麼做的話。
LOCAL_SRC_FILES := helloworld.c
LOCAL_SRC_FILES變數必須包含將要編譯打包進模組中的C或C++原始碼檔案。注意,你不用在這裡列出標頭檔案和包含檔案,因為編譯系統將會自動為你找出依賴型的檔案;僅僅列出直接傳遞給編譯器的原始碼檔案就好。【注意,預設的C++原始碼檔案的副檔名是’.cpp’. 指定一個不同的副檔名也是可能的,只要定義LOCAL_DEFAULT_CPP_EXTENSION變數,不要忘記開始的小圓點(也就是定義為‘.cxx’,而不是‘cxx’)(當然這一步我們一般不會去改它)】
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY是編譯系統提供的變數,指向一個GNU Makefile指令碼(應該就是在build/core目錄下的shared_library.mk),負責收集自從上次呼叫'include $(CLEAR_VARS)'以來,定義在LOCAL_XXX變數中的所有資訊,並且決定編譯什麼,如何正確地去做。並根據其規則生成靜態庫。同理對於靜態庫。
3.深入分析
下面我們嘗試從一個小模組逐步對android build system做一個深入剖析。選擇的這個模組名字叫做acp ,原始碼位於build\tools\acp目錄。
後續很多模組的編譯都需要使用到acp,根據編譯依賴一般會先編譯本模組。當然它也需要依賴到其他檔案,需要的時候我們再進行闡述。
acp的Android.mk比較簡單,去掉的無用程式碼後,如下面所示:
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES := acp.c
- LOCAL_STATIC_LIBRARIES := libhost
- LOCAL_C_INCLUDES := build/libs/host/include
- LOCAL_MODULE := acp
- LOCAL_ACP_UNAVAILABLE := true
- include $(BUILD_HOST_EXECUTABLE)
上面的語句大致的意思就是,使用當前路徑下的acp.c原始碼,引用的include和連結的library都是host模組,最終編譯生成一個可在當前主機執行的可執行檔案,名字為acp(linux環境)。。
這裡我們先不談每一個變數的具體含義和使用,我們先大概看一下一個Android.mk的基本組成。
- LOCAL_PATH 定義了當前模組的相對路徑,必須出現在所有的編譯模組之前
- 每個編譯模組由include $(CLEAR_VARS) 開始,由include $(BUILD_XXX) 結束
- include $(CLEAR_VARS) 是一個編譯模組的開始,它會清空除LOCAL_PATH之外的所有LOCA_XXX變數
- include $(BUILD_XXX) 描述了編譯目標
- LOCAL_SRC_FILES 定義了本模組編譯使用的原始檔,採用的是基於LOCAL_PATH的相對路徑
- LOCAL_MODULE 定義了本模組的模組名
編譯acp還需要了幾個可選的變數:
- LOCAL_STATIC_LIBRARIES 表示編譯本模組時需要連結的靜態庫
- LOCAL_C_INCLUDES 表示了本模組需要引用的include檔案
- LOCAL_ACP_UNAVAILABLE 表示是否支援acp,如果支援acp,則使用acp進行拷貝,否則使用linux cp拷貝,本模組編譯acp,當然是不支援acp了
編譯目標
上面我們用到include $(CLEAR_VARS)和include $(BUILD_HOST_EXECUTABLE),那麼他們是在哪裡定義的呢?除了BUILD_HOST_EXECUTABLE還有哪些BUILD_XXX目標呢? 它們的定義位於build/core/config.mk檔案,當然config.mk檔案定義的編譯目標也很多,下面列舉幾個常用的目標:編譯目標 | 說明 |
BUILD_HOST_STATIC_LIBRARY | 主機上的靜態庫 |
BUILD_HOST_SHARED_LIBRARY | 主機上的動態庫 |
BUILD_HOST_EXECUTABLE | 主機上的可執行檔案 |
BUILD_STATIC_LIBRARY | 目標裝置上的靜態庫 |
BUILD_SHARED_LIBRARY | 目標裝置上的動態庫 |
BUILD_EXECUTABLE | 目標裝置上的可執行檔案 |
BUILD_JAVA_LIBRARY | JAVA庫 |
BUILD_STATIC_JAVA_LIBRARY | 靜態JAVA庫 |
BUILD_HOST_JAVA_LIBRARY | 主機上的JAVA庫 |
BUILD_PACKAGE | APK程式 |
有人就問了,在本Android.mk中又沒有使用到LOCAL_PATH,為什麼先 要定義這麼一個變數呢?為什麼規定必須放在所有的include $(CLEAR_VARS)之前呢? 在Android.mk中我們發現有LOCAL_SRC_FILES := acp.的定義,NDK檔案中對LOCAL_SRC_FILES 的說明如下: This is a list of source files that will be built for your module. Only list the files that will be passed to a compiler, since the build system automatically computes dependencies for you.
Note that source files names are all relative to LOCAL_PATH and you can use path components . 因此在定義LOCAL_SRC_FILES 時已經間接的使用到了LOCAL_PATH變數,即定義LOCAL_SRC_FILES是用的基於當前路徑的相對路徑。 我們接著看看為什麼LOCAL_PATH的定義必須要放到所有的include $(CLEAR_VARS)之前。 LOCAL_PATH通過呼叫my-dir函式來獲取當前的路徑,my-dir函式的定義位於core/definitions.mk檔案: Makefile程式碼
- <span style="font-size: small;"># Figure out where we are.
- define my-dir
- $(strip \
- $(eval md_file_ := $$(lastword $$(MAKEFILE_LIST))) \
- $(if $(filter $(CLEAR_VARS),$(md_file_)), \
- $(error LOCAL_PATH must be set before including $$(CLEAR_VARS)) \
- , \
- $(patsubst %/,%,$(dir $(md_file_))) \
- ) \
- )
- endef
- $(if $(filter $(CLEAR_VARS),$(md_file_))
- CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
- BUILD_SYSTEM := $(TOPDIR)build/core
- TOPDIR :=
討論完LOCAL_PATH,我們緊接著來看看LOCAL_SRC_FILES。
LOCAL_SRC_FILES: Makefile程式碼
- LOCAL_SRC_FILES := acp.c
- ###########################################################
- ## C: Compile .c files to .o.
- ###########################################################
- c_arm_sources := $(patsubst %.c.arm,%.c,$(filter %.c.arm,$(LOCAL_SRC_FILES)))
- c_arm_objects := $(addprefix $(intermediates)/,$(c_arm_sources:.c=.o))
- c_normal_sources := $(filter %.c,$(LOCAL_SRC_FILES))
- c_normal_objects := $(addprefix $(intermediates)/,$(c_normal_sources:.c=.o))
- $(c_arm_objects): PRIVATE_ARM_MODE := $(arm_objects_mode)
- $(c_arm_objects): PRIVATE_ARM_CFLAGS := $(arm_objects_cflags)
- $(c_normal_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
- $(c_normal_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
- c_objects := $(c_arm_objects) $(c_normal_objects)
- ifneq ($(strip $(c_objects)),)
- $(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
- $(transform-$(PRIVATE_HOST)c-to-o)
- -include $(c_objects:%.o=%.P)
- endif
- build/core/host_java_library.mk:intermediates := $(call local-intermediates-dir)
- build/core/base_rules.mk:intermediates := $(call local-intermediates-dir)
- build/core/dynamic_binary.mk:guessed_intermediates := $(call local-intermediates-dir)
- build/core/java.mk:intermediates := $(call local-intermediates-dir)
- # Uses LOCAL_MODULE_CLASS, LOCAL_MODULE, and LOCAL_IS_HOST_MODULE
- # to determine the intermediates directory.
- #
- # $(1): if non-empty, force the intermediates to be COMMON
- define local-intermediates-dir
- $(strip \
- $(if $(strip $(LOCAL_MODULE_CLASS)),, \
- $(error $(LOCAL_PATH): LOCAL_MODULE_CLASS not defined before call to local-intermediates-dir)) \
- $(if $(strip $(LOCAL_MODULE)),, \
- $(error $(LOCAL_PATH): LOCAL_MODULE not defined before call to local-intermediates-dir)) \
- $(call intermediates-dir-for,$(LOCAL_MODULE_CLASS),$(LOCAL_MODULE),$(LOCAL_IS_HOST_MODULE),$(1)) \
- )
- endef
LOCAL_MODULE value acp
LOCAL_IS_HOST_MODULE value true 其中,LOCAL_MODULE 的值是acp,這個肯定的是沒問題的,因為在acp模組的Android.mk檔案中有明確的定義:LOCAL_MODULE := acp 那LOCAL_MODULE_CLASS 為什麼是EXECUTABLES呢?我們這裡先猜一下,估計是和最後一句include $(BUILD_HOST_EXECUTABLE )有關, 同樣,LOCAL_IS_HOST_MODULE 為true,估計也是和include $(BUILD_HOST _EXECUTABLE)有關了。 我們還是先回到 local-intermediates-dir函式中,其中前兩個判斷是判斷是否定義LOCAL_MODULE_CLASS和LOCAL_MODULE,如果未空,則直接報錯,這裡也就說明了在每一個編譯模組中(即include $(CLEAR_VARS)和include $(BUILD_XXX)之間)必須定義LOCAL_MODULE的值。 因此,如果LOCAL_MODULE_CLASS和LOCAL_MODULE都不為空時,則執行intermediates-dir-for這個函式,$(LOCAL_MODULE_CLASS),$(LOCAL_MODULE),$(LOCAL_IS_HOST_MODULE)還有 local-intermediates-dir函式的第一個引數 $(1)會作為引數傳給intermediates-dir-for函式。根據上面intermediates的賦值部分的程式碼,我們知道呼叫local-intermediates-dir函式時沒有傳遞任何引數,因此此時的$(1)即為空,傳給intermediates-dir-for函式的也就只有上述的3個引數。 intermediates-dir-for 下面我們來看intermediates-dir-for Makefile程式碼
- ###########################################################
- ## The intermediates directory. Where object files go for
- ## a given target. We could technically get away without
- ## the "_intermediates" suffix on the directory, but it's
- ## nice to be able to grep for that string to find out if
- ## anyone's abusing the system.
- ###########################################################
- # $(1): target class, like "APPS"
- # $(2): target name, like "NotePad"
- # $(3): if non-empty, this is a HOST target.
- # $(4): if non-empty, force the intermediates to be COMMON
- define intermediates-dir-for
- $(strip \
- $(eval _idfClass := $(strip $(1))) \
- $(if $(_idfClass),, \
- $(error $(LOCAL_PATH): Class not defined in call to intermediates-dir-for)) \
- $(eval _idfName := $(strip $(2))) \
- $(if $(_idfName),, \
- $(error $(LOCAL_PATH): Name not defined in call to intermediates-dir-for)) \
- $(eval _idfPrefix := $(if $(strip $(3)),HOST,TARGET)) \
- $(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
- $(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_INTERMEDIATES)) \
- , \
- $(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES)) \
- ) \
- $(_idfIntBase)/$(_idfClass)/$(_idfName)_intermediates \
- )
- endef
- $(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES))
- HOST_OUT_INTERMEDIATES := $(HOST_OUT)/obj
- HOST_OUT := $(HOST_OUT_$(HOST_BUILD_TYPE))
- # the host build defaults to release, and it must be release or debug
- ifeq ($(HOST_BUILD_TYPE),)
- HOST_BUILD_TYPE := release
- endif
- HOST_OUT := $(HOST_OUT_release)
- HOST_OUT_release := $(HOST_OUT_ROOT_release)/$(HOST_OS)-$(HOST_ARCH)
- HOST_OUT_ROOT_release := $(OUT_DIR)/host
- c_objects := $(c_arm_objects) $(c_normal_objects)
- ifneq ($(strip $(c_objects)),)
- $(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
- $(transform-$(PRIVATE_HOST)c-to-o)
- -include $(c_objects:%.o=%.P)
- endif
相關推薦
Android.mk檔案語法規範及使用
1.概述Android.mk編譯檔案是用來向Android NDK描述你的C,C++原始碼檔案的。具體來說:該檔案是GNU Makefile的一小部分,會被編譯系統解析一次或更多次的build系統。因此,您應儘量減少您宣告的變數,不要認為某些變數在解析過程中不會被定義。這
Android.mk檔案語法規範——深入瞭解android平臺的jni
Android.mk是Android提供的一種makefile檔案,用來指定諸如編譯生成so庫名、引用的標頭檔案目錄、需要編譯的.c/.cpp檔案和.a靜態庫檔案等。要掌握jni,就必須熟練掌握Android.mk的語法規範。 一、Android.mk檔案的用途一個andr
Android.mk檔案語法詳解
原文地址為:Android.mk 檔案語法詳解 轉:http://blog.sina.com.cn/s/blog_602f8770010148ce.html ===============================================================
Android.mk 檔案語法詳解
===================================================================================== 0. Android.mk簡介: Android.mk檔案用來告知NDK Build 系統關於Sou
安卓Android.mk 檔案語法詳解
0. Android.mk簡介: Android.mk檔案用來告知NDK Build 系統關於Source的資訊。 Android.mk將是GNU Makefile的一部分,且將被Build System解析一次或多次。 所以,請儘量少的在Android.mk中宣告
NDK 編譯和使用靜態庫、動態庫; Android.mk 檔案語法詳解; Android.mk高階寫法
===================================================================================== 0. Android.mk簡介: Android.mk檔案用來告知NDK Build 系統關於Source的資訊。 Andro
androd.mk 檔案語法規範
http://blog.163.com/[email protected]/blog/static/70234777201102611363180/ Android.mk檔案語法規範 序言: ------------- 此文件旨在描述Android.
android.mk檔案語法總結
LOCAL_PATH := $(call my-dir)//指定本地路徑,通常是android.mk檔案所在路徑 include $(CLEAR_VARS)//這兩行必須要 LOCAL_MODULE := OgreGLES2Sample//指定模組名,
Android.mk入門到精通(001)——Android.mk 檔案語法詳解:神文
https://www.cnblogs.com/wainiwann/p/3837936.html 0. Android.mk簡介: Android.mk檔案用來告知NDK Build 系統關於Source的資訊。 Android.mk將是GNU Makefile的一部分,
Android.mk檔案語法詳述
介紹:------------這篇文件是用來描述你的C或C++原始檔中Android.mk編譯檔案的語法的,為了理解她們我們需要您先看完docs/OVERVIEW.html(http://hualang.iteye.com/blog/1135105)檔案來了解它的作用概覽:
Android.mk 檔案語法大全
講解如下:LOCAL_PATH := $(call my-dir) 每個Android.mk檔案必須以定義LOCAL_PATH為開始。它用於在開發tree中查詢原始檔。巨集my-dir 則由Build System提供。返回包含Android.mk的目錄路徑。include $(CLEAR_VARS)CLE
Android .mk檔案語法解析
下面是MTK-AndroidFM模組Android .mk程式碼內容: 1 ifeq ($(MTK_FM_SUPPORT),yes) 2 LOCAL_PATH:= $(call my-dir) 3 include $(CLEAR_VARS) 4 LOCAL_MODULE_T
Android5.1 內建第三方APK及Android.mk檔案編寫(以在amlogic5.1公版系統內建百度輸入法為例)
Android.mk檔案用來向編譯系統描述如何編譯你的原始碼。在編譯整個工程的情況下,系統所找到的所有的Android.mk將會先存入subdir_makefiles變數中,隨後一次性一次性include進整個編譯檔案中。 示例 Android.mk內容:
ndk開發中的Android.mk檔案與Application.mk詳解及例項
Android.mk檔案的作用: An Android.mk file is written to describe your sources to the build system. 中文意思是:寫一個Android.mk檔案是為了向生成系統描述你的原始碼。
編寫Android.mk檔案備錄
前言: 由於目前供職於機器人公司,從事基於android系統的軟體開發,因此常常需要進行原始碼編譯(當然也可以基於機器人的sdk和android studio環境進行開發)。 進行原始碼編譯,少不了編寫Android.mk檔案。通常類比前人的Android.mk檔案修修改
Android Studio使用自定義的Android.mk檔案編譯ffmpegyuv-bgr
概述 最近做專案的時候,領導安排一個任務,讓測試一下,用ffmpeg中的yuv轉bgr函式的速度。之前編譯so庫大部分都是用eclipse,本次博主花了兩天時間,在Android studio上編譯並執行,在此做一下記錄。 設定Android Studio ndk 1、開啟setings
LOCAL_MODULE_TAGS--------在Android.mk檔案裡的配置項------------
ZZZZ: http://blog.csdn.net/talking12391239/article/details/10904653 要了解Android編譯選項eng、user和userdebug的區別,需先了解下LOCAL_MODULE_TAGS這一Android.m
Makefile & Android.mk檔案
1. 列印輸出:$(warning xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)或者$(error xxxxx) 列印輸出變數的值:$(warning $(LOCAL_SHARED_LIBRARIES)) 2. LOCAL_CFLAGS
專案中在Android.mk檔案中根據專案名稱選擇不同的AndroidManifest.xml檔案 && 如何使用系統設定的日期顯示格式
專案中根據專案名稱選擇不同的AndroidManifest.xml檔案 MY_PROJECT_NAME := $(subst full_,,$(TARGET_PRODUCT)) ifeq ($(strip $(MY_PROJECT_NAME)), xxxxxx)# xxxx
解讀Android.mk檔案
一、介紹 本文章會介紹構建 Android.mk檔案的構建過程;Android.mk檔案會將我們的 C 和 C++ 檔案描述為 Android NDK 二、概述 Android.mk檔案是描述原始檔在構建系統的作用,更具體來說: 這個Andro