Android Mk Application Mk make makefile筆記

weixin_34007291發表於2018-11-28

說明

這只是筆記。。。。。。。。

從0開始搭建測試環境

下載android ndk ,然後配置ndk環境變數,使ndk-build命令能在任意目錄執行.

目錄的規定

在任意目錄建立一個Android.mk和Application.mk
然後切換命令列在此目錄輸入ndk-build
出現錯誤

Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
D:\env\android_sdk\ndk-bundle\build\\..\build\core\build-local.mk:151: *** Android NDK: Aborting

百思不得其解,網上的文章沒有幾篇靠譜的,嘗試把這個目錄改名為jni,切換到此目錄,竟然錯誤消失了,出現另外一個目錄

解決警告

雖然這個錯誤沒有出現了,但是又出現了2個警告,1是提示定義最小版本,二是定說沒有模組.

Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.
D:/env/android_sdk/ndk-bundle/build//../build/core/build-all.mk:89: Android NDK: WARNING: There are no modules to build in this project!
  • 定義版本號
    在Application.mk定義如下內容:
    APP_PLATFORM:=android-14

    E:\cross-c\Androidmk\jni>ndk-build -B
    Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.
    D:/env/android_sdk/ndk-bundle/build//../build/core/build-all.mk:89: Android NDK: WARNING: There are no modules to build in this project!
    make: Nothing to be done for `all'.

這種情況,關閉終端重啟.

ndk-build命令幫助

ndk-build V=1 顯示詳細資訊
ndk-build -B 強制編譯
ndk-build NDK_APPLICATION_MK=My.mk自定義Application.mk
ndk-build NDK_DEBUG為1可以實現優化不優化的問題,有符號就能定位堆疊。
ndk-build NDK_HOST_32BIT=1 不根據作業系統的64位使用這個構建
<ndk>/toolchain/<name>/prebuilt/

下面的語法實際上是make命令的語法

E:\cross-c\Androidmk\jni>ndk-build --help
用例: make [選項] [目標] ...
Options:
  -b, -m                      Ignored for compatibility.忽略相容性
  -B, --always-make           Unconditionally make all targets.無條件完成所有target編譯,感覺沒啥變化
  -C DIRECTORY, --directory=DIRECTORY
                              Change to DIRECTORY before doing anything. 做任意事情之前改變目錄
  -d                          Print lots of debugging information.
  --debug[=FLAGS]          debug模式,列印除錯資訊    Print various types of debugging information.
  -e, --environment-overrides 覆蓋makefiles的環境變數
                              Environment variables override makefiles.
  -f FILE, --file=FILE, --makefile=FILE 自定義makefile檔案
                              Read FILE as a makefile.
  -h, --help               列印幫助資訊and退出
  -i, --ignore-errors         Ignore errors from commands.忽略命令列錯誤
  -I DIRECTORY, --include-dir=DIRECTORY
                              Search DIRECTORY for included makefiles. 定義包含的目錄
  -j [N], --jobs[=N]          Allow N jobs at once; infinite jobs with no arg. 次允許N個作業;沒有引數則無限工作
  -k, --keep-going            Keep going when some targets can't be made.當一些目標無法達成時,繼續前進。
  -l [N], --load-average[=N], --max-load[=N] 指定平均載入任務
                              Don't start multiple jobs unless load is below N.除非負載小於N,否則不要啟動多個作業。
  -L, --check-symlink-times   Use the latest mtime between symlinks and target. 用符號連結和目標之間的最新時間。
  -n, --just-print, --dry-run, --recon
                              Don't actually run any commands; just print them.不執行實際的命令只是列印。
  -o FILE, --old-file=FILE, --assume-old=FILE
                              Consider FILE to be very old and don't remake it. 認為檔案很舊,不要重做。
  -p, --print-data-base       Print make's internal database.列印內部資料庫
  -q, --question              Run no commands; exit status says if up to date. 退出狀態表示是否是最新
  -r, --no-builtin-rules      Disable the built-in implicit rules.禁用內建的隱式規則。
  -R, --no-builtin-variables   禁用內建變數 Disable the built-in variable settings.
  -s, --silent, --quiet      靜默模式,不輸出資訊 Don't echo commands.
  -S, --no-keep-going, --stop
                              Turns off -k.
  -t, --touch                 Touch targets instead of remaking them.
  -v, --version            列印make版本號   Print the version number of make and exit.
  -w, --print-directory  列印當前目錄     Print the current directory.
  --no-print-directory     不列印當前目錄   Turn off -w, even if it was turned on implicitly. 隱式開啟
  -W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE
                              Consider FILE to be infinitely new. 認為檔案是無限新的
  --warn-undefined-variables  Warn when an undefined variable is referenced. 引用未定義變數時發出警告。

    This program built for i686-w64-mingw32
    Report bugs to <bug-make@gnu.org>
    E:\cross-c\Androidmk\jni>




mk語法與AndroidMk的變數與巨集

android 一般使用ndk-build測試的,而不是單純的玩make,

定義變數
變數名 := 變數值

判斷變數是否存在

變數拼接
MY_VAR+=append........
列印字串
這裡在控制檯列印HelloWorld
$(warning HelloWorld)
列印變數

MY_VAR:=I am var
$(warning $(MY_VAR))

列印拼接的變數

    $(warning 33333$(MY_VAR))
  • 控制檯輸出的效果
    E:\cross-c\Androidmk\jni>ndk-build
    E:/cross-c/Androidmk/jni/Application.mk:3: WellcomeUseAndroidMk
    [armeabi-v7a] Compile++ thumb: png <= hello.cpp
    [armeabi-v7a] SharedLibrary  : libpng.so
    [armeabi-v7a] Install        : libpng.so => libs/armeabi-v7a/libpng.so

列印當前目錄
$(warning currentPath:$(my-dir))
my-dir變數是android的ndk-build環境才有的,純make是沒有的
列印CLEAR_VARS

$(CLEAR_VARS)需要在Android.mk裡面編寫才能測試

$(warning currentPath:$(CLEAR_VARS))
$(warning ------------------)

輸出結果
D:/env/android_sdk/ndk-bundle/build//../build/core/clear-vars.mk

語法錯誤的效果

:\cross-c\Androidmk\jni>ndk-build
:/cross-c/Androidmk/jni/Application.mk:3: *** missing separator.  Stop.

註釋

#開頭就是註釋了。
邏輯分支

DEBUG:=1
NAME:=qssq
SEX:=man
EMPTY:=#定義空
SPACE:=$(EMPTY) $(EMPTY) #定義空格
ifeq ($(DEBUG),1)#關鍵字後面需要加空格,否則語法錯誤
$(warning 除錯模式)
else
$(warning 非除錯模式)
endif


#去掉收尾空格進行判斷是否為空
ifeq ($(strip $(SPACE)),)
$(warning SPACE變數去掉首尾空格為空)
endif

# 如果不是空而是空格也是不匹配的。
ifneq ($(SPACE),)
$(warning 不去掉首尾,不是空)
endif

#----------------------------------------------
ifeq ($(DEBUG),qssq)
$(warning 輸出了作者)
else
$(warning 不知道你輸入了什麼名字,名字是$(NAME))
endif

ifeq ($(SEX),man)
$(warning 是個男人)
endif

#是否SEX等於woman字串
ifneq ($(SEX),woman)
$(warning 不是女人)
endif

#定義變數 (看上去是一個函式
define tempvar
$(warning  執行了temp定義)
endef

#判斷是否定義了tempvar
ifdef tempvar
$(warning 即將執行tempvar)
$(call tempvar)
endif




#判斷是否定義了tempvar3
ifdef tempvar3
$(warning 即將執行tempvar3)
$(call tempvar3)
endif


ifndef tempvar2
$(warning 沒有定義tempvar2)
endif

定義多行
如果下一行要繼續上一行,則上一行應該以\結尾

Application.mk內嵌的變數

設定編譯的架構

定義需要編譯的架構 多個用空格隔開
APP_ABI :=arm64-v8a

APP_ABI:=armeabi-v7a x86 x86_64 arm64-v8a x86_64

APP_ABI:=all 和不填寫的效果一樣。

定義目標平臺
APP_PLATFORM
接受的變數如 android-14
測試錯誤的結果
賦值為android-1433 提示這個1433大於最高的版本28,請選擇一個支援的api級別,或者設定為latest,latest的意思就是最新的。

:/cross-c/Androidmk/jni/Application.mk:6: 33333I am var
ndroid NDK: android-1433 is above the maximum supported version android-28. Choose a supported API level or set APP_PLATFORM to "latest".
:/env/android_sdk/ndk-bundle/build//../build/core/setup-app-platform.mk:127: *** Android NDK: Aborting.    .  Stop.

設定最高版本APP_PLATFORM:=latest

Android NDK: Using latest available APP_PLATFORM: android-28.

設定最低版本
最低版本就是不指定APP_PLATFORM變數。

Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.

設定最小支援庫
筆者在編譯後找不到某些標頭檔案,發現我們的c++大神把我的配置
gnustl_static改為了stlport_static
如今記憶猶新哈。
APP_STL

libstdc++(預設)   預設最小系統 C++ 執行時庫。    不適用
gabi++_static   GAbi++ 執行時(靜態)。 C++ 異常和 RTTI
gabi++_shared   GAbi++ 執行時(共享)。 C++ 異常和 RTTI
stlport_static  STLport 執行時(靜態)。    C++ 異常和 RTTI;標準庫
stlport_shared  STLport 執行時(共享)。    C++ 異常和 RTTI;標準庫
gnustl_static   GNU STL(靜態)。    C++ 異常和 RTTI;標準庫
gnustl_shared   GNU STL(共享)。    C++ 異常和 RTTI;標準庫
c++_static  LLVM libc++ 執行時(靜態)。    C++ 異常和 RTTI;標準庫
c++_shared  LLVM libc++ 執行時(共享)。    C++ 異常和 RTTI;標準庫

AndroidMk的執行順序

先執行Application.mk
然後執行Android.mk

Application.mk官方說明

這裡的配置相對於Android.mk比較少

本文件介紹 Application.mk 構建檔案,此檔案用於描述應用需要的原生模組。 模組可以是靜態庫、共享庫或可執行檔案。

建議在閱讀本頁之前先閱讀概念和 Android.mk 頁面。 這樣有助於您最深入地瞭解本頁的內容。

概覽
Application.mk 檔案實際上是定義要編譯的多個變數的微小 GNU Makefile 片段。 它通常位於 PROJECT 指向應用的專案目錄。 另一種方式是將其放在頂級 NDK/apps/<myapp>/Application.mk
這裡的 <myapp> 是用於向 NDK 構建系統描述應用的短名稱。它不會實際進入生成的共享庫或最終軟體包。

變數
APP_PROJECT_PATH
此變數用於儲存應用專案根目錄的絕對路徑。構建系統使用此資訊將生成的 JNI 共享庫的簡縮版放入 APK 生成工具已知的特定位置。

如果將 Application.mk 檔案放在 PROJECT/jni/ 下,則此變數可選。

APP_OPTIM
將此可選變數定義為 release 或 debug。在構建應用的模組時可使用它來更改優化級別。

發行模式是預設模式,可生成高度優化的二進位制檔案。除錯模式會生成未優化的二進位制檔案,更容易除錯。

請注意,您可以除錯發行或除錯二進位制檔案。但發行二進位制檔案在除錯時提供的資訊較少。 例如,構建系統會選擇某些合適的變數,您無需檢查它們。 此外,程式碼重新排序可能增大單步除錯程式碼的難度;堆疊追蹤可能不可靠。

在應用清單的 <application> 標記中宣告 android:debuggable 將導致此變數預設使用 debug而非 release。 將 APP_OPTIM 設定為 release 可替換此預設值。

APP_CFLAGS
此變數用於儲存構建系統在為任何模組編譯任何 C 或 C++ 原始碼時傳遞到編譯器的一組 C 編譯器標誌。 您可使用此變數根據需要它的應用更改指定模組的版本,而無需修改 Android.mk 檔案本身。

這些標誌中的所有路徑應為頂級 NDK 目錄的相對路徑。例如,如果您有以下設定:

sources/foo/Android.mk
sources/bar/Android.mk
要在 foo/Android.mk 中指定您在編譯時要新增指向 bar 原始檔的路徑,應使用:

APP_CFLAGS += -Isources/bar
或者:

APP_CFLAGS += -INDK_ROOT/../bar 後不會執行。

注:此變數僅適用於 android-ndk-1.5_r1 中的 C 原始檔,而不適用於 C++ 原始檔。 在該版本後的所有版本中,APP_CFLAGS 匹配整個 Android 構建系統。

APP_CPPFLAGS
此變數包含構建系統在僅構建 C++ 原始檔時傳遞到編譯器的一組 C++ 編譯器標誌。

注:在 android-ndk-1.5_r1 中,此變數適用於 C 和 C++ 原始檔。 在 NDK 的所有後續版本中,APP_CPPFLAGS 現在匹配整個 Android 構建系統。 對於適用於 C 和 C++ 原始檔的標誌,請使用 APP_CFLAGS。

APP_LDFLAGS
構建系統在連結應用時傳遞的一組連結器標誌。此變數僅在構建系統構建共享庫和可執行檔案時才相關。 當構建系統構建靜態庫時,會忽略這些標誌。

APP_BUILD_SCRIPT
預設情況下,NDK 構建系統在 jni/ 下查詢名稱為 Android.mk 的檔案。

如果要改寫此行為,可以定義 APP_BUILD_SCRIPT 指向替代構建指令碼。 構建系統始終將非絕對路徑解釋為 NDK 頂級目錄的相對路徑。

APP_ABI
預設情況下,NDK 構建系統為 armeabi ABI 生成機器程式碼。 此機器程式碼對應於基於 ARMv5TE、採用軟體浮點運算的 CPU。 您可以使用 APP_ABI 選擇不同的 ABI。 表 1 所示為不同指令集的 APP_ABI 設定。

表 1. APP_ABI 不同指令集的設定。

指令集 值
基於 ARMv7 的裝置上的硬體 FPU 指令 APP_ABI := armeabi-v7a
ARMv8 AArch64 APP_ABI := arm64-v8a
IA-32 APP_ABI := x86
Intel64 APP_ABI := x86_64
MIPS32 APP_ABI := mips
MIPS64 (r6) APP_ABI := mips64
所有支援的指令集 APP_ABI := all
注:all 從 NDKr7 開始可用。

您也可以指定多個值,將它們放在同一行上,中間用空格分隔。例如:

APP_ABI := armeabi armeabi-v7a x86 mips
如需瞭解所有支援的 ABI 列表及其用法和限制的詳細資訊,請參閱 ABI 管理。

APP_PLATFORM
此變數包含目標 Android 平臺的名稱。例如,android-3 指定 Android 1.5 系統映像。 如需平臺名稱和對應 Android 系統映像的完整列表,請參閱 Android NDK 原生 API。

APP_STL
預設情況下,NDK 構建系統為 Android 系統提供的最小 C++ 執行時庫 (system/lib/libstdc++.so) 提供 C++ 標頭。 此外,它隨附您可以在自己的應用中使用或連結的替代 C++ 實現。請使用 APP_STL 選擇其中一個。 如需瞭解有關支援的執行時及其功能的資訊,請參閱 NDK 執行時和功能。

APP_SHORT_COMMANDS
相當於 Application.mk 中的 LOCAL_SHORT_COMMANDS,適用於整個專案。如需瞭解詳細資訊,請參閱 Android.mk 上此變數的相關文件。

NDK_TOOLCHAIN_VERSION
將此變數定義為 4.9 或 4.8 以選擇 GCC 編譯器的版本。 64 位 ABI 預設使用版本 4.9 ,32 位 ABI 預設使用版本 4.8。要選擇 Clang 的版本,請將此變數定義為 clang3.4、clang3.5 或 clang。 指定 clang 會選擇 Clang 的最新版本。

APP_PIE
從 Android 4.1(API 級別 16)開始,Android 的動態連結器支援位置獨立的可執行檔案 (PIE)。 從 Android 5.0(API 級別 21)開始,可執行檔案需要 PIE。要使用 PIE 構建可執行檔案,請設定 -fPIE 標誌。 此標誌增大了通過隨機化程式碼位置來利用記憶體損壞缺陷的難度。 預設情況下,如果專案針對 android-16 或更高版本,ndk-build 會自動將此值設定為 true。您可以手動將其設定為 true 或 false。

此標誌僅適用於可執行檔案。它在構建共享或靜態庫時沒有影響。

注:PIE 可執行檔案無法在 4.1 版之前的 Android 上執行。

此限制僅適用於可執行檔案。它在構建共享或靜態庫時沒有影響。

APP_THIN_ARCHIVE
在 Android.mk 檔案中為此專案中的所有靜態庫模組設定 LOCAL_THIN_ARCHIVE 的預設值。 如需瞭解詳細資訊,請參閱 Android.mk 文件中的 LOCAL_THIN_ARCHIVE。

Android.mk官方說明

基礎知識
在詳細瞭解語法之前,先了解 Android.mk 檔案所含內容的基本資訊很有用。 為此,本節使用 Hello-JNI 示例中的 Android.mk 檔案,解釋檔案中的每行所起的作用。

Android.mk 檔案必須首先定義 LOCAL_PATH 變數:

LOCAL_PATH := $(call my-dir)
此變數表示原始檔在開發樹中的位置。在這裡,構建系統提供的巨集函式 my-dir 將返回當前目錄(包含 Android.mk 檔案本身的目錄)的路徑。

下一行宣告 CLEAR_VARS 變數,其值由構建系統提供。

include $(CLEAR_VARS)
CLEAR_VARS 變數指向特殊 GNU Makefile,可為您清除許多 LOCAL_XXX 變數,例如 LOCAL_MODULELOCAL_SRC_FILESLOCAL_STATIC_LIBRARIES

請注意,它不會清除 LOCAL_PATH。此變數必須保留其值,因為系統在單一 GNU Make 執行環境(其中所有變數都是全域性的)中解析所有構建控制檔案。 在描述每個模組之前,必須宣告(重新宣告)此變數。

接下來,LOCAL_MODULE 變數將儲存您要構建的模組的名稱。請在應用中每個模組使用一個此變數。

LOCAL_MODULE := hello-jni
每個模組名稱必須唯一,且不含任何空格。構建系統在生成最終共享庫檔案時,會將正確的字首和字尾自動新增到您分配給 LOCAL_MODULE 的名稱。 例如,上述示例會導致生成一個名為 libhello-jni.so 的庫。

注:如果模組名稱的開頭已是 lib,則構建系統不會附加額外的字首 lib;而是按原樣採用模組名稱,並新增 .so 副檔名。 因此,比如原來名為 libfoo.c 的原始檔仍會生成名為 libfoo.so 的共享物件檔案。

此行為是為了支援 Android 平臺原始檔從 Android.mk 檔案生成的庫;所有這些庫的名稱都以 lib 開頭。

下一行列舉原始檔,以空格分隔多個檔案:

LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES 變數必須包含要構建到模組中的 C 和/或 C++ 原始檔列表。

最後一行幫助系統將所有內容連線到一起:

include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY 變數指向 GNU Makefile 指令碼,用於收集您自最近 include 後在 LOCAL_XXX 變數中定義的所有資訊。 此指令碼確定要構建的內容及其操作方法。

示例目錄中有更復雜的示例,包括您可以檢視的帶註釋的 Android.mk 檔案。 此外,示例:native-activity 詳細說明了該示例的 Android.mk 檔案。 最後,變數和巨集提供本節中變數的進一步資訊。

變數和巨集
構建系統提供許多可用於 Android.mk 檔案中的變數。其中許多變數已預先賦值。 另一些變數由您賦值。

除了這些變數之外,您還可以定義自己的任意變數。在定義變數時請注意,NDK 構建

系統會預留以下變數名稱

  • LOCAL_開頭的名稱,例如 LOCAL_MODULE

  • PRIVATE_NDK_APP 開頭的名稱。構建系統在內部使用這些變數。

  • 小寫名稱,例如 my-dir。構建系統也是在內部使用這些變數。

為了方便別人閱讀而需要在 Android.mk 檔案中定義自己的變數,建議在名稱前附加 MY_

NDK 定義的變數
本節討論構建系統在解析 Android.mk 檔案之前定義的 GNU Make 變數。 在某些情況下,NDK 可能會多次解析 Android.mk 檔案,每次使用其中某些變數的不同定義。

CLEAR_VARS
此變數指向的構建指令碼用於取消定義下面“開發者定義的變數”一節中列出的幾乎全部 LOCAL_XXX 變數。 在描述新模組之前,使用此變數包括此指令碼。 使用它的語法為:

include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY

此變數指向的指令碼用於收集您在 LOCAL_XXX 變數中提供的模組所有相關資訊,以及確定如何從列出的原始檔構建目標共享庫。 請注意,使用此指令碼要求您至少已為 LOCAL_MODULELOCAL_SRC_FILES賦值(如需瞭解有關這些變數的詳細資訊,請參閱模組描述變數)。

使用此變數的語法為:

include $(BUILD_SHARED_LIBRARY)
共享庫變數導致構建系統生成具有 .so 副檔名的庫檔案。

BUILD_STATIC_LIBRARY
用於構建靜態庫的 BUILD_SHARED_LIBRARY 的變體。構建系統不會將靜態庫複製到您的專案/軟體包,但可能使用它們構建共享庫(請參閱下面的 LOCAL_STATIC_LIBRARIESLOCAL_WHOLE_STATIC_LIBRARIES)。 使用此變數的語法為:

include $(BUILD_STATIC_LIBRARY)
靜態庫變數導致構建系統生成副檔名為 .a 的庫。

PREBUILT_SHARED_LIBRARY
指向用於指定預建共享庫的構建指令碼。與BUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARY 的情況不同,這裡的 LOCAL_SRC_FILES 值不能是原始檔, 而必須是指向預建共享庫的單一路徑,例如 foo/libfoo.so。 使用此變數的語法為:

include $(PREBUILT_SHARED_LIBRARY)
也可使用 LOCAL_PREBUILTS 變數引用另一個模組中的預建庫。 如需瞭解有關使用預建庫的詳細資訊,請參閱使用預建庫。

PREBUILT_STATIC_LIBRARY
與 PREBUILT_SHARED_LIBRARY 相同,但用於預構建的靜態庫。如需瞭解有關使用預建庫的詳細資訊,請參閱使用預建庫。

TARGET_ARCH
Android 開放原始碼專案所指定的目標 CPU 架構的名稱。對於與 ARM 相容的任何構建,請使用獨立於 CPU 架構修訂版或 ABI 的 arm(請參閱下面的 TARGET_ARCH_ABI)。

此變數的值取自您在 Android.mk 檔案中定義的 APP_ABI 變數,系統將在解析 Android.mk 檔案前讀取其值。(翻譯:應該是Application.mk)

TARGET_PLATFORM
作為構建系統目標的 Android API 級別號。例如,Android 5.1 系統映像對應於 Android API 級別 22:android-22。如需平臺名稱及相應 Android 系統映像的完整列表,請參閱 Android NDK 原生 API。以下示例顯示了使用此變數的語法:

TARGET_PLATFORM := android-22
TARGET_ARCH_ABI
當構建系統解析此 Android.mk 檔案時,此變數將 CPU 和架構的名稱儲存到目標。 您可以指定以下一個或多個值,使用空格作為多個目標之間的分隔符。 表 1 顯示了要用於每個支援的 CPU 和架構的 ABI 設定。

表 1. 不同 CPU 和架構的 ABI 設定。

CPU 和架構|設定的引數
ARMv5TE armeabi
ARMv7   armeabi-v7a
ARMv8 AArch64   arm64-v8a
i686    x86
x86-64  x86_64
mips32 (r1) mips
mips64 (r6) mips64
全部  all

以下示例顯示如何將 ARMv8 AArch64 設定為目標 CPU 與 ABI 的組合:

TARGET_ARCH_ABI := arm64-v8a
注:在 Android NDK 1.6_r1 和以前的版本中,此變數定義為 arm。

如需瞭解架構 ABI 和相關相容性問題的詳細資訊,請參閱 ABI 管理。

未來的新目標 ABI 將有不同的值。

TARGET_ABI
目標 Android API 級別與 ABI 的聯接,特別適用於要針對實際裝置測試特定目標系統映像的情況。 例如,要指定在 Android API 級別 22 上執行的 64 位 ARM 裝置:

TARGET_ABI := android-22-arm64-v8a
注:在 Android NDK 1.6_r1 和以前的版本中,預設值為 android-3-arm

模組描述變數
本節中的變數向構建系統描述您的模組。每個模組描述應遵守以下基本流程:

使用 CLEAR_VARS 變數初始化或取消定義與模組相關的變數。
為用於描述模組的變數賦值。
使用 BUILD_XXX 變數設定 NDK 構建系統,以便為模組使用適當的構建指令碼。
LOCAL_PATH
此變數用於指定當前檔案的路徑。必須在 Android.mk 檔案的開頭定義它。 以下示例向您展示如何操作:

LOCAL_PATH := $(call my-dir)
CLEAR_VARS 指向的指令碼不會清除此變數。因此,即使您的 Android.mk 檔案描述了多個模組,您也只需定義它一次。

LOCAL_MODULE
此變數用於儲存模組的名稱。它在所有模組名稱之間必須唯一,並且不得包含任何空格。 必須在包含任何指令碼(用於 CLEAR_VARS 的指令碼除外)之前定義它。 無需新增 lib 字首或者 .so 或 .a 副檔名;構建系統會自動進行這些修改。 在整個 Android.mk 和 Application.mk 檔案中,請通過未修改的名稱引用模組。 例如,以下行會導致生成名為 libfoo.so 的共享庫模組:

LOCAL_MODULE := "foo"
如果希望生成的模組使用 lib 以外的名稱和 LOCAL_MODULE 以外的值,可以使用 LOCAL_MODULE_FILENAME 變數為生成的模組指定自己選擇的名稱。

LOCAL_MODULE_FILENAME
此可選變數可讓您覆蓋構建系統預設用於其生成的檔案的名稱。 例如,如果 LOCAL_MODULE 的名稱為 foo,您可以強制系統將它生成的檔案命名為 libnewfoo。 以下示例顯示如何完成此操作:

LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo
對於共享庫模組,此示例將生成一個名為 libnewfoo.so 的檔案。

注:無法替換檔案路徑或副檔名。

LOCAL_SRC_FILES
此變數包含構建系統用於生成模組的原始檔列表。 只列出構建系統實際傳遞到編譯器的檔案,因為構建系統會自動計算所有關聯的依賴關係。

請注意,可以使用相對檔案路徑(指向 LOCAL_PATH)和絕對檔案路徑。

建議避免使用絕對檔案路徑;相對路徑會使 Android.mk 檔案移植性更強。

注:在構建檔案中務必使用 Unix 樣式的正斜槓 (/)。構建系統無法正確處理 Windows 樣式的反斜槓 ()。

LOCAL_CPP_EXTENSION
可以使用此可選變數為 C++ 原始檔指明 .cpp 以外的副檔名。 例如,以下行會將副檔名改為 .cxx。(設定必須包含點。)

LOCAL_CPP_EXTENSION := .cxx
從 NDK r7 開始,您可以使用此變數指定多個副檔名。例如:

LOCAL_CPP_EXTENSION := .cxx .cpp .cc
LOCAL_CPP_FEATURES
可以使用此可選變數指明您的程式碼依賴於特定 C++ 功能。它在構建過程中啟用正確的編譯器和連結器標誌。 對於預構建的庫,此變數還可宣告二進位制檔案依賴哪些功能,從而幫助確保最終關聯正確工作。 建議使用此變數,而不要直接在 LOCAL_CPPFLAGS 定義中啟用 -frtti 和 -fexceptions。

使用此變數可讓構建系統對每個模組使用適當的標誌。使用 LOCAL_CPPFLAGS 會導致編譯器對所有模組使用所有指定的標誌,而不管實際需求如何。

例如,要指示您的程式碼使用 RTTI(執行時型別資訊),請編寫:
LOCAL_CPP_FEATURES := rtti
要指示您的程式碼使用 C++ 異常,請編寫:

LOCAL_CPP_FEATURES := exceptions
您還可為此變數指定多個值。例如:

LOCAL_CPP_FEATURES := rtti features
描述值的順序不重要。
LOCAL_C_INCLUDES
可以使用此可選變數指定相對於 NDK root 目錄的路徑列表,以便在編譯所有原始檔(C、C++ 和 Assembly)時新增到 include 搜尋路徑。 例如:

LOCAL_C_INCLUDES := sources/foo
甚至:

LOCAL_C_INCLUDES := $(LOCAL_PATH)//foo
在通過 LOCAL_CFLAGS 或 LOCAL_CPPFLAGS 設定任何對應的 include 標誌之前定義此變數。

在使用 ndk-gdb 啟動本地除錯時,構建系統也會自動使用 LOCAL_C_INCLUDES 路徑。

LOCAL_CFLAGS
此可選變數為構建系統設定在構建 C 和 C++ 原始檔時要傳遞的編譯器標誌。 此功能對於指定額外的巨集定義或編譯選項可能很有用。

儘量不要更改 Android.mk 檔案中的優化/除錯級別。構建系統可使用 Application.mk 檔案中的相關資訊自動為您處理此設定。 這樣允許構建系統生成在除錯時使用的有用資料檔案。

注:在 android-ndk-1.5_r1 中,相應的標誌只適用於 C 原始檔,而不適用於 C++ 原始檔。 它們現在與整個 Android 構建系統的行為匹配。(您現在可以使用 LOCAL_CPPFLAGS 只為 C++ 原始檔指定標誌。)

可通過編寫以下程式碼指定其他 include 路徑:

LOCAL_CFLAGS += -I<path>,
但使用 LOCAL_C_INCLUDES 更好,因為這樣也可以通過 ndk-gdb 使用可用於本地除錯的路徑。
LOCAL_CPPFLAGS
僅當構建 C++ 原始檔時才會傳遞一組可選的編譯器標誌。 它們將出現在編譯器命令列中的 LOCAL_CFLAGS 後面。

注:在 android-ndk-1.5_r1 中,相應的標誌適用於 C 和 C++ 原始檔。 這已經更正,可與整個 Android 構建系統的行為匹配。要為 C 和 C++ 原始檔指定標誌,請使用 LOCAL_CFLAGS。

LOCAL_STATIC_LIBRARIES
此變數用於儲存當前模組依賴的靜態庫模組列表。

如果當前模組是共享庫或可執行檔案,此變數將強制這些庫連結到生成的二進位制檔案。

如果當前模組是靜態庫,此變數只是指示,依賴當前模組的模組也會依賴列出的庫。

LOCAL_SHARED_LIBRARIES
此變數是此模組在執行時依賴的共享庫模組列表。 此資訊在連結時需要,並且會在生成的檔案中嵌入相應的資訊。

LOCAL_WHOLE_STATIC_LIBRARIES
此變數是 LOCAL_STATIC_LIBRARIES 的變體,表示連結器應將相關的庫模組視為整個存檔。 如需瞭解有關整個存檔的詳細資訊,請參閱 GNU 連結器關於 --whole-archive 標誌的文件。

當多個靜態庫之間具有迴圈相依關係時,此變數很有用。 使用此變數構建共享庫時,將會強制構建系統將所有物件檔案從靜態庫新增到最終二進位制檔案。 但在生成可執行檔案時不會發生這樣的情況。

LOCAL_LDLIBS
此變數包含在構建共享庫或可執行檔案時要使用的其他連結器標誌列表。 它可讓您使用 -l 字首傳遞特定系統庫的名稱。 例如,以下示例指示連結器生成在載入時連結到 /system/lib/libz.so 的模組:

LOCAL_LDLIBS := -lz
如需瞭解此 NDK 版本中可以連結的已公開系統庫列表,請參閱 Android NDK 原生 API。

注: 如果為靜態庫定義此變數,構建系統會忽略它,並且 ndk-build 會顯示一則警告。

LOCAL_LDFLAGS
構建共享庫或可執行檔案時供構建系統使用的其他連結器標誌列表。 例如,以下示例在 ARM/X86 GCC 4.6+ 上使用 ld.bfd 連結器,該系統上的預設連結器是 ld.gold

LOCAL_LDFLAGS += -fuse-ld=bfd
注:如果為靜態庫定義此變數,構建系統會忽略它,並且 ndk-build 會顯示一則警告。

LOCAL_ALLOW_UNDEFINED_SYMBOLS
預設情況下,若構建系統在嘗試構建共享庫時遇到未定義的引用,將會引發“未定義的符號”錯誤。 此錯誤可幫助您捕獲原始碼中的缺陷。

要停用此檢查,請將此變數設定為 true。請注意,此設定可能導致共享庫在執行時載入。

注: 如果為靜態庫定義此變數,構建系統會忽略它,並且 ndk-build 會顯示一則警告。

LOCAL_ARM_MODE
預設情況下,構建系統在 thumb 模式中生成 ARM 目標二進位制檔案,其中每個指令都是 16 位寬,並且與 thumb/ 目錄中的 STL 庫連結。將此變數定義為 arm 會強制構建系統在 32 位 arm 模式下生成模組的物件檔案。 以下示例顯示如何執行此操作:

LOCAL_ARM_MODE := arm
您也可以為原始檔名附加 .arm 字尾,指示構建系統只在 arm 模式中構建特定的原始檔。 例如,以下示例指示構建系統始終在 ARM 模式中編譯 bar.c,但根據 LOCAL_ARM_MODE 的值構建 foo.c。

LOCAL_SRC_FILES := foo.c bar.c.arm
注:您也可以在 Application.mk 檔案中將 APP_OPTIM 設定為 debug,強制構建系統生成 ARM 二進位制檔案。指定 debug 會強制構建 ARM,因為工具鏈除錯程式無法正確處理 Thumb 程式碼。

LOCAL_ARM_NEON
此變數僅在您針對 armeabi-v7a ABI 時才重要。它允許在 C 和 C++ 原始檔中使用 ARM Advanced SIMD (NEON) GCC 行內函數,以及在 Assembly 檔案中使用 NEON 指令。

請注意,並非所有基於 ARMv7 的 CPU 都支援 NEON 指令集擴充套件。因此,必須執行執行時檢測以便在執行時安全地使用此程式碼。 如需瞭解詳細資訊,請參閱 NEON 支援和 cpufeatures 庫。

或者,您也可以使用 .neon 字尾指定構建系統只編譯支援 NEON 的特定原始檔。 在以下示例中,構建系統編譯支援 thumb 和 neon 的 foo.c、支援 thumb 的 bar.c,以及支援 ARM 和 NEON 的 zoo.c。

LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon
如果您使用兩個字尾,.arm 必須在 .neon 前面。

LOCAL_DISABLE_NO_EXECUTE
Android NDK r4 新增了對“NX 位”安全功能的支援。此支援預設啟用,但您也可通過將此變數設定為 true 將其停用。 如果沒有必要的原因,我們不建議停用。

此功能不會修改 ABI,並且僅在針對 ARMv6+ CPU 裝置的核心上啟用。 啟用此功能的機器程式碼在執行較早 CPU 架構的裝置上將不加修改而直接執行。

如需瞭解詳細資訊,請參閱 Wikipedia:NX 位和 GNU 棧快速入門。

LOCAL_DISABLE_RELRO

預設情況下,NDK 編譯具有隻讀重定位和 GOT 保護的程式碼。 此變數指示執行時連結器在重定位後將某些記憶體區域標記為只讀,增加了某些安全漏洞利用(例如 GOT 覆蓋)的難度。 請注意,這些保護僅在 Android API 級別 16 和更高版本上有效。在較低的 API 級別上,該程式碼仍會執行,但沒有記憶體保護。

此變數預設啟用,但您也可通過將其值設定為 true 來停用它。 如果沒有必要的原因,我們不建議停用。

如需瞭解詳細資訊,請參閱 RELRO:重定位只讀和 RedHat Enterprise Linux 中的安全增強功能(第 6 節)。

LOCAL_DISABLE_FORMAT_STRING_CHECKS

預設情況下,構建系統編譯具有格式字串保護的程式碼。如果 printf 樣式的函式中使用非常量的格式字串,這樣會強制編譯器出錯。

此保護預設啟用,但您也可通過將此變數的值設定為 true 將其停用。 如果沒有必要的原因,我們不建議停用。

LOCAL_EXPORT_CFLAGS
此變數用於記錄一組 C/C++ 編譯器標誌,這將標誌將新增到通過 LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 變數使用它們的任何其他模組的 LOCAL_CFLAGS 定義。

例如,假設有以下模組對:foo 和 bar,分別依賴於 foo:

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=2
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)

在這裡,構建系統在構建 bar.c 時會向編譯器傳遞標誌 -DFOO=1 和 -DBAR=2。 它還會在模組的 LOCAL_CFLAGS 前面加上匯出的標誌,以便您輕鬆替換它們。

此外,模組之間的關係也是可傳遞的:如果 zoo 依賴於 bar,後者又依賴於 foo,則 zoo 也會繼承從 foo 匯出的所有標誌。
最後,構建系統在本地構建時不使用匯出的標誌(即,構建要匯出其標誌的模組)。 因此,在上面的示例中,構建 foo/foo.c 時不會將 -DFOO=1 傳遞到編譯器。 要在本地構建,請改用 LOCAL_CFLAGS。

LOCAL_EXPORT_CPPFLAGS
此變數與 LOCAL_EXPORT_CFLAGS 相同,但僅適用於 C++ 標誌。

LOCAL_EXPORT_C_INCLUDES
此變數與 LOCAL_EXPORT_CFLAGS 相同,但適用於 C include 路徑。例如,當 bar.c 需要包含模組 foo 中的標頭時很有用。

LOCAL_EXPORT_LDFLAGS
此變數與 LOCAL_EXPORT_CFLAGS 相同,但適用於連結器標誌。

LOCAL_EXPORT_LDLIBS
此變數與 LOCAL_EXPORT_CFLAGS 相同,用於指示構建系統將特定系統庫的名稱傳遞到編譯器。 在您指定的每個庫名稱前面附加 -l。

請注意,構建系統會將匯入的連結器標誌附加到模組的 LOCAL_LDLIBS 變數值。 其原因在於 Unix 連結器執行的方式。

當模組 foo 是靜態庫並且具有依賴於系統庫的程式碼時,此變數通常很有用。 然後您可以使用 LOCAL_EXPORT_LDLIBS 匯出相依關係。 例如:

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)

在此示例中,構建系統在構建 libbar.so 時,將在連結器命令的末尾放置 -llog。 這樣會告知連結器,由於 libbar.so 依賴於 foo,因此它也依賴於系統日誌記錄庫。

LOCAL_SHORT_COMMANDS
當您的模組有很多原始檔和/或相依的靜態或共享庫時,將此變數設定為 true。 這樣會強制構建系統對包含中間物件檔案或連結庫的存檔使用 @ 語法。

此功能在 Windows 上可能很有用,其中命令列最多隻接受 8191 個字元,這對於複雜的專案可能太少。 它還會影響個別原始檔的編譯,而且將幾乎所有編譯器標誌放在列表檔案內。

請注意,true 以外的任何值都將恢復到預設行為。 您也可在 Application.mk 檔案中定義 APP_SHORT_COMMANDS,以強制對專案中的所有模組實施此行為。

不建議預設啟用此功能,因為它會減慢構建的速度。

LOCAL_THIN_ARCHIVE
構建靜態庫時將此變數設定為 true。這樣會生成一個瘦存檔 ,即一個庫檔案,其中不含物件檔案,而只包含它通常要包含的實際物件的檔案路徑。

這對於減小構建輸出的大小非常有用。缺點是:這樣的庫無法移至不同的位置(其中的所有路徑都是相對的)。

有效值為 true、false 或空白。可通過 APP_THIN_ARCHIVE 變數在 Application.mk 檔案中設定預設值。

注:對於非靜態庫模組或預構建的靜態庫模組會忽略此變數。

LOCAL_FILTER_ASM
將此變數定義為構建系統要用於過濾從您為 LOCAL_SRC_FILES 指定的檔案提取或生成的彙編檔案的 shell 命令。

定義此變數會導致發生以下情況:

構建系統從任何 C 或 C++ 原始檔生成臨時彙編檔案,而不是將它們編譯到物件檔案。
構建系統在任何臨時彙編檔案以及 LOCAL_SRC_FILES 中所列任何彙編檔案的 LOCAL_FILTER_ASM 中執行 shell 命令,因此會生成另一個臨時彙編檔案。
構建系統將這些過濾的彙編檔案編譯到物件檔案中。
例如:

LOCAL_SRC_FILES  := foo.c bar.S
LOCAL_FILTER_ASM :=

foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.o
bar.S                                 --2--> $OBJS_DIR/bar.S --3--> $OBJS_DIR/bar.o

“1”對應編譯器,“2”對應過濾器,“3”對應彙編程式。過濾器必須是採用輸入檔名稱作為其第一個引數、輸出檔名稱作為第二個引數的獨立 shell 命令。 例如:

myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S
myasmfilter bar.S $OBJS_DIR/bar.S

NDK 提供的函式巨集
本節說明 NDK 提供的 GNU Make 函式巨集。使用 $(call <function>) 對它們估值;它們返回文字資訊。

my-dir
此巨集返回最後包含的 makefile 的路徑,通常是當前 Android.mk 的目錄。my-dir 可用於在 Android.mk 檔案的開頭定義 LOCAL_PATH。 例如:

LOCAL_PATH := $(call my-dir)
由於 GNU Make 執行的方式,此巨集實際返回的內容是構建系統在解析構建指令碼時包含在最後一個 makefile 的路徑。 因此,在包含另一個檔案後不應呼叫 my-dir。

例如,考慮以下示例:

LOCAL_PATH := $(call my-dir)

declare one module

include $(LOCAL_PATH)/foo/Android.mk

LOCAL_PATH := $(call my-dir)

declare another module
這裡的問題在於,對 my-dir 的第二次呼叫將 LOCAL_PATH 定義為 PATH,因為這是其最近 include 指向的位置。

在 Android.mk 檔案中的任何其他內容後放置額外 include 可避免此問題。 例如:

LOCAL_PATH := $(call my-dir)

... declare one module

LOCAL_PATH := $(call my-dir)

... declare another module

extra includes at the end of the Android.mk file
include $(LOCAL_PATH)/foo/Android.mk

如果以這種方式構建檔案不可行,請將第一個 my-dir 呼叫的值儲存到另一個變數中。 例如:

MY_LOCAL_PATH := $(call my-dir)

LOCAL_PATH := $(MY_LOCAL_PATH)

... declare one module

include $(LOCAL_PATH)/foo/`Android.mk`

LOCAL_PATH := $(MY_LOCAL_PATH)

... declare another module
all-subdir-makefiles
返回位於當前 my-dir 路徑所有子目錄中的 Android.mk 檔案列表。

可以使用此函式為構建系統提供深入巢狀的源目錄層次結構。 預設情況下,NDK 只在包含 Android.mk 檔案的目錄中查詢檔案。

this-makefile
返回當前 makefile(構建系統從中呼叫函式)的路徑。

parent-makefile
返回包含樹中父 makefile 的路徑(包含當前 makefile 的 makefile 路徑)。

grand-parent-makefile
返回包含樹中祖父 makefile 的路徑(包含當前父 makefile 的 makefile 路徑)。

import-module
用於按模組的名稱查詢和包含模組的 Android.mk 檔案的函式。 典型的示例如下所示:

$(call import-module,<name>)
在此示例中,構建系統查詢 NDK_MODULE_PATH 環境變數引用的目錄列表中以 <name> 標記的模組,並且自動為您包含其Android.mk 檔案。

純make練習語法。

window使用cygwin64 把bin目錄新增到環境變數中
make -f myfile.mk 測試一個mk檔案。

make預設識別的檔案是當前執行目錄下的Makefile不帶字尾檔案。

myfile.mk內容如下

$(warning nihao)
LOCAL_PATH:= current_$(call my-dir)
$(warning $(LOCAL_PATH))

my-dir沒有輸出任何東西,因為這要安卓的ndk-build才有。
測試這個檔案的方法
make -f myfile.mk
或者在此目錄建立Makefile然後輸入include myfile.mk 執行make將自動執行.

定義Make target

語法格式與執行

target名:
TAB命令列名

aa:
    gcc -o hello hello.c
    ./hello.exe

切記gcc前面是用tab隔開的,否則會報錯誤。
測試執行
make -f mymake.mk aa

如果不出意外會編譯當前目錄的hello.c並執行,前提是hello.c存在以及配置了gcc的環境變數。

完整示例:

#配置環境變數make,用法 輸入 make -f test.mk
#圖示是可以指定的,如果沒有指定目標會找到第一個,如果傳遞了目標比如傳遞make -f test.mk run:則會執行後者,而不是前者。
VARIABLE1:= 555
$(param $(1))
$(info 2-$(VARIABLE1))
aa=$(call VARIABLE1,hello,world)#不用冒號也可以定義?/
$(warning 你可以輸入make -f test.mk help執行選單幫助)

$(info 2-$(aa))
help:
    @echo 歡迎學習mk,你如果能執行本檔案,那麼你應該可以算和我一樣已經找到了寫make的感覺了。
    @echo 輸入make -f 檔案 run 執行檔案
    @echo 輸入make -f 檔案 compile 編譯檔案
    @echo 執行了all任務,
    @echo 你好 你好 target下面的東西都需要用空格隔開,否則會出現語法錯誤。
    @echo make語法中以艾特開頭可以執行系統的命令,如echo就屬於.
    
    
    
$(warning Wellcome Study write makefile)
TEMP:=HELLO
$(warning execcompile)#不執行..似乎不能連續輸出多個
compile:bbb #這個值1:值2是必須寫的,否則報錯。
    gcc -o foo hello.c
    ./foo.exe
    @echo 執行編譯完成


run:
    @echo 執行了run
    ./foo.exe

參考資料

相關文章