当前位置: 首页 > news >正文

告别Android.mk:手把手教你用Soong和Blueprint编写你的第一个Android.bp模块

从Android.mk到Android.bp:现代构建系统迁移实战指南

在Android开源项目(AOSP)的演进历程中,构建系统的现代化改造是一个里程碑式的变革。传统基于Makefile的Android.mk脚本逐渐被更高效、更易维护的Android.bp文件所取代。这一转变不仅仅是语法层面的更新,更是构建理念的全面升级。本文将带您深入理解Soong构建系统的核心机制,并通过完整案例演示如何将现有模块从Android.mk迁移到Android.bp格式。

1. 构建系统演进背景

Android平台早期的构建系统基于GNU Make,这种设计在项目规模较小时表现良好。但随着代码量呈指数级增长(AOSP代码库已超过1亿行),Makefile的局限性日益凸显:

  • 解析性能瓶颈:全量解析数万个Makefile需要消耗数分钟
  • 依赖关系复杂:隐式依赖导致增量构建经常失效
  • 扩展性受限:添加新模块类型需要修改核心Makefile
  • 可读性差:条件判断和shell脚本交织导致维护困难

Soong构建系统的引入解决了这些痛点。其核心优势体现在:

特性Android.mkAndroid.bp
构建速度慢(分钟级)快(秒级)
依赖管理隐式声明显式声明
语法复杂度高(混合shell/make语法)低(声明式配置)
可扩展性需要修改核心系统模块化扩展
多平台支持有限原生支持

典型的中型C++项目构建时间对比:

# Android.mk构建耗时 real 2m45.3s user 4m12.1s sys 0m35.6s # Android.bp构建耗时 real 0m38.2s user 1m56.3s sys 0m12.8s

2. Blueprint语法深度解析

Android.bp采用Blueprint声明式语法,其设计哲学强调简洁性和可读性。以下是一个完整的C++可执行模块定义示例:

cc_binary { name: "video_decoder", srcs: [ "main.cpp", "decoder/avc_parser.cpp", "decoder/hevc_parser.cpp", ], cflags: [ "-Wall", "-Werror", "-DLOG_LEVEL=3", ], static_libs: ["libavcodec"], shared_libs: [ "liblog", "libutils", ], header_libs: ["libmedia_headers"], export_include_dirs: ["include"], product_variables: { eng: { cflags: ["-DDEBUG=1"], }, }, }

关键属性解析:

  • name:模块唯一标识符,构建产物会以此命名
  • srcs:支持glob模式匹配(如"src/**/*.cpp"
  • cflags:同时影响C和C++编译,针对C++应使用cppflags
  • product_variables:实现条件编译,支持eng/userdebug/user等变体

注意:模块名称在整个构建系统中必须唯一,如果出现冲突会导致构建失败。建议采用<项目前缀>_<功能描述>的命名规范。

多模块协同的典型场景:

// 基础库模块 cc_library { name: "libmedia_core", srcs: ["core/*.cpp"], visibility: ["//frameworks/av/media"], } // 中间件模块 cc_library { name: "libmedia_codec", srcs: ["codec/*.cpp"], static_libs: ["libmedia_core"], } // 最终可执行文件 cc_binary { name: "media_server", srcs: ["server/main.cpp"], shared_libs: ["libmedia_codec"], }

3. 迁移实战:从Makefile到Blueprint

让我们通过一个真实案例演示迁移过程。假设有一个视频处理模块,原始Android.mk内容如下:

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libvideo_processor LOCAL_SRC_FILES := \ src/processor.cpp \ src/format.cpp \ src/codec.cpp LOCAL_CFLAGS := -DLOG_LEVEL=2 -Wall LOCAL_STATIC_LIBRARIES := libavformat libavcodec LOCAL_SHARED_LIBRARIES := liblog libcutils include $(BUILD_SHARED_LIBRARY)

转换后的Android.bp实现:

cc_library_shared { name: "libvideo_processor", srcs: [ "src/processor.cpp", "src/format.cpp", "src/codec.cpp", ], cflags: [ "-DLOG_LEVEL=2", "-Wall", ], static_libs: [ "libavformat", "libavcodec", ], shared_libs: [ "liblog", "libcutils", ], // 确保头文件可见性 export_include_dirs: ["include"], }

迁移过程中的关键差异点:

  1. 变量声明

    • Makefile:需要手动清除变量(CLEAR_VARS)
    • Blueprint:每个模块都是独立作用域
  2. 模块类型

    • Makefile:通过BUILD_SHARED_LIBRARY等宏指定
    • Blueprint:直接使用cc_library_shared等类型
  3. 依赖管理

    • Makefile:LOCAL_STATIC_LIBRARIES/LOCAL_SHARED_LIBRARIES分离
    • Blueprint:统一通过static_libs/shared_libs管理

常见问题处理方案:

  • 条件编译:使用product_variables替代ifeq
  • 文件遍历:推荐显式列出文件,避免使用find
  • 跨模块变量:通过顶层变量定义实现共享

4. 高级构建技巧

4.1 多架构支持

现代Android设备需要支持armeabi-v7a、arm64-v8a等多种ABI,Blueprint提供了优雅的实现方式:

cc_library { name: "libneon_optimized", srcs: ["neon/*.cpp"], arch: { arm: { cflags: ["-mfpu=neon"], }, arm64: { cflags: ["-march=armv8-a+simd"], }, x86: { enabled: false, // 禁用x86构建 }, }, }

4.2 预编译二进制集成

对于第三方闭源库,可以使用prebuilt模块:

cc_prebuilt_library_shared { name: "libthird_party", srcs: ["prebuilt/libthird_party.so"], strip: { none: true, // 保留调试符号 }, check_elf_files: false, // 跳过ELF检查 }

4.3 构建时代码生成

通过genrule实现构建时操作:

genrule { name: "version_generator", tools: ["python3"], cmd: "python3 $(location generate_version.py) > $(out)", srcs: ["generate_version.py"], out: ["version.cpp"], } cc_library { name: "libwith_version", srcs: [ "src/*.cpp", ":version_generator", // 引用生成的文件 ], }

5. 调试与优化

5.1 构建过程分析

使用以下命令获取详细构建信息:

# 显示构建依赖图 m --dumpvars-mode --modules "module_name" # 生成编译命令数据库 export SOONG_GEN_COMPDB=1 m nothing

5.2 常见错误处理

  • 模块冲突:使用visibility属性控制模块可见性
  • 头文件缺失:确保依赖模块声明了export_include_dirs
  • ABI不兼容:检查arch条件是否正确配置

5.3 性能优化建议

  1. 避免在Android.bp中使用复杂shell命令
  2. 将大型模块拆分为多个子模块
  3. 为常用库设置stl: "c++_shared"减少重复链接
  4. 使用cc_library_static替代重复源码编译

在实际项目迁移中,建议采用渐进式策略:先迁移叶子模块,再处理复杂依赖。AOSP代码库中提供了大量参考实例,可以通过find . -name "Android.bp" | xargs grep "cc_library"快速查找示例。

http://www.jsqmd.com/news/842563/

相关文章:

  • 转:调动员工积极性的七个关键
  • Python爬虫实战:如何优雅地抓取在线学习平台 FAQ 构建高质量语料库?
  • Armv8原子操作调试:LDXR/STXR指令对与独占监视器
  • 【人工智能】GenFlow 4.0是由百度个人超级智能事业群(PSIG)于 2026 年 4 月 27 日联合百度文库与百度网盘重磅发布的新一代通用 AI 智能体(AI Agent)。
  • 共享内存概述
  • 2026红西柚果粒厂家推荐+柑橘果粒厂家推荐:源头直供,品质优选 - 栗子测评
  • 高并发应用场景
  • 如何优化 ECS 实例的网络带宽峰值应对突发流量
  • 2026柚子皮厂家推荐:全品类供应,高性价比之选 - 栗子测评
  • 【网安-Web渗透测试-内网渗透】内网信息收集(工具)
  • 恒立直线导轨供应商哪家好?2026直线导轨定制厂家汇总:直线导轨供应厂家推荐+RUSON中空旋转平台供应商推荐 - 栗子测评
  • 量子计算中SIMD编译优化与离子阱架构实践
  • FastAPI + SQLite 实战:从零搭建个人记账系统
  • 计算机毕业设计 | vue+springboot高校宿舍 学生住宿管理系统(附源码+论文+讲解视频)
  • 3步实现B站视频转文字:让学习笔记制作变得轻松简单
  • 第六章:UI组件与Material3主题
  • Blender-Armatures
  • C51可重入函数原理与实践指南
  • 2026香柚果茸厂家推荐:优质原料直采,风味纯正 - 栗子测评
  • 第一阶段开发复盘与优化纪要
  • 电镀整流机源头厂家:企业采购选型策略深度解析
  • HTML代码加密工具源码_在线网页加密解密_防复制源码
  • 2026合金铝板定制厂家甄选:花纹铝板生产厂家+防滑铝板生产厂家+防滑铝板源头厂家汇总 - 栗子测评
  • 向量数据库横评:Milvus vs Pinecone vs Weaviate 选型指南
  • NotebookLM具身智能落地实战(从零部署到ROS2集成):谷歌AI团队内部培训手册泄露版
  • 解决FlexNet Publisher许可证协议不匹配错误-83
  • 2026铝板定制加工厂推荐盘点:靠谱保温铝板生产厂家+冲压用铝板源头厂家推荐 - 栗子测评
  • 长期项目使用 Taotoken 聚合 API 在模型选型与切换上的便利性体验
  • ABAP RFC调用避坑指南:从`SY-SUBRC`错误码到`CX_ROOT`异常处理的完整实战
  • Equalizer APO终极指南:免费开源的系统级音频均衡解决方案