Android.mk 浅析 模块编译Makefile编写

终于将C++代码porting到了bootloader中,唯一的收获就是熟悉了Makefile,有工厂的公司伤不起啊,每次都得先做一些东西满足工厂端测试的需求,为了能够做到工厂在boot中测试的要求,经过与芯片公司讨论,只有将C++弄到了boot中,真是一个很二的决定boot最终做到了2M比有些kernel还要大。不过老板要这么做就硬着头皮做了现在做成了心中还蛮高兴的,原来被逼之后人的潜能还是蛮大的。

        对于Makefile中所用的函数还在研究中,之后会写一写主要函数的用法。

         因为从事着android驱动开发所以天天要接触Android.mk。
        1、在运行  . build/envsetup.sh 会生成一些操作例如:chooseproduct mmm
        2、运行 chooseproduct project  选择所要编译的工程
        3、运行make,回去编译整个android source

怎么说到了编译Android Source的方法呢

切入主题 先写一个简单的Android.mk

  1. LOCAL_PATH := $(call my-dir)             #指定当前目录 
  2.     
  3. include $(CLEAR_VARS)                    #引入编译变量 
  4.  
  5. LOCAL_MODULE_TAGS := optional            #编译选项便是在何种情况下编译 
  6.  
  7. LOCAL_SRC_FILES := hello.c               #源文件(可以指定多个)  
  8.   
  9. LOCAL_MODULE := hello                    #编译出来的模块名 
  10.  
  11. LOCAL_MODULE_CLASS := EXECUTABLES        #指定编译之后放置的位置(此处指示放在system/bin下) 
  12.  
  13. include $(BUILD_EXECUTABLE)              #引入编译成可执行文件的规则  
LOCAL_PATH := $(call my-dir)             #指定当前目录
   
include $(CLEAR_VARS)                    #引入编译变量

LOCAL_MODULE_TAGS := optional            #编译选项便是在何种情况下编译

LOCAL_SRC_FILES := hello.c               #源文件(可以指定多个) 
 
LOCAL_MODULE := hello                    #编译出来的模块名

LOCAL_MODULE_CLASS := EXECUTABLES        #指定编译之后放置的位置(此处指示放在system/bin下)

include $(BUILD_EXECUTABLE)              #引入编译成可执行文件的规则 

以上的Android.mk 会编译出一个hello的可执行文件,并放入system/bin

LOCAL_PATH : 指定目录,以上是一般用法指示当前目录(my-dir函数是Android编译时. build/envsetup.sh命令生成的 能够获取当前目录的路径)

CLEAR_VARS: android有自己的一套代码编译规则跟编译选项等变量的定义,此变量会引入,实际是android/build/core下的clear_vas.mk,

clear_vas.mk

  1. ########################################################## 
  2. ## Clear out values of all variables used by rule templates. 
  3. ########################################################### 
  4.  
  5. LOCAL_MODULE:=                                                                           
  6. LOCAL_MODULE_PATH:= 
  7. LOCAL_MODULE_STEM:= 
  8. LOCAL_DONT_CHECK_MODULE:= 
  9. LOCAL_CHECKED_MODULE:=  
  10. LOCAL_CERTIFICATE:= 
  11. LOCAL_SDK_VERSION:= 
  12. LOCAL_NDK_VERSION:= 
  13. LOCAL_NO_EMMA_INSTRUMENT:= 
  14. LOCAL_NO_EMMA_COMPILE:= 
  15. LOCAL_PROGUARD_ENABLED:= # '',optonly,full,custom 
  16. LOCAL_PROGUARD_FLAGS:= 
  17. LOCAL_PROGUARD_FLAG_FILES:= 
  18. LOCAL_EMMA_COVERAGE_FILTER:= 
  19. LOCAL_MANIFEST_FILE:= 
  20. LOCAL_BUILD_HOST_DEX:= 
  21. LOCAL_DEX_PREOPT:= 
  22. LOCAL_DEX_PREOPT:= 
  23.  
  24. # Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to 
  25. # iterate over thousands of entries every time. 
  26. # Leave the current makefile to make sure we don't break anything 
  27. # that expects to be able to find the name of the current makefile. 
  28. MAKEFILE_LIST := $(lastword $(MAKEFILE_LIST)) 
##########################################################
## Clear out values of all variables used by rule templates.
###########################################################

LOCAL_MODULE:=                                                                          
LOCAL_MODULE_PATH:=
LOCAL_MODULE_STEM:=
LOCAL_DONT_CHECK_MODULE:=
LOCAL_CHECKED_MODULE:= 
.
.
.
LOCAL_CERTIFICATE:=
LOCAL_SDK_VERSION:=
LOCAL_NDK_VERSION:=
LOCAL_NO_EMMA_INSTRUMENT:=
LOCAL_NO_EMMA_COMPILE:=
LOCAL_PROGUARD_ENABLED:= # '',optonly,full,custom
LOCAL_PROGUARD_FLAGS:=
LOCAL_PROGUARD_FLAG_FILES:=
LOCAL_EMMA_COVERAGE_FILTER:=
LOCAL_MANIFEST_FILE:=
LOCAL_BUILD_HOST_DEX:=
LOCAL_DEX_PREOPT:=
LOCAL_DEX_PREOPT:=

# Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to
# iterate over thousands of entries every time.
# Leave the current makefile to make sure we don't break anything
# that expects to be able to find the name of the current makefile.
MAKEFILE_LIST := $(lastword $(MAKEFILE_LIST))
在编译C/C++代码时候常用的变量定义

LOCAL_MODULE 指示当前编译出来的模块名

LOCAL_MODULE_TAGS 标识在什么情况下去编译起模块

有几个选项

user 模块只在user下编译
eng 模块在eng模式下编译
tests test状态下编译
optional 此模块在所有版本下都编译
即 TARGET_BUILD_VARIANT=eng 编译TAGS为eng和optional的模块

LOCAL_SRC_FILES 表示编译出此模块需要的源程序 可以有多个

LOCAL_C_INCLUDE  如果不去调用标准库头文件,跟当前目录的头文件,则需要在此指定头文件的位置,在此指定头文件的目录。

LOCAL_STATIC_LIBRARIES:  指定需要连接的静态库像一些比较通用的标准库就无需指定了

LOCAL_SHARED_LIBRARIES: 指定需要连接的动态库

最后include $(BUILD_XXX) 表示编译出来的模块类型,有三种

BUILD_EXECUTABLE 编译成可执行的模块 build/core/host_executable.mk
BUILD_STATIC_LIBRARY 编译成静态库 build/core/host_static_library.mk
BUILD_SHARED_LIBRARY 编译成动态库 build/core/host_shared_library.mk
LOCAL_MODULE_CLASS 标识了所编译模块最后放置的位置,如果不指定,不会放到系统中,之后放在最后的obj目录下的对应目录中。

LOCAL_MODULE_CLASS := ETC                                    #表示放于system/etc目录

LOCAL_MODULE_CLASS := EXECUTABLES               #放于/system/bin

LOCAL_MODULE_CLASS := SHARED_LIBRARIES     #放在/system/lib下


build/core下有很多编译的全局的mk,如编译C/C++规则definitions.mk ......


再说一下编译内核模块的Makefile

  1. ifneq ($(KERNELRELEASE),)  #查看是都已定义kernel版本 
  2.  
  3. obj-m := gps_onoff.o       #如果已定义则编译出得模块名是gps_onoff.o 
  4.                            #(在linux2.6编译模块后会生成module_name.ko module_name.o  
  5.                            #使用insmod module_name.ko来装载模块moudule_name.o已经弃用  
  6.                            #即moudule_name.ko 是最终产物) 
  7.  
  8. else                       #第一次运行时候会走此分支 
  9.  
  10. PWD := $(shell pwd)        #指定源文件目录         
  11.  
  12. KDIR ?= /home/zk/POP_TD/marvell-pxa920-kernel      #指定到已经编译的内核的目录 
  13.                            #如果编译PC机上的模块则指定到当前运行的内核 
  14.                            #(uname -r 查看当前的内核版本) 
  15.                            #(此时内核版本也被定义KERNELRELEASE非空) 
  16.                                
  17. #内核编译命令 此处可以指定硬件体系与交叉编译工具 
  18. all:  
  19.     $(MAKE) -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-eabi-  
  20.  
  21. #重新编译内核前需要先make clean 清空编译生成的文件 否则编译会出错 
  22. clean:  
  23.     rm -rf .* *.ko *.o *.cmd *.tmp_version *.mod.c *.order Module.*endif 
ifneq ($(KERNELRELEASE),)  #查看是都已定义kernel版本

obj-m := gps_onoff.o       #如果已定义则编译出得模块名是gps_onoff.o
                           #(在linux2.6编译模块后会生成module_name.ko module_name.o 
                           #使用insmod module_name.ko来装载模块moudule_name.o已经弃用 
                           #即moudule_name.ko 是最终产物)

else                       #第一次运行时候会走此分支

PWD := $(shell pwd)        #指定源文件目录        

KDIR ?= /home/zk/POP_TD/marvell-pxa920-kernel      #指定到已经编译的内核的目录
                           #如果编译PC机上的模块则指定到当前运行的内核
                           #(uname -r 查看当前的内核版本)
                           #(此时内核版本也被定义KERNELRELEASE非空)
                              
#内核编译命令 此处可以指定硬件体系与交叉编译工具
all: 
    $(MAKE) -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-eabi- 

#重新编译内核前需要先make clean 清空编译生成的文件 否则编译会出错
clean: 
    rm -rf .* *.ko *.o *.cmd *.tmp_version *.mod.c *.order Module.*endif

编译模块的Mkefile会被读取两次,Makefile从命令行调用时候KERNELRELEASE尚未设置,

在运行到KDIR时即会指向一个内核构造树,

在运行$(MAKE)时 会会第二次运行make命令,此时设置obj-m 构造真正的内核模块


阅读更多
个人分类: Android
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭