zoukankan      html  css  js  c++  java
  • 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是否有配置成功。

  • 相关阅读:
    近来几个有用的网站
    军事视频网站
    美军武器命名
    区块链的五个关键要素
    处理多媒体的两个重要工具
    Python re模块将字符串分割为列表
    Python 自动刷新网页
    selenium:chromedriver与chrome版本的对应关系
    怎么批量删除QQ空间说说?
    ssm获取数据库名称
  • 原文地址:https://www.cnblogs.com/hansenn/p/12728626.html
Copyright © 2011-2022 走看看