makefile編寫

#設置當編譯路徑爲當前文件夾所在路徑
LOCAL_PATH := $(call my-dir)

#清空編譯環境的變量(由其他模塊設置過的變量)
include $(CLEAR_VARS)

其中:
#BUILD_STATIC_LIBRARY:編譯爲靜態庫。 
#BUILD_SHARED_LIBRARY :編譯爲動態庫 
#BUILD_EXECUTABLE:編譯爲Native C可執行程序 

LOCAL_PATH:=$(call my-dir)

Android.mk文件首先需要指定LOCAL_PATH變量,用於查找源文件。由於一般情況下
Android.mk和需要編譯的源文件在同一目錄下,所以定義成如下形式:

include (CLEARVARS)...include (BUILD_XXX)

Android.mk中可以定義多個編譯模塊,每個編譯模塊都是以include $(CLEAR_VARS)開始,以include $(BUILD_XXX)結束。

include $(CLEAR_VARS)
CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE爲你清除除LOCAL_PATH以外的所有LOCAL_XXX變量,
如:LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_SHARED_LIBRARIES,LOCAL_STATIC_LIBRARIES等。

  • include $(BUILD_STATIC_LIBRARY)表示編譯成靜態庫
  • include $(BUILD_SHARED_LIBRARY)表示編譯成動態庫。
  • include $(BUILD_EXECUTABLE)表示編譯成可執行程序

舉例:
frameworks/base/libs/audioflinger/Android.mk

#編譯當前目錄
LOCAL_PATH:= $(call my-dir)
#模塊一
include $(CLEAR_VARS)  
ifeq ($(AUDIO_POLICY_TEST),true)
  ENABLE_AUDIO_DUMP := true
endif
LOCAL_SRC_FILES:= \
    AudioHardwareGeneric.cpp \
    AudioHardwareStub.cpp \
    AudioHardwareInterface.cpp
ifeq ($(ENABLE_AUDIO_DUMP),true)
  LOCAL_SRC_FILES += AudioDumpInterface.cpp
  LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
endif
LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    libbinder \
    libmedia \
    libhardware_legacy
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
  LOCAL_CFLAGS += -DGENERIC_AUDIO
endif
LOCAL_MODULE:= libaudiointerface
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  LOCAL_SRC_FILES += A2dpAudioInterface.cpp
  LOCAL_SHARED_LIBRARIES += liba2dp
  LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
  LOCAL_C_INCLUDES += $(call include-path-for, bluez)
endif
include $(BUILD_STATIC_LIBRARY)  #模塊一編譯成靜態庫

#繼續編寫模塊2
#模塊二
include $(CLEAR_VARS)  
LOCAL_SRC_FILES:=               \
    AudioPolicyManagerBase.cpp
LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    libmedia
ifeq ($(TARGET_SIMULATOR),true)
 LOCAL_LDLIBS += -ldl
else
 LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudiopolicybase
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  LOCAL_CFLAGS += -DWITH_A2DP
endif
ifeq ($(AUDIO_POLICY_TEST),true)
  LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif

補充知識

ifeq ($(變量名), 變量值 )
........
else ifeq ($(..), ..)
.........
else
.........
endif

編譯apk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all Java files in the java subdirectory-->直譯(建立在java子目錄中的所有Java文件)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build-->直譯(創建APK的名稱)
LOCAL_PACKAGE_NAME := LocalPackage
# Tell it to build an APK-->直譯(告訴它來建立一個APK)
include $(BUILD_PACKAGE)

編譯一個依賴於靜態Java庫(static.jar)的應用程序

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

# List of static libraries to include in the package
LOCAL_STATIC_JAVA_LIBRARIES := static-library

# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)

# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage

# Tell it to build an APK
include $(BUILD_PACKAGE)

編譯一個需要用平臺的key簽名的應用程序

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)

# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage

LOCAL_CERTIFICATE := platform

# Tell it to build an APK
include $(BUILD_PACKAGE)

編譯一個需要用特定key前面的應用程序

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)

# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage

LOCAL_CERTIFICATE := vendor/example/certs/app

# Tell it to build an APK
include $(BUILD_PACKAGE)

“`

(8)添加一個預編譯應用程序
LOCAL_PATH := (callmydir)include (CLEAR_VARS)

# Module name should match apk name to be installed.
LOCAL_MODULE := LocalModuleName
LOCAL_SRC_FILES := (LOCALMODULE).apkLOCALMODULECLASS:=APPSLOCALMODULESUFFIX:= (COMMON_ANDROID_PACKAGE_SUFFIX)

include $(BUILD_PREBUILT)

(9)添加一個靜態JAVA庫
LOCAL_PATH := (callmydir)include (CLEAR_VARS)

# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)

# Any libraries that this library depends on
LOCAL_JAVA_LIBRARIES := android.test.runner

# The name of the jar file to create
LOCAL_MODULE := sample

# Build a static jar file.
include $(BUILD_STATIC_JAVA_LIBRARY)

(10)Android.mk的編譯模塊中間可以定義相關的編譯內容,也就是指定相關的變量如下:
LOCAL_AAPT_FLAGS

LOCAL_ACP_UNAVAILABLE

LOCAL_ADDITIONAL_JAVA_DIR

LOCAL_AIDL_INCLUDES

LOCAL_ALLOW_UNDEFINED_SYMBOLS

LOCAL_ARM_MODE

LOCAL_ASFLAGS

LOCAL_ASSET_DIR

LOCAL_ASSET_FILES 在Android.mk文件中編譯應用程序(BUILD_PACKAGE)時設置此變量,表示資源文件,
通常會定義成LOCAL_ASSET_FILES += $(call find-subdir-assets)

LOCAL_BUILT_MODULE_STEM
LOCAL_C_INCLUDES 額外的C/C++編譯頭文件路徑,用LOCAL_PATH表示本文件所在目錄
舉例如下:
LOCAL_C_INCLUDES += extlibs/zlib-1.2.3
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src

LOCAL_CC 指定C編譯器

LOCAL_CERTIFICATE 簽名認證

LOCAL_CFLAGS 爲C/C++編譯器定義額外的標誌(如宏定義),舉例:LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1

LOCAL_CLASSPATH

LOCAL_COMPRESS_MODULE_SYMBOLS

LOCAL_COPY_HEADERS install應用程序時需要複製的頭文件,必須同時定義LOCAL_COPY_HEADERS_TO

LOCAL_COPY_HEADERS_TO install應用程序時複製頭文件的目的路徑

LOCAL_CPP_EXTENSION 如果你的C++文件不是以cpp爲文件後綴,你可以通過LOCAL_CPP_EXTENSION指定C++文件後綴名
如:LOCAL_CPP_EXTENSION := .cc
注意統一模塊中C++文件後綴必須保持一致。

LOCAL_CPPFLAGS 傳遞額外的標誌給C++編譯器,如:LOCAL_CPPFLAGS += -ffriend-injection

LOCAL_CXX 指定C++編譯器

LOCAL_DX_FLAGS

LOCAL_EXPORT_PACKAGE_RESOURCES

LOCAL_FORCE_STATIC_EXECUTABLE 如果編譯的可執行程序要進行靜態鏈接(執行時不依賴於任何動態庫),則設置LOCAL_FORCE_STATIC_EXECUTABLE:=true
目前只有libc有靜態庫形式,這個只有文件系統中/sbin目錄下的應用程序會用到,這個目錄下的應用程序在運行時通常
文件系統的其它部分還沒有加載,所以必須進行靜態鏈接。

LOCAL_GENERATED_SOURCES

LOCAL_INSTRUMENTATION_FOR

LOCAL_INSTRUMENTATION_FOR_PACKAGE_NAME

LOCAL_INTERMEDIATE_SOURCES

LOCAL_INTERMEDIATE_TARGETS

LOCAL_IS_HOST_MODULE

LOCAL_JAR_MANIFEST

LOCAL_JARJAR_RULES

LOCAL_JAVA_LIBRARIES 編譯java應用程序和庫的時候指定包含的java類庫,目前有core和framework兩種
多數情況下定義成:LOCAL_JAVA_LIBRARIES := core framework
注意LOCAL_JAVA_LIBRARIES不是必須的,而且編譯APK時不允許定義(系統會自動添加)

LOCAL_JAVA_RESOURCE_DIRS

LOCAL_JAVA_RESOURCE_FILES

LOCAL_JNI_SHARED_LIBRARIES

LOCAL_LDFLAGS 傳遞額外的參數給連接器(務必注意參數的順序)

LOCAL_LDLIBS 爲可執行程序或者庫的編譯指定額外的庫,指定庫以”-lxxx”格式,舉例:
LOCAL_LDLIBS += -lcurses -lpthread
LOCAL_LDLIBS += -Wl,-z,origin

LOCAL_MODULE 生成的模塊的名稱(注意應用程序名稱用LOCAL_PACKAGE_NAME而不是LOCAL_MODULE)

LOCAL_MODULE_PATH 生成模塊的路徑

LOCAL_MODULE_STEM

LOCAL_MODULE_TAGS 生成模塊的標記

LOCAL_NO_DEFAULT_COMPILER_FLAGS

LOCAL_NO_EMMA_COMPILE

LOCAL_NO_EMMA_INSTRUMENT

LOCAL_NO_STANDARD_LIBRARIES

LOCAL_OVERRIDES_PACKAGES

LOCAL_PACKAGE_NAME APK應用程序的名稱

LOCAL_POST_PROCESS_COMMAND

LOCAL_PREBUILT_EXECUTABLES 預編譯including (BUILDPREBUILT) (BUILD_HOST_PREBUILT)時所用,指定需要複製的可執行文件

LOCAL_PREBUILT_JAVA_LIBRARIES

LOCAL_PREBUILT_LIBS 預編譯including (BUILDPREBUILT) (BUILD_HOST_PREBUILT)時所用, 指定需要複製的庫.

LOCAL_PREBUILT_OBJ_FILES

LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES

LOCAL_PRELINK_MODULE 是否需要預連接處理(默認需要,用來做動態庫優化)

LOCAL_REQUIRED_MODULES 指定模塊運行所依賴的模塊(模塊安裝時將會同步安裝它所依賴的模塊)

LOCAL_RESOURCE_DIR

LOCAL_SDK_VERSION

LOCAL_SHARED_LIBRARIES 可鏈接動態庫

LOCAL_SRC_FILES 編譯源文件

LOCAL_STATIC_JAVA_LIBRARIES

LOCAL_STATIC_LIBRARIES 可鏈接靜態庫

LOCAL_UNINSTALLABLE_MODULE

LOCAL_UNSTRIPPED_PATH

LOCAL_WHOLE_STATIC_LIBRARIES 指定模塊所需要載入的完整靜態庫(這些精通庫在鏈接是不允許鏈接器刪除其中無用的代碼)

LOCAL_YACCFLAGS

OVERRIDE_BUILT_MODULE_PATH

接下來我們詳細看一下android裏的makefile文件

android最頂層的目錄結構如下:
.
|– Makefile (全局的Makefile)
|– bionic (Bionic含義爲仿生,這裏面是一些基礎的庫的源代碼)
|– bootloader (引導加載器)
|– build (build目錄中的內容不是目標所用的代碼,而是編譯和配置所需要的腳本和工具)
|– dalvik (JAVA虛擬機)
|– development (程序開發所需要的模板和工具)
|– external (目標機器使用的一些庫)
|– frameworks (應用程序的框架層)
|– hardware (與硬件相關的庫)
|– kernel (Linux2.6的源代碼)
|– packages (Android的各種應用程序)
|– prebuilt (Android在各種平臺下編譯的預置腳本)
|– recovery (與目標的恢復功能相關)
`– system (Android的底層的一些庫)
本文將要分析的是build目錄下的makefile和shell文件,android的代碼是1.5的版本。
主要的目錄結構如下:
1.makefile入門
1.1 makefile helloworld
1.2 用makefile構建交叉編譯環境
1.3 makefile裏面的一些技巧
2.android makefile分析
2.1 android shell分析
2.2 android build下的各個makefile分析
3. android其他目錄的android.mk分析

大家先通過網絡的一些文章來了解一下andoroid的makefile。
1.
Android build system
2.
Android Building System 分析
3.
Android Build System(介紹使用)
1.1 makefile helloworld

Makefile的規則如下:

target … : prerequisites …

command … …

target可以是一個目標文件,也可以是Object File(例如helloworld.obj),也可以是執行文件和標籤。

prerequisites就是生成target所需要的文件或是目標。

command
也就是要達到target這個目標所需要執行的命令。這裏沒有說“使用生成target所需要執行的命令”,是因爲target可能是標籤。需要注意的是
command前面必須是TAB鍵,而不是空格,因此喜歡在編輯器裏面將TAB鍵用空格替換的人需要特別小心了。

我們寫程序一般喜歡寫helloworld,當我們寫了一個c的helloworld之後,我們該如何寫helloworld來編譯helloworld.c呢?

下面就是編譯helloworld的makefile。

helloworld : helloworld.o

cc -o helloworld helloworld .o

helloworld.o : helloworld.c

cc -c main.c

clean:

rm helloworld helloworl.o

之後我們執行make就可以編譯helloworld.c了,執行make clean就可以清除編譯結果了(其實就是刪除helloworld helloworl.o)。

可能有人問爲什麼執行make就會生成helloworld呢?這得從make的默認處理說起:make將makefile的第一個target作爲作爲最終的
target,凡是這個規則依賴的規則都將被執行,否則就不會執行。所以在執行make的時候,clean這個規則就沒有被執行。

上面的是最簡單的makefile,複雜點makefile就開始使用高級點的技巧了,例如使用變量,使用隱式規則,執行負責點shell命令(常見的是字符串處理和文件處理等),這裏不打算介紹這些規則,後面在分析android的makefile時會結合具體代碼進行具體分析,大家可以先看看陳皓的《跟我一起寫makefile》來了解了解。

發佈了68 篇原創文章 · 獲贊 12 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章