[ Android 编译 ] Android.bp 根据条件添加宏定义

Posted 那个写代码的

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ Android 编译 ] Android.bp 根据条件添加宏定义相关的知识,希望对你有一定的参考价值。

[ android 编译 ] Android.bp 根据条件添加宏定义

尊重原创,转载请注明出处!
创作不易,如有帮助请点赞支持~

参考:
Android.bp文件详解
Android.bp入门指南之浅析Android.bp语法
Android.bp正确姿势添加宏控制编译指南
Android.bp 添加宏开关

之前对 Android.bp 一直了解不多,也就是停留在大概能看懂,可以简单改改的阶段。最近遇到了一个问题,需要根据编译参数去添加宏定义,一下子就傻眼了。

如果不需要添加控制逻辑,只是单纯地添加宏定义,直接在 Android.bp 对应模块的 cflags / cppflags 中添加 "-DXXX" 即可。

但是如果需要添加控制逻辑,由于 bp 文件跟 mk 文件不同,它是纯粹的配置,没有分支等流程控制,所以只能通过编写 Go 语言实现。

之前没接触过 go 语言,但是编程语言都是相通的,百度一下相关的文章,根据自己的实际情况进行修改,磕磕绊绊地也算是完成了这个需求,这里记录一下实现的整个流程。

编写 go 脚本文件

首先添加 bionic/linker/linker_controller.go 文件,编写控制逻辑:

package linker_controller

import (
    "android/soong/android"
    "android/soong/cc"
    // 如果需要打印调试日志,这个需要导包。如果不需要打印则无需导包,否则编译会报错导入未使用的包
    "fmt"
)

func init() 
    // 在 go 的入口函数中,将linkerDefaultsFactory注册到"linker_controller"的moduleType中
    android.RegisterModuleType("linker_controller", linkerDefaultsFactory)


func linkerDefaultsFactory() (android.Module) 
    module := cc.DefaultsFactory()
	// 添加装载时的hook函数
    android.AddLoadHook(module, linkerDefaultsDefaults)
    return module


func linkerDefaultsDefaults(ctx android.LoadHookContext) 
    type props struct 
        Cflags []string
    
    p := &props
	// 获取需要定义的宏,添加到cflags中
    p.Cflags = cflagsDefaults(ctx)
    ctx.AppendProperties(p)


// 这里加入控制逻辑,当符合条件时添加相应的-DXXX参数
func cflagsDefaults(ctx android.BaseContext) ([]string) 
    var cppflags []string
	// 打印调试日志
	fmt.Println("DEBUG === BUILD_TYPE:", ctx.AConfig().Getenv("BUILD_TYPE"))
	// 当环境变量BUILD_TYPE为custom时,添加CUSTOM_LINKER的宏定义
    if ctx.AConfig().Getenv("BUILD_TYPE") == "custom" 
        cppflags = append(cppflags, "-DCUSTOM_LINKER")
    
    return cppflags

Android.bp 引入 go 脚本文件

添加了 go 脚本文件后,还需要把它配置到 Android.bp 中,才能生效,需要对 bionic/linker/Android.bp 做一点改动:

// 引入go脚本,添加编译go脚本所需的依赖
bootstrap_go_package 
    // 模块名为soong-[go文件名]
    name: "soong-linker_controller",
	// go文件包名路径
    pkgPath: "android/soong/linker_controller",
    deps: [
        "blueprint",
        "blueprint-pathtools",
        "soong",
        "soong-android",
        "soong-cc",
        "soong-genrule",
    ],
	// go脚本文件
    srcs: [
        "linker_controller.go",
    ],
    pluginFor: ["soong_build"],


// 自定义模块类型,即在go脚本中注册的moduleType
linker_controller 
    // 模块名称
    name: "linker_controller_defaults",


cc_binary 
    // 在defaults中添加引用上面添加的module
    defaults: ["linux_bionic_supported", "linker_defaults", "linker_controller_defaults"],
    srcs: [ ":linker_sources" ],
	...

在代码中添加对宏的判断

#ifdef CUSTOM_LINKER
  // do something
  DL_WARN("DEBUG === CUSTOM_LINKER has defined!");
#endif

结尾

本篇博客只是简单地添加了通过环境变量来控制宏的逻辑。显然,可以通过 go 脚本控制 Android.bp 的逻辑还有很多,想要掌握并不是一时半会儿的事,以后有机会使用到更多的控制逻辑的时候,再做进一步的学习和记录吧。

Android.bp学习

一. Android.bp概念

Android.bp 文件首先是 Android 系统的一种编译配置文件,是用来代替原来的 Android.mk文件的。在Android7.0 以前,Android 都是使用 make 来组织各模块的编译,对应的编译配置文件就是 Android.mk。

在 Android7.0 开始,Google 引入了 ninja 和 kati 来编译,为啥引入 ninja?因为随着 Android 越来越庞大,module 越来越多,编译时间也越来越久,而使用 ninja 在编译的并发处理上较 make 有很大的提升。Ninja 的配置文件就是Android.bp,Android 系统使用 Blueprint 和 Soong 工具来解析 Android.bp 转换生成 ninja文件。为了兼容老的 mk 配置文件,Android 当初也开发了 Kati 工具来转换 mk 文件生成ninja,目前 Android Q 里边,还是支持 Android.mk 方式的。相信在将来的版本中,会彻底让 mk 文件废弃,同时 Kati 也就淘汰了,只保留 bp 配置方式,所以我们要提前学习bp。

这里涉及到Ninja, kati, Soong, bp概念,接下来分别简单介绍一下。

Ninja

ninja是一个编译框架,会根据相应的ninja格式的配置文件进行编译,但是ninja文件一般不会手动修改,而是通过将Android.bp文件转换成ninja格文件来编译。

Android.bp

Android.bp的出现就是为了替换Android.mk文件。bp跟mk文件不同,它是纯粹的配置,没有分支、循环等流程控制,不能做算数逻辑运算。如果需要控制逻辑,那么只能通过Go语言编写。

Soong

Soong类似于之前的Makefile编译系统的核心,负责提供Android.bp语义解析,并将之转换成Ninja文件。Soong还会编译生成一个androidmk命令,用于将Android.mk文件转换为Android.bp文件,不过这个转换功能仅限于没有分支、循环等流程控制的Android.mk才有效。

Blueprint

Blueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong负责Android编译而设计的工具,而Blueprint只是解析文件格式,Soong解析内容的具体含义。Blueprint和Soong都是由Golang写的项目,从Android 7.0,prebuilts/go/目录下新增Golang所需的运行环境,在编译时使用。

Kati

kati是专为Android开发的一个基于Golang和C++的工具,主要功能是把Android中的Android.mk文件转换成Ninja文件。代码路径是build/kati/,编译后的产物是ckati。

重要的事情说三篇,Android.mk可以引用Android.bp中的模块,反之Android.bp不能引用Android.mk中的模块。

重要的事情说三篇,Android.mk可以引用Android.bp中的模块,反之Android.bp不能引用Android.mk中的模块。

重要的事情说三篇,Android.mk可以引用Android.bp中的模块,反之Android.bp不能引用Android.mk中的模块。

二. Android mk转换成Android bp

1.安装androidmk 工具

我们以rk3399来举例说明

source build/envsetup.sh

lunch rk3399_roc_pc_plus-userdebug

make androidmk

生成androidmk转换工具,路径为:/out/soong/host/linux-x86/bin/androidmk

2.转换

androidmk Android.mk > Android.bp

三.Android bp语法

1.编译静态库

首先我们把vendor下创建一个Study的目录,然后再Study创建一个test1的目录,tree如下:

我们的目标是把test.c编译成一个静态库

test.c代码如下:

#include <stdio.h>

int test(void)

	printf("hello Androoid.mk\\r\\n");
	return 0;

Android.bp代码如下:

cc_library_static 
    name: "test3",
    srcs: ["test.c"],

编译方法:

方法1:在android 跟目录下敲指令:make test3

方法2:在vendor/Study/test3目录下敲指令mm

注意:两个方法都需要先source build/envsetup.sh -> lunch选择41

test.a生成在out/target/product/rk3399_roc_pc_plus/obj_arm/STATIC_LIBRARIES/test3_intermediates/test3.a

NOTED:我们发现生成的并不是libtest3.a,而是test3.a,这个要注意下

其中cc_library_static就是编译成c/c++ 静态库,可以有以下类型

name就是模组的名称

srcs就是源文件

2.编译动态库

首先我们把vendor下创建一个Study的目录,然后再Study创建一个test2的目录,tree如下:

我们的目标是把test.c编译成一个静态库

test.c代码如下:

#include <stdio.h>

int test(void)

	printf("hello Androoid.mk\\r\\n");
	return 0;

Android.bp代码如下:

cc_library_shared 
    name: "test4",
    srcs: ["test.c"],

编译方法:

方法1:在android 跟目录下敲指令:make test4

方法2:在vendor/Study/test4目录下敲指令mm

注意:两个方法都需要先source build/envsetup.sh -> lunch选择41

test.so生成在out/target/product/rk3399_roc_pc_plus/obj_arm/SHARED_LIBRARIES/test4_intermediates/test4.so

NOTED:我们发现生成的并不是libtest4.so,而是test4.so,这个要注意下

以上是关于[ Android 编译 ] Android.bp 根据条件添加宏定义的主要内容,如果未能解决你的问题,请参考以下文章

Android.bp学习

Android.bp学习

Android——编译:android.bp的相关知识

Android.bp 语法和使用

Android.mk转Android.bp

Android.bp快速入门