android裏的makefile

轉載自原文地址:http://blog.csdn.net/andy_android/article/details/6960314

 

(1)Android.mk文件首先需要指定LOCAL_PATH變量,用於查找源文件。由於一般情況下
Android.mk和需要編譯的源文件在同一目錄下,所以定義成如下形式:
LOCAL_PATH:=$(call my-dir)
上面的語句的意思是將LOCAL_PATH變量定義成本文件所在目錄路徑。

(2)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)表示編譯成可執行程序

(3)舉例如下(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)  模塊一編譯成靜態庫
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
include $(BUILD_STATIC_LIBRARY) 模塊二編譯成靜態庫
include $(CLEAR_VARS) 模塊三
LOCAL_SRC_FILES:=               \
    AudioFlinger.cpp            \
    AudioMixer.cpp.arm          \
    AudioResampler.cpp.arm      \
    AudioResamplerSinc.cpp.arm  \
    AudioResamplerCubic.cpp.arm \
    AudioPolicyService.cpp
LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    libbinder \
    libmedia \
    libhardware_legacy
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
  LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
  LOCAL_CFLAGS += -DGENERIC_AUDIO
else
  LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
endif
ifeq ($(TARGET_SIMULATOR),true)
 LOCAL_LDLIBS += -ldl
else
 LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudioflinger
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
  LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
  LOCAL_SHARED_LIBRARIES += liba2dp
endif
ifeq ($(AUDIO_POLICY_TEST),true)
  LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
endif
ifeq ($(TARGET_SIMULATOR),true)
    ifeq ($(HOST_OS),linux)
        LOCAL_LDLIBS += -lrt -lpthread
    endif
endif
ifeq ($(BOARD_USE_LVMX),true)
    LOCAL_CFLAGS += -DLVMX
    LOCAL_C_INCLUDES += vendor/nxp
    LOCAL_STATIC_LIBRARIES += liblifevibes
    LOCAL_SHARED_LIBRARIES += liblvmxservice
#    LOCAL_SHARED_LIBRARIES += liblvmxipc
endif
include $(BUILD_SHARED_LIBRARY) 模塊三編譯成動態庫


(4)編譯一個應用程序(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)

(5)編譯一個依賴於靜態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)

(6)編譯一個需要用平臺的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)


(7)編譯一個需要用特定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 := $(call my-dir)
  include $(CLEAR_VARS)
   
  # Module name should match apk name to be installed.
  LOCAL_MODULE := LocalModuleName
  LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
  LOCAL_MODULE_CLASS := APPS
  LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
   
  include $(BUILD_PREBUILT)

(9)添加一個靜態JAVA庫
  LOCAL_PATH := $(call my-dir)
  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 $(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用,指定需要複製的可執行文件

LOCAL_PREBUILT_JAVA_LIBRARIES 

LOCAL_PREBUILT_LIBS 預編譯including $(BUILD_PREBUILT)或者$(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》來了解了解。 
   
makefile的大體的結構是程序樹形的,如下: 
   
                                                      
 

   
這樣寫起makefile也簡單,我們將要達到的目標作爲第一個規則,然後將目標分解成子目標,然後一個個寫規則,依次類推,直到最下面的規則很容易實現爲止。這其實和算法裏面的分治法很像,將一個複雜的問題分而治之。 
   
 
到樹,我想到了編譯原理裏面的語法分析,語法分析裏面有自頂而下的分析方法和自底而下的分析方法。當然makefile並不是要做語法分析,而是要做與語 
法分析分析相反的事。(語法分析要做的是一個句子是不是根據語法可以推出來,而makefile要做的是根據規則生成一個command 
執行隊列。)不過makefile的規則和詞法分析還是很像的。下面出一道編譯原理上面的一個例子,大家可以理解一下makefile和詞法分析的不同點 
和相同點: 
   
  ->      
      -> |||ε      
    ->       
    -> |ε      
    -> +      
    -> -      
   -> >      
    -> >= 
   

   
最後,介紹一下autoconfautomake,使用這兩個工具可以自動生成makefile。 
   
 
   
 
上面的圖可以看出,通過autoscan,我們可以根據代碼生成一個叫做configure.scan的文件,然後我們編輯這個文件,參數一個 
configure.in的文件。接着我們寫一個makefile.am的文件,然後就可以用automake生成makefile.in,最後,根據 
makefile.in和configure就可以生成makefile了。在很多開源的工程裏面,我們都可以看到 
makefile.am,configure.in,makefine.in,configure文件,還有可能看到一個十分複雜的makefile文 
件,許多人學習makefile的時候想通過看這個文件來學習,最終卻發現太複雜了。如果我們知道這個文件是自動生成的,就理解這個makefile文件 
爲什麼這個複雜了。 
   
欲更加詳細的理解automake等工具,可以參考 
http://www.ibm.com/developerworks/cn/linux/l-makefile/ 
 
1.2 用makefile構建交叉編譯環境 
   
這節的內容請參考 
http://blog.csdn.net/absurd/category/228434.aspx 
裏面的交叉編譯場景分析,我只是說一下我做的步驟: 
   
1.下載交叉編譯環境( 
http://www.codesourcery.com/downloads/public/gnu_toolchain/arm-none-linux-gnueabi 
)並安裝,一般解壓就可以了,然後將裏面的bin目錄加到環境變量的PATH裏面,我的做法是在~/.bashrc最下面加一行:export PATH=$PATH:~/arm-2009q1/bin。 
   
2.在用戶的home目錄(cd ~)建一個目錄cross-compile 
   
3.在cross-compile創建一個文件cross.env,內容如下: 
   
export WORK_DIR=~/cross-compile    
export ROOTFS_DIR=$WORK_DIR/rootfs     
export ARCH=arm     
export PKG_CONFIG_PATH=$ROOTFS_DIR/usr/local/lib/pkgconfig:$ROOTFS_DIR/usr/lib/pkgconfig:$ROOTFS_DIR/usr/X11R6/lib/pkgconfig     
if [ ! -e "$ROOTFS_DIR/usr/local/include" ]; then mkdir -p $ROOTFS_DIR/usr/local/include;fi;     
if [ ! -e "$ROOTFS_DIR/usr/local/lib" ]; then mkdir -p $ROOTFS_DIR/usr/local/lib; fi;     
if [ ! -e "$ROOTFS_DIR/usr/local/etc" ]; then mkdir -p $ROOTFS_DIR/usr/local/etc; fi;     
if [ ! -e "$ROOTFS_DIR/usr/local/bin" ]; then mkdir -p $ROOTFS_DIR/usr/local/bin; fi;     
if [ ! -e "$ROOTFS_DIR/usr/local/share" ]; then mkdir -p $ROOTFS_DIR/usr/local/share; fi;     
if [ ! -e "$ROOTFS_DIR/usr/local/man" ]; then mkdir -p $ROOTFS_DIR/usr/local/man; fi;     
if [ ! -e "$ROOTFS_DIR/usr/include" ]; then mkdir -p $ROOTFS_DIR/usr/include; fi;     
if [ ! -e "$ROOTFS_DIR/usr/lib" ]; then mkdir -p $ROOTFS_DIR/usr/lib; fi;     
if [ ! -e "$ROOTFS_DIR/usr/etc" ]; then mkdir -p $ROOTFS_DIR/usr/etc; fi;     
if [ ! -e "$ROOTFS_DIR/usr/bin" ]; then mkdir -p $ROOTFS_DIR/usr/bin; fi;     
if [ ! -e "$ROOTFS_DIR/usr/share" ]; then mkdir -p $ROOTFS_DIR/usr/share; fi;     
if [ ! -e "$ROOTFS_DIR/usr/man" ]; then mkdir -p $ROOTFS_DIR/usr/man; fi; 
   
4.開啓命令行,進入cross-compile目錄下,執行. cross.env 
   
5.將編譯linux時生產的頭文件,so等拷貝到cross-compile目錄下rootfs/usr對應的目錄(頭文件一般可以拷pc的,so一定要拷arm版的)。 
   
5.下載要編譯的源代碼,並放在cross-compile目錄下 
   
6.按照 
http://blog.csdn.net/absurd/category/228434.aspx 
裏面的方法寫makefile文件,放在cross-compile目錄下 
   
7.在命令行執行make -f libxml2.mk(libxml2.mk爲上一步寫的makefile)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章