Android.mk官方詳解

Android.mk

本頁介紹了 ndk-build 所使用的 Android.mk 編譯文件的語法。

概覽

Android.mk 文件位於項目 jni/ 目錄的子目錄中,用於向編譯系統描述源文件和共享庫。它實際上是編譯系統解析一次或多次的微小 GNU makefile 片段。Android.mk 文件用於定義 Application.mk、編譯系統和環境變量所未定義的項目範圍設置。它還可替換特定模塊的項目範圍設置。

Android.mk 的語法支持將源文件分組爲模塊。模塊是靜態庫、共享庫或獨立的可執行文件。您可在每個 Android.mk 文件中定義一個或多個模塊,也可在多個模塊中使用同一個源文件。編譯系統只將共享庫放入您的應用軟件包。此外,靜態庫可生成共享庫。

除了封裝庫之外,編譯系統還可爲您處理各種其他事項。例如,您無需在 Android.mk 文件中列出頭文件或生成的文件之間的顯式依賴關係。NDK 編譯系統會自動計算這些關係。因此,您應該能夠享受到未來 NDK 版本中新工具鏈/平臺支持帶來的益處,而無需處理 Android.mk 文件。

此文件的語法與隨整個 Android 開源項目分發的 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_FILES 和 LOCAL_STATIC_LIBRARIES。請注意,GNU Makefile 不會清除 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 定義的 include 變量

本部分探討了編譯系統在解析 Android.mk 文件前定義的 GNU Make 變量。在某些情況下,NDK 可能會多次解析 Android.mk 文件,每次使用其中某些變量的不同定義。

CLEAR_VARS

此變量指向的編譯腳本用於取消定義下文“開發者定義的變量”部分中列出的幾乎所有 LOCAL_XXX 變量。在描述新模塊之前,請使用此變量來包含此腳本。使用它的語法爲:

include $(CLEAR_VARS)
    

 

BUILD_SHARED_LIBRARY

此變量指向的編譯腳本用於收集您在 LOCAL_XXX 變量中提供的模塊的所有相關信息,以及確定如何根據您列出的源文件編譯目標共享庫。請注意,使用此腳本要求您至少已經爲 LOCAL_MODULE 和 LOCAL_SRC_FILES 賦值(要詳細瞭解這些變量,請參閱模塊描述變量)。

使用此變量的語法爲:

include $(BUILD_SHARED_LIBRARY)
    

 

共享庫變量會導致編譯系統生成擴展名爲 .so 的庫文件。

BUILD_STATIC_LIBRARY

用於編譯靜態庫的 BUILD_SHARED_LIBRARY 的變體。編譯系統不會將靜態庫複製到您的項目/軟件包中,但可以使用靜態庫編譯共享庫(請參閱下文的 LOCAL_STATIC_LIBRARIES 和 LOCAL_WHOLE_STATIC_LIBRARIES)。使用此變量的語法爲:

include $(BUILD_STATIC_LIBRARY)
    

 

靜態庫變量會導致編譯系統生成擴展名爲 .a 的庫。

PREBUILT_SHARED_LIBRARY

指向用於指定預編譯共享庫的編譯腳本。與 BUILD_SHARED_LIBRARY 和 BUILD_STATIC_LIBRARY 的情況不同,這裏的 LOCAL_SRC_FILES 值不能是源文件,而必須是指向預編譯共享庫的一個路徑,例如 foo/libfoo.so。使用此變量的語法爲:

include $(PREBUILT_SHARED_LIBRARY)
    

 

您也可以使用 LOCAL_PREBUILTS 變量引用另一個模塊中的預編譯庫。要詳細瞭解如何使用預編譯庫,請參閱使用預編譯庫

PREBUILT_STATIC_LIBRARY

與 PREBUILT_SHARED_LIBRARY 相同,但用於預編譯靜態庫。要詳細瞭解如何使用預編譯庫,請參閱使用預編譯庫

目標信息變量

編譯系統會根據 APP_ABI 變量所指定的每個 ABI 解析 Android.mk 一次,該變量通常在 Application.mk 文件中定義。如果 APP_ABI 爲 all,則編譯系統會根據 NDK 支持的每個 ABI 解析 Android.mk 一次。本部分介紹了編譯系統每次解析 Android.mk 時定義的變量。

TARGET_ARCH

編譯系統解析此 Android.mk 文件時面向的 CPU 系列。此變量是 armarm64x86 或 x86_64 之一。

TARGET_PLATFORM

編譯系統解析此 Android.mk 文件時面向的 Android API 級別編號。例如,Android 5.1 系統映像對應於 Android API 級別 22:android-22。如需平臺名稱和對應 Android 系統映像的完整列表,請參閱 Android NDK 原生 API。以下示例演示了使用此變量的語法:

ifeq ($(TARGET_PLATFORM),android-22)
        # ... do something ...
    endif
    

 

TARGET_ARCH_ABI

編譯系統解析此 Android.mk 文件時面向的 ABI。表 1 顯示用於每個受支持 CPU 和架構的 ABI 設置。

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

CPU 和架構 設置
ARMv7 armeabi-v7a
ARMv8 AArch64 arm64-v8a
i686 x86
x86-64 x86_64

以下示例演示瞭如何檢查 ARMv8 AArch64 是否爲目標 CPU 與 ABI 的組合:

ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
      # ... do something ...
    endif
    

 

要詳細瞭解架構 ABI 和相關兼容性問題,請參閱 ABI 管理

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

TARGET_ABI

目標 Android API 級別與 ABI 的連接,特別適用於要針對實際設備測試特定目標系統映像的情況。例如,要檢查搭載 Android API 級別 22 的 64 位 ARM 設備:

ifeq ($(TARGET_ABI),android-22-arm64-v8a)
      # ... do something ...
    endif
    

 

模塊描述變量

本部分中的變量會向編譯系統描述您的模塊。每個模塊描述都應遵守以下基本流程:

  1. 使用 CLEAR_VARS 變量初始化或取消定義與模塊相關的變量。
  2. 爲用於描述模塊的變量賦值。
  3. 使用 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
    

 

您可以使用此變量指定多個擴展名。例如:

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)/<subdirectory>/foo
    

 

請在通過 LOCAL_CFLAGS 或 LOCAL_CPPFLAGS 設置任何對應的包含標記前定義此變量。

在使用 ndk-gdb 啓動原生調試時,編譯系統也會自動使用 LOCAL_C_INCLUDES 路徑。

LOCAL_CFLAGS

此可選變量用於設置在編譯 C 和 C++ 源文件時編譯系統要傳遞的編譯器標記。這樣,您就可以指定額外的宏定義或編譯選項。可以使用 LOCAL_CPPFLAGS 僅爲 C++ 指定標記。

請勿嘗試在 Android.mk 文件中更改優化/調試級別。編譯系統可以使用 [pplication.mk] 文件中的相關信息自動處理此設置。這樣,編譯系統就可以生成供調試期間使用的有用數據文件。

您可通過輸入以下代碼指定額外的 include 路徑:

LOCAL_CFLAGS += -I<path>,
    

 

但是,最好使用 LOCAL_C_INCLUDES,因爲這樣也可以使用可用於 ndk-gdb 原生調試的路徑。

LOCAL_CPPFLAGS

只編譯 C++ 源文件時將傳遞的一組可選編譯器標記。它們將出現在編譯器命令行中的 LOCAL_CFLAGS 後面。使用 LOCAL_CFLAGS 爲 C 和 C++ 指定標記。

LOCAL_STATIC_LIBRARIES

此變量用於存儲當前模塊依賴的靜態庫模塊列表。

如果當前模塊是共享庫或可執行文件,此變量將強制這些庫鏈接到生成的二進制文件。

如果當前模塊是靜態庫,此變量只是指出依賴於當前模塊的其他模塊也會依賴於列出的庫。

LOCAL_SHARED_LIBRARIES

此變量會列出此模塊在運行時依賴的共享庫模塊。此信息是鏈接時必需的信息,用於將相應的信息嵌入到生成的文件中。

LOCAL_WHOLE_STATIC_LIBRARIES

此變量是 LOCAL_STATIC_LIBRARIES 的變體,表示鏈接器應將相關的庫模塊視爲完整歸檔。要詳細瞭解完整歸檔,請參閱 GNU ld 文檔的 --whole-archive 標記部分。

多個靜態庫之間存在循環依賴關係時,此變量很有用。使用此變量編譯共享庫時,它將強制編譯系統將靜態庫中的所有對象文件添加到最終二進制文件。但是,生成可執行文件時不會發生這種情況。

LOCAL_LDLIBS

此變量列出了在編譯共享庫或可執行文件時使用的額外鏈接器標記。利用此變量,您可使用 -l 前綴傳遞特定系統庫的名稱。例如,以下示例指示鏈接器生成在加載時鏈接到 /system/lib/libz.so 的模塊:

LOCAL_LDLIBS := -lz
    

 

如需瞭解此 NDK 版本中可以鏈接的公開系統庫列表,請參閱 Android NDK 原生 API

注意:如果爲靜態庫定義此變量,編譯系統會忽略此變量,並且 ndk-build 會顯示一則警告。

LOCAL_LDFLAGS

此變量列出了編譯系統在編譯共享庫或可執行文件時使用的其他鏈接器標記。例如,要在 ARM/X86 上使用 ld.bfd 鏈接器:

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) 編譯器內建函數,以及在 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_FORMAT_STRING_CHECKS

默認情況下,編譯系統會在編譯代碼時保護格式字符串。這樣的話,如果 printf 樣式的函數中使用了非常量格式的字符串,就會強制引發編譯器錯誤。此保護默認啓用,但您也可通過將此變量的值設置爲 true 將其停用。如果沒有必要的原因,我們不建議停用。

LOCAL_EXPORT_CFLAGS

此變量用於記錄一組 C/C++ 編譯器標記,這些標記將添加到通過 LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 變量使用此模塊的任何其他模塊的 LOCAL_CFLAGS 定義中。

例如,假設有下面這一對模塊:foo 和 bar,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 上可能很有用,在 Windows 上,命令行最多隻接受 8191 個字符,這對於複雜的項目來說可能太少。它還會影響個別源文件的編譯,而且將幾乎所有編譯器標記都放在列表文件內。

請注意,true 以外的任何值都將恢復爲默認行爲。您也可以在 Application.mk 文件中定義 APP_SHORT_COMMANDS,以對項目中的所有模塊強制實施此行爲。

不建議默認啓用此功能,因爲它會減慢編譯速度。

LOCAL_THIN_ARCHIVE

編譯靜態庫時,請將此變量設置爲 true。這樣會生成一個瘦歸檔,即一個庫文件,其中不含對象文件,而只包含它通常包含的實際對象的文件路徑。

這對於減小編譯輸出的大小非常有用。但缺點是,這樣的庫無法移至其他位置(其中的所有路徑都是相對路徑)。

有效值爲 truefalse 或空白。您可在 Application.mk 文件中通過 APP_THIN_ARCHIVE 變量設置默認值。

注意:在非靜態庫模塊或預編譯的靜態庫模塊中,將會忽略此變量。

LOCAL_FILTER_ASM

請將此變量定義爲一個 shell 命令,供編譯系統用於過濾根據您爲 LOCAL_SRC_FILES 指定的文件提取或生成的彙編文件。定義此變量會導致發生以下情況:

  1. 編譯系統從任何 C 或 C++ 源文件生成臨時彙編文件,而不是將它們編譯到對象文件中。
  2. 編譯系統在任何臨時彙編文件以及 LOCAL_SRC_FILES 中所列任何彙編文件的 LOCAL_FILTER_ASM 中執行 shell 命令,因此會生成另一個臨時彙編文件。
  3. 編譯系統將這些過濾的彙編文件編譯到對象文件中。

例如:

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/foo,而不是 $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 文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章