android bp文件_Android.bp正确姿势添加宏控制编译指南
前言
随着Android版本的迭代,越来越多的移动终端都用上了香喷喷的Android 9和10系统。相对于原来的Android版本,Android 9和10越来越多的使用Android.bp替换以前的Android.mk编译脚本。我们知道 Android.mk采用Makefile的语言,所以为了控制条件编译和多版本适配,我们可以在不同产品直接在Android.mk中采用Makefile语言控制编译。虽然我们也可以通过Android的预置工具androidmk将Android.mk转换为Android.bp脚本,但是对于有宏控制的条件编译,androidmk是无能为力的。这是因为Android.bp是类似JSON的纯文本形式,对于Android.mk里面流控制部分,在Android.bp里要借助使用go语言文件去进行控制。好了说了这么多了,我想读者应该知道这个篇章要写什么了,那就是手把手带领大伙手撸一把Android.bp添加宏控制编译。
一.实战开始
我们知道在Android原来的编译脚本Android.mk中添加宏控制有两种场景,分别是:
无条件控制的宏添加,形如:
#无条件控制宏编译
LOCAL_CFLAGS += -Wno-error=implicit-function-declaration -DPRINT
有条件控制的宏添加,即满足某个条件才添加对应的宏,这个场景比较,形如:
#有条件的添加宏控制
ifeq ($(ANDROIDBP_FUN), "YES")
LOCAL_CFLAGS += -DXXX
endif
下面的篇章我们将分别从上述两种场景出发,来说明在Android.bp中如何添加宏控制。
1.1 无条件控制的宏添加
这里我会以实际案例来说明,怎么一步步添加无条件控制的宏。
1.1.1 编写源文件main.c
#include
int main()
{
#ifdef PRINT//宏控制
printf("Hello world\n");
#endif
#ifdef XXX//宏控制
printf("XXX\n");
#endif
printf("This is AndroidBp Test\n");
return 0;
}
代码非常简单,就是一个简单的打印。在我们正式在Android.bp中添加宏前,我们先看看Android.mk应该怎么编写。
1.1.2 编写Android.mk编译脚本
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := AndroidBp
LOCAL_SRC_FILES := main.c
ANDROIDBP_FUN=YES
#有条件的添加宏控制
ifeq ($(ANDROIDBP_FUN), "YES")
LOCAL_CFLAGS += -DXXX
endif
#无条件宏控制
LOCAL_CFLAGS += -Wno-error=implicit-function-declaration -DPRINT
LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
include $(BUILD_EXECUTABLE)
这个也非常简单,就是编译一个可执行文件,并有条件和无条件的添加宏控制。
1.1.3 将Android.mk转换为Android.bp
在前面的博客中,我们知道Android内置的androidmk工具能将Android.mk转换为对应的Android.bp,但是当Android.mk中有宏条件控制时就无能为力了。下面让我们转换一下看看是否如此:
[SPRD] xxx@pd:~/ssd/xxx/ap/idh.code/xxxxroid/external/AndroidBp$ androidmk Android.mk > Android.bp
[SPRD] xxx@pd:~/ssd/xxx/ap/idh.code/xxxxroid/external/AndroidBp$
查看转换后生成的Android.bp文件如下,可以看到androidmk的转换失效了,
ANDROIDBP_FUN = ["YES"]
cc_binary {
name: "AndroidBp",
srcs: ["main.c"],
// ANDROIDMK TRANSLATION ERROR: unsupported conditional
// ifeq ($(ANDROIDBP_FUN), "YES")
cflags: ["-DXXX"] + [ // ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
// endif
"-Wno-error=implicit-function-declaration",
"-DPRINT",
],
shared_libs: [
"libcutils",
"liblog",
"libutils",
],
}
1.1.4 Android.bp直接添加宏
通过前面的章节我们可以直接,Android.bp直接添加宏非常简单,只需要在cflags后面添加对应的宏就OK了。
cflags: ["-DXXX"] + [ // ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
// endif
"-Wno-error=implicit-function-declaration",
"-DPRINT",
],
1.2 有条件控制的宏添加
根据前面的章节我们知道,在Android.bp中需要有条件的添加宏是不能直接做到的,必须借助go脚本实现动态控制编译项,那么让我们看看怎么动态添加如下的宏:
#有条件的添加宏控制
ifeq ($(ANDROIDBP_FUN), "YES")
LOCAL_CFLAGS += -DXXX
endif
1.2.1 添加go脚本
我们在Android.bp同级目录添加go脚本文件xxxparser.go,其内容如下:
package xxxparser
import (
"android/soong/android"
"android/soong/cc"
)
func init() {
// resister a module "xxxparser_defaults"
android.RegisterModuleType("xxxparser_defaults", xxxdroidDefaultsFactory)
}
func xxxdroidDefaultsFactory() (android.Module) {
module := cc.DefaultsFactory()
android.AddLoadHook(module, xxxdroidDefaults)
return module
}
func xxxdroidDefaults(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
if ctx.AConfig().Getenv("ANDROIDBP_FUN") == "YES" {
cppflags = append(cppflags,"-DXXX")
}
return cppflags
}
1.2.2 Android.bp使用go脚本
在Android.bp开头位置引入go脚本文件xxxparser.go,如下:
//引入go脚本
bootstrap_go_package {
name: "soong-xxxparser",
pkgPath: "android/soong/xxxparser",
deps: [
"blueprint",
"blueprint-pathtools",
"soong",
"soong-android",
"soong-cc",
"soong-genrule",
],
srcs: [
"xxxparser.go",
],
pluginFor: ["soong_build"],
}
xxxparser_defaults {
name: "xxxparser_defaults",
}
ANDROIDBP_FUN = ["YES"]
cc_binary {
defaults: ["xxxparser_defaults"],
name: "AndroidBp",
srcs: ["main.c"],
cflags: ["-Wno-error=implicit-function-declaration"],
shared_libs: [
"libcutils",
"liblog",
"libutils",
],
}
以上语句可以保证运行Android.bp时,先编译对应的xxxparser.go运行go脚本时,会首先运行init函数,将 xxxdroidDefaultsFactory函数注册到module中,之后调用xxxdroidDefaultsFactory函数时,会将回调函数 xxxdroidDefaults注册进去之后调用 privateParserDefaults 时,我们可以从 ctx.AConfig() 中获取好多属性
(参考 build/soong/android/config.go 中对 build/soong/android/module.go中的 androidBaseContext interface的各种函数实现),其中有一项是获取宏值的,之后回调xxxdroidDefaults添加宏信息。
1.2.3 演示运行
在正式进行编译之前,让我们对编译环境设置环境变量,我这里使用的是ubuntu编译,所以这个不用多说怎么配置环境变量了,如下:
[SPRD] xxx@pd:~/ssd/xxx/ap/idh.code$ export ANDROIDBP_FUN=YES
[SPRD] xxx@pd:~/ssd/xxx/ap/idh.code$ echo $ANDROIDBP_FUN
YES
[SPRD] xxx@pd:~/ssd/xxx/ap/idh.code$
执行可执行文件,查看输出结果,完美。
1|xxx:/system/bin # ./AndroidBp
XXX
This is AndroidBp Test
xxx:/system/bin #
二.浅析go脚本文件
由于对go语法不是非常了解,这里只对xxxparser.go中用到的语法进行简单的解析,以便大家了解,如果想深入的话得自行研究内功了。这里臣妾做不到。
2.1 解析 init 函数
我们知道bin文件执行先从main开始,而运行go语言时,先运行init函数,我们这里的此函数为:
func init() {
// resister a module "xxxparser_defaults"
// 注册xxxparser_defaults, 指定要调用的方法入口xxxdroidDefaultsFactory
android.RegisterModuleType("xxxparser_defaults", xxxdroidDefaultsFactory)
}
2.1.1 解析RegisterModuleType函数
脚本开头import了两个包 “android/soong/android” 和 “android/soong/cc”从 build/soong/ 目录下搜索 “func RegisterModuleType” 来获取RegisterModuleType函数的定义位置RegisterModuleType函数位于build/soong/android/register.go中,如下:
func RegisterModuleType(name string, factory ModuleFactory) {
moduleTypes = append(moduleTypes, moduleType{name, ModuleFactoryAdaptor(factory)})
}
可以看出将 name 和 ModuleFactoryAdaptor(factory) append到 var moduleTypes []moduleType 中
moduleType类型如下:
type moduleType struct {
name string
factory blueprint.ModuleFactory
}
2.1.2 查找ModuleFactory类型
xxxparser.go 开头 import “github.com/google/blueprint”我们从github上下载 github.com/google/blueprint/ 仓后,搜索 “type ModuleFactory” 来获取 ModuleFactory 定义位置,位于 github.com/buleprint/context.go中,如下:
// A ModuleFactory function creates a new Module object. See the
// Context.RegisterModuleType method for details about how a registered
// ModuleFactory is used by a Context.
type ModuleFactory func() (m Module, propertyStructs []interface{})
可以看出ModuleFactory为一函数指针,形参为null,返回类型为 Module, []interface{}。
注: 此处我们详细的讲解了如何搜索变量名和函数名的位置,即关键字 “type xxx"和"func xxx”,之后不再给出详细步骤。
2.1.3 解析ModuleFactoryAdaptor函数
通过搜索如下所示:
// ModuleFactoryAdapter Wraps a ModuleFactory into a blueprint.ModuleFactory by converting an Module
// into a blueprint.Module and a list of property structs
func ModuleFactoryAdaptor(factory ModuleFactory) blueprint.ModuleFactory {
return func() (blueprint.Module, []interface{}) {
module := factory()
return module, module.GetProperties()
}
}
此处将xxxparser.go中的 type ModuleFactory func() Module 函数指针,转换成 blueprint.ModuleFactory 类型的函数指针。
2.2 解析回调函数 xxxdroidDefaultsFactory
从上文可以得知,xxxdroidDefaultsFactory类型为 type ModuleFactory func() Module
我们实现了这个函数为:
func xxxdroidDefaultsFactory() (android.Module) {
module := cc.DefaultsFactory()
android.AddLoadHook(module, xxxdroidDefaults)
return module
}
2.2.1 解析 DefaultsFactory()函数
函数实现见 build/soong/cc/cc.go,如下:
func DefaultsFactory(props ...interface{}) android.Module {
module := &Defaults{}
module.AddProperties(props...)
module.AddProperties(
&BaseProperties{},
&VendorProperties{},
&BaseCompilerProperties{},
&BaseLinkerProperties{},
&LibraryProperties{},
&FlagExporterProperties{},
&BinaryLinkerProperties{},
&TestProperties{},
&TestBinaryProperties{},
&UnusedProperties{},
&StlProperties{},
&SanitizeProperties{},
&StripProperties{},
&InstallerProperties{},
&TidyProperties{},
&CoverageProperties{},
&SAbiProperties{},
&VndkProperties{},
<OProperties{},
&PgoProperties{},
&android.ProtoProperties{},
)
android.InitDefaultsModule(module)
return module
}
好了,就到这里了。不是本人赖,是因为这个我也是参考别人的。但是各位放心,后续我会继续将本章接力下去继续分析精进的。
写在最后
Android.bp正确姿势添加宏控制编译指南中介绍的两种添加宏的场景就到这里了,我想通过这个文档大伙一定能构建自己的Android.bp脚本了。好了最后如果文章对你有帮助麻烦点个赞,如果觉得很low也可以拍个砖一起探讨。
相关推荐
Android.bp正确姿势添加宏控制编译指南
Android.bp正确姿势添加宏控制编译指南前言 随着Android版本的迭代,越来越多的移动终端都用上了香喷喷的Android 9和10系统。相对于原来的Android版本,9和10越来越多的使
技术转移机构如何基于数据提升项目撮合精准度?.docx
技术转移机构如何基于数据提升项目撮合精准度?
超扭滑模与快速终端滑模的永磁同步电机无感控制:理论、离散化实现与仿真研究(Simulink仿真实现)
内容概要:本文系统研究了超扭滑模控制(STSMC)与快速终端滑模控制(FTSMC)在永磁同步电机(PMSM)无感控制中的应用,重点涵盖其理论基础、离散化实现方法及Simulink仿真验证。文章深入阐述了两种高阶滑模控制策略的设计原理,利用磁链无感观测技术实现转子位置与速度的精确估计,从而省去物理传感器,有效提升了系统的可靠性与鲁棒性。同时,提供了完整的Simulink仿真模型构建方案,包括控制器设计、关键参数整定及动态响应性能分析,充分验证了所提出的方法在零速与低速工况下的卓越控制性能和有效性。; 适合人群:具备电机控制、现代控制理论基础知识及熟练掌握MATLAB/Simulink仿真技能的研究生、科研人员与工程技术人员。; 使用场景及目标:①深入理解高阶滑模控制在电机驱动系统中的设计思想与具体实现;②掌握基于滑模观测器的无感控制核心技术;③开展永磁同步电机高性能控制算法的理论研究、仿真验证与工程化探索。; 阅读建议:建议将文中详尽的理论推导与Simulink仿真模型相结合进行学习,重点关注滑模面的构建、抖振抑制策略的实施以及离散化处理的细节,有条件的研究者可进一步将算法移植到DSP等硬件平台进行实验验证,以深化对理论的理解并检验其实际应用效果。
多源动态最优潮流的分布鲁棒优化方法(IEEE118节点)(Matlab代码实现)
内容概要:本文系统阐述了基于Matlab的多源动态最优潮流分布鲁棒优化方法,聚焦于IEEE118节点电力系统,旨在应对高比例可再生能源接入背景下源荷双重不确定性所带来的调度挑战。该方法深度融合分布鲁棒优化理论,通过构建能够抵御最坏情况概率分布的决策模型,有效提升了电力系统在复杂不确定性环境下的运行安全性、经济性与可靠性。研究不仅提供了完整的Matlab代码实现,便于结果复现与算法验证,还特别关注了含风电等新能源的现代电网低碳调度问题,为解决实际工程中的优化调度难题提供了强有力的理论支撑和技术工具。; 适合人群:具备电力系统分析基础和Matlab编程能力的研究生、科研人员及从事智能电网优化运行、能源系统规划等相关领域的工程技术人员。; 使用场景及目标:①研究含高比例可再生能源接入的电力系统动态最优潮流问题;②掌握分布鲁棒优化在电力系统经济调度、低碳调度中的建模思想与求解方法;③利用IEEE118标准测试系统进行算法有效性验证与性能对比分析;④基于所提供的Matlab代码进行二次开发,探索新型不确定性优化理论在电力系统中的创新应用。; 阅读建议:建议读者结合电力系统最优潮流、不确定性优化理论(特别是分布鲁棒优化)的背景知识进行学习,重点关注模型的构建逻辑、目标函数与约束条件的设计原理,以及Matlab代码的具体实现细节。在学习过程中,应动手调试代码,尝试修改系统参数(如新能源出力波动范围、负荷水平等),以观察不同场景下优化结果的变化,从而深刻理解该方法的适应性、优势及其潜在的局限性。
车间调度基于GA、PSO、SA、ACO、TS优化算法的车间调度比较研究(Matlab代码实现)
内容概要:本文系统性地比较了遗传算法(GA)、粒子群优化(PSO)、模拟退火(SA)、蚁群优化(ACO)和禁忌搜索(TS)五种智能优化算法在车间调度问题中的性能表现,并提供了基于Matlab的完整代码实现。研究聚焦于调度优化的核心目标——最小化完工时间(makespan),通过标准测试案例对各算法的收敛速度、求解精度和稳定性进行了深入对比分析,旨在为实际生产调度中算法的选择与改进提供科学依据。文中不仅详述了每种算法的设计思路与关键参数设置,还展示了其实现逻辑,便于读者理解、复现与拓展。; 适合人群:从事智能制造、工业工程、运筹优化等相关领域的研究人员,以及具备Matlab编程基础、希望将智能优化算法应用于实际调度问题的研究生和工程师。; 使用场景及目标:① 掌握主流智能优化算法在解决NP-hard车间调度问题上的具体应用与差异;② 学习如何利用Matlab实现并对比不同优化算法的性能;③ 为解决生产制造、物流配送等领域中的资源调度难题提供算法选型和技术参考。; 阅读建议:建议读者在阅读时重点关注各算法的Matlab实现代码和实验结果对比部分,动手运行代码以直观感受不同算法的寻优过程和效果差异。同时,可结合具体调度约束条件,尝试调整算法参数或融合多种算法思想,以深化对优化机理的理解。


Google技术社区
