条件控制宏编译是什么?
在我们进行编译文件的编写时,时常需要根据平台信息、硬件信息等选择需要编译的模块,或者进行编译的配置,同时,这也是为了向前兼容之前的模块,大部分代码都是共主线开发,使用编译宏进行控制,这一点在 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 = YESifeq ($(CONDITION_TEST),"YES")    LOCAL_CFLAGS += -DMK_CONDITION_PRINTendif
       复制代码
 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_PRINTendif
LOCAL_SHARED_LIBRARIES := libcutils liblog libutilsinclude $(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 pushadb push Y:\AOSP\out\target\product\flame\system\bin\AndroidConditionCompileTest system/bin/# run the executableadb 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 之后执行如下
评论