Android条件控制宏编译

1,232 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

条件控制宏编译是什么?

在我们进行编译文件的编写时,时常需要根据平台信息、硬件信息等选择需要编译的模块,或者进行编译的配置,同时,这也是为了向前兼容之前的模块,大部分代码都是共主线开发,使用编译宏进行控制,这一点在Android平台中尤其明显。

随着Android版本的演进迭代,旧有版本上面的Android.mk被替代为Android.bp,原始的Android.mk是基于Makefile进行开发的,在Makefile文件中,我们可以很轻松地使用ifeq等条件判断进行编译控制,但是Android.bp本质上是一个配置文件,其中没有复杂的条件控制,需要借助go语言来进行控制。接下来,我们就一起看看这两种方式的区别与具体实现。

一 Android.mk条件编译

这里的条件编译就与Makefile中大致相同,我们看下有条件和无条件的情况分别是如何实现的?

(1)无条件控制宏编译

LOCAL_CFLAGS += -DMK_NO_CONDITION_PRINT

通过赋值运算符使用-D参数增加了一个宏MK_NO_CONDITION_PRINT

(2)有条件控制宏编译

CONDITION_TEST = YES
ifeq ($(CONDITION_TEST),"YES")
    LOCAL_CFLAGS += -DMK_CONDITION_PRINT
endif

ifeq比较两个值,满足条件,则添加对应的宏,这里的条件可以是对应的平台,系统设置的property等。

让我们来看一个完整的代码例子: 在Android.mk文件中增加两个宏MK_NO_CONDITION_PRINT,MK_CONDITION_PRINT,代码中增加打印。

在frameworks/av/services/camera/libcameraservice下mm -j编译

LOCAL_PATH := $(call my-dir) 
include $(CLEAR_VARS)

LOCAL_MODULE := AndroidConditionCompileTest 
LOCAL_SRC_FILES := main.c

# no condition macro control 
LOCAL_CFLAGS += -DMK_NO_CONDITION_PRINT 

# condition macro control 
CONDITION_TEST = "YES" 
ifeq ($(CONDITION_TEST),"YES")
    LOCAL_CFLAGS += -DMK_CONDITION_PRINT
endif

LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
include $(BUILD_EXECUTABLE)
/*************************************************************************
 @File Name    : main.c
 @Author       : SangYu
 @Email        : sangyu.code@gmail.com
 @Created Time : Fri 24 Jun 2022 01:48:55 AM UTC
 @Description  : android condition macro Test
 ************************************************************************/

#include <stdio.h>

int main(){
    printf("condition compile test begin!\n");

#ifdef MK_NO_CONDITION_PRINT
    printf("MK_NO_CONDITION_PRINT here!\n");
#endif

#ifdef MK_CONDITION_PRINT
    printf("MK_CONDITION_PRINT here!\n");
#endif

    printf("condition compile test end!\n");
    return 0;
}

push 可执行文件到手机中,执行,得到结果如下

# adb push
adb push Y:\AOSP\out\target\product\flame\system\bin\AndroidConditionCompileTest system/bin/
# run the executable
adb shell system/bin/AndroidConditionCompileTest

condition compile test begin!
MK_NO_CONDITION_PRINT here!
MK_CONDITION_PRINT here!
condition compile test end!

二 Android.bp条件编译

Android.mk中的条件编译较简单,可以使用条件语句ifeq等关键字进行控制

但是Android.bp文件是一个配置文件,不能配置复杂的分支逻辑,这种情况下必须要使用go语言来写相关逻辑,并集成中Android.bp中。

(1)无条件控制宏编译

cc_library_shared {
    name: "libcameraservice",
    ...
    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
        "-Wno-ignored-qualifiers",
        "-DMP_NO_CONDITION_PRINT"
    ],
}

使用方法与Android.mk类似

(2)有条件控制宏编译

Android.bp文件 主要是声明cameraparser_defaults的来源是cameraparser.go文件,然后在go文件中添加注册,并书写相关的条件判断逻辑。

bootstrap_go_package {                                                                                                                                                                                      
    name: "soong-cameraparser",
    pkgPath: "android/soong/xxxparser",
    deps: [
        "blueprint",
        "blueprint-pathtools",
        "soong",
        "soong-android",
        "soong-cc",
        "soong-genrule",
    ],
    srcs:[
        "cameraparser.go"
    ],
    pluginFor:["soong_build"],
}

cameraparser_defaults{
    name:"cameraparser_defaults",
}

cc_binary {
    name: "AndroidBPConditionCompileTest",

    defaults:["cameraparser_defaults"],

    // Camera service source

    srcs: [
        "main.c",
    ],

    shared_libs: [
        "libcutils",
        "liblog",
        "libutils",
    ],

    cflags: [
        "-DMP_NO_CONDITION_PRINT"
    ],
}

Go语言文件 主要的代码细节就是注册cameraparser_defaults,然后在注册过程中设定相关Flag,这样就能够通过条件控制宏是否添加,实现的效果与Android.mk一致。

package cameraparser               

import(
    "android/soong/android"
    "android/soong/cc"
    "fmt"
)

func init(){
    //register a module "cameraparser_defaults"
    android.RegisterModuleType("cameraparser_defaults", cameraDroidDefaultsFactory)
}

func cameraDroidDefaultsFactory()(android.Module){
    module := cc.DefaultsFactory()
    android.AddLoadHook(module, cameraDroidDefaults)
    return module
}

func cameraDroidDefaults(ctx android.LoadHookContext){
    type props struct{
        Cflags []string
    }
    p:=&props{}
    p.Cflags = globalDefaults(ctx)
    ctx.AppendProperties(p)
}

func globalDefaults(ctx android.BaseContext)([]string){
    var cppflags []string
    fmt.Println("wcy debug here")
    if ctx.AConfig().Getenv("ANDROIDBP_TEST") == "YES"{
        cppflags = append(cppflags,"-DMP_CONDITION_PRINT")
        fmt.Println("wcy debug here cppflags:", cppflags)
    }
    return cppflags
}

main.c修改

+    printf("-------------------------->\n");
+
+#ifdef MP_NO_CONDITION_PRINT
+    printf("MP_NO_CONDITION_PRINT here!\n");
+#endif
+
+#ifdef MP_CONDITION_PRINT
+    printf("MP_CONDITION_PRINT here!\n");
+#endif
+
     printf("condition compile test end!\n");

正常编译 设置环境变量后编译,export ANDROIDBP_TEST="YES" push之后执行如下