Android驱动笔记(7)——makefile

 makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了规则来指定,哪些文件先编译,哪些文件后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。makefile带来的好处就是“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
 makefile并不是唯一用来定义编译规则的,Android BP侧代码基于python的scons的一套编译机制(几乎不需要修改)。Android AP侧代码并不单纯的是makefile机制,还引入了ninja以及google改造后的Android.mk语法,编译效率更高。后续google可能会用go语言改造整个流程。
makefile流程

 Android项目的主Makefile文件就放在根目录下,里面指向build/core/main.mk

### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###

 这时如果直接运行make指令的话,就会把目标设为DEFAULT_GOAL

#This is the default target.  It must be the first declared target.
.PHONY:droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL): droid_targets

 droid依赖到下面的代码。

#Build files and then package it into the rom formats
.PHONY:droidcore
droidcore: files 
           systemimage 
           $(INSTALLED_BOOTIMAGE_TARGET) 
           $(INSTALLED_RECOVERYIMAGE_TARGET) 
           …

 如果我们想加一个自己的image,也默认make可以编译出来,可以在这里加上依赖关系。
 另外项目里面的一些环境变量可以通过printconfig和export命令查询。可以获得当前编译的版本:

TARGET_BUILD_VARIANT=userdebug

 说明当前的编译配置是userdebug。

7.1、Android.mk怎么写?

 拿一个自己写过的文件来简单说明一下Android.mk的写法。一般情况下如果相同路径下有类似的makefile文件可以直接搬来使用。

LOCAL_PATH := $(call my-dir)
#这个变量用于给出当前文件的路径,必须在Android.mk的开头定义,可以这样使用:LOCAL_PATH := $(call my-dir),这样这个变量不会被$(CLEAR_VARS)清除
common_cflags := -std=c99 -Wall

include $(CLEAR_VARS)
#因为一个Android.mk可能定义多个模块,每个模块都用到同样的变量名,这句话是清除掉前面变量。
LOCAL_SRC_FILES := mifunctiontest.c 
#要编译的源文件
LOCAL_C_INCLUDES := system/core/libcutils/include 
	system/core/include

LOCAL_CFLAGS := $(common_cflags)
#定义了c编译用的一些参数,比较常用的-DXXXX_YYYY来定义一个宏,其效果和在.c/.h文件的语句里面的#define XXXX_YYYY相同。
LOCAL_STATIC_LIBRARIES := libcurl libz libcrypto_static liblog libcutils
*表明本模块在编译时要用到的静态库。如果用到动态库可以用LOCAL_SHARED_LIBRARIES。
LOCAL_MODULE := mifunctiontest
* LOCAL_MODULE定义了你这个module生成目标最终的文件名。
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/bin
LOCAL_MODULE_TAGS := optional

include $(BUILD_EXECUTABLE)
#表明该module的类型,有以下几类:
#   include $(BUILD_STATIC_LIBRARY)表明生成一个静态库文件;
#   include $(BUILD_SHARED_LIBRARY) 表明生成一个动态库文件;
#   include $(BUILD_HOST_EXECUTABLE) 生成一个用于host主机即PC端运行的可执行程序,bin文件;

 当Android.mk新加一个module以后,make此时并不会自动地编译到系统。需要在PRODUCT_PACKAGES变量里增加LOCAL_MODULE所对应的名字。PRODUCT_PACKAGES变量对于有zproject的项目,在相应的文件夹下Config文件里面有,在后面追加即可。在没有zproject的项目里面,可以在device/qcom/msmXXX/msmXXX.mk文件里面追加。
 关于变量定义如果过长,需要换行的时候,可以用''连接两行,但是注意''后面不能有空格,否则会导致编译不过。

LOCAL_SRC_FILES := a.c 

7.2、kernel makefile怎么写?

 在kernel添加驱动编译相关的配置通常需要修改3个文件:Makefile,Kconfig,msmxxx_defconfig或perf_config。
其中Makefile里面添加源文件对应的.o配置。里面的obj-((CONFIG_XXXXX)中)(CONFIG_XXXXX)是个变量,需要在Kconfig里面定义

Path:/drivers/misc/Makefile

obj-$(CONFIG_OKL4_LINK_SHBUF)    += okl4-link-shbuf.o
obj-$(CONFIG_SIMTRAY_STATUS)     += simtray.o

*在makefile中新添加一个节点的状态,这里是编译的保证。里面的obj-$(CONFIG_XXXXX)中$(CONFIG_XXXXX)是个变量,需要在Kconfig里面定义

Path: /drivers/misc/Kconfig

config SIMTRAY_STATUS
	tristate "SIM tray status"
#tristate:意思是三态(3种状态,对应Y、N、M三种选择方式),意思就是这个(CONFIG_XXXXX)可以被三种选择。Y会 被编入,M会#被单独链接成一个.ko模块,N则不会被编译。
	default n
	help
	  Say 'y' here to support SIM tray GPIO detection
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"

 $(CONFIG_XXXXX)的开关是在kernel/arch/arm64/configs/vendor/xxx_defconfig里面定义的。龙旗一个项目通常对应两个xxx_defconfig,一个是xxx_defconfig一个是xxx-perf_defconfig,xxx_defconfig里面有很多debug开关是打开的,msmxxx-perf_defconfig是user版本默认的配置的,所以提交配置两个文件通常都需要提交。而对于选择哪个defconfig是定义在device/qcom/xxx/AndroidBoard.mk里面

#----------------------------------------------------------------------
# Compile Linux Kernel
#----------------------------------------------------------------------
ifeq ($(KERNEL_DEFCONFIG),)
    ifeq ($(TARGET_BUILD_VARIANT),user)
        KERNEL_DEFCONFIG := vendor/trinket-perf_defconfig
    else
        KERNEL_DEFCONFIG := vendor/trinket_defconfig
    endif
endif

 config编译生成的中间文件放在out/target/product/xxx/obj/KERNEL_OBJ/.config.如果添加驱动后.c没有编译到,可以到这文件里面确认相关config是否有配置成功。

原文地址:https://www.cnblogs.com/hansenn/p/12728626.html