当前位置:   article > 正文

Android.bp中支持条件编译_android.bp 条件编译

android.bp 条件编译

Android P(Android 9.0)以来,安卓系统在构建时开始采用Blueprint描述文件用于指导编译构建,同时引入了新的编译系统soong;而原本的Kati+GNU Make的组合将会被逐渐被替代;原本使用的Android.mk编译配置文件将会被Android.bp替代。

使用Android.bp进行构建时经常会遇到一个问题就是如何在Android.bp中支持条件编译,这是因为Android.bp中对条件编译的支持是相当有限的。

比较常见的一个场景是,当我们的代码涉及到一些与平台、硬件或功能相关的特性时,往往会使用不同的源码文件或者说依赖不同的库,设定不同的编译宏等等。如果我们使用Android.mk,可以直接通过ifeq或者ifneq这类逻辑控制语句实现差异化配置,如下示例:

  1. ifeq ($(TARGET_ARCH),x86_64)
  2. LOCAL_SRC_FILES+=win64.cc
  3. else ifeq ($(TARGET_ARCH),i686)
  4. LOCAL_SRC_FILES+=win32.cc
  5. else
  6. LOCAL_SRC_FILES+=win64.cc
  7. endif

如果我们使用Android.bp,那么我们可以在Android.bp中通过arch字段进行配置从而实现与上述类似条件编译的效果。如下所示:

  1. /frameworks/libs/native_bridge_support/libOpenMAXAL/Android.bp
  2. cc_library {
  3. defaults: ["native_bridge_stub_library_defaults"],
  4. name: "libnative_bridge_guest_libOpenMAXAL",
  5. overrides: ["libOpenMAXAL"],
  6. stem: "libOpenMAXAL",
  7. arch: {
  8. arm: {
  9. srcs: ["stubs_arm.cc"],
  10. },
  11. arm64: {
  12. srcs: ["stubs_arm64.cc"],
  13. },
  14. },
  15. shared_libs: [
  16. "liblog",
  17. "libnative_bridge_guest_libnativewindow",
  18. ],
  19. }

在整个Android.bp中,我们可以看到通过arch字段配置了arm和arm64两个不同平台,使用了不同的源码文件,这样可以根据平台差异这个条件实现条件编译;

但如果我们的差异并不能简单根据平台来区分怎么办呢,在我们实际开发过程中,有很多差异化的配置可能是无法通过平台进行区分的,也无法通过xml,json配置或者编译宏等实现兼容,比如不同的功能特性导致需要链接不同的依赖库等。此时我们就只能借助soong的自身的能力来实现了。

网上关于这部分的指导其实还是比较少的,但其实soong提供了解决方案,即在Android.bp中通过soong_config_module_type来帮我们进行配置,可以让我们将差异化的配置以module的形式对外提供,在编译时进行引用。

我们首先看看soong_config_module_type的配置说明,在官方文档文档中, soong_config_module_type是一种机制,允许在 Android.bp构建文件中基于 Soong 配置变量来定义模块类型。一旦在 Android.bp文件中定义了这样的模块类型,它就可以被其他模块进行引用。

这种机制允许开发人员根据所需的条件、环境或特定的配置选项,定义定制的模块类型。这些条件可以基于 Soong 配置系统中的变量,例如目标架构、编译器选项、操作系统等等。一旦定义了这样的模块类型,它将在该 Android.bp文件中可用,并可以用于定义新的模块,以满足特定条件下的构建需求。

这里将进行举例说明:

  1. #声明一个soong编译配置模块
  2. #name表明该模块的名称
  3. #config_namespace表名该编译配置模块所属的命名空间,用于在Makefile中使用
  4. #modlue_type用于表明该编译配置模块所附属的编译配置
  5. #variables,bool_variables,value_variables表明该编译配置模块所支持的选项类型
  6. #bool_variables用于定义一个表征bool类型的配置项
  7. #value_variables用于定义一个可传递的配置项,通过%s进行获取
  8. #properties用于表明该编译配置模块最终影响的可选项,其来自于moudle_type中的可选项
  9. soong_config_module_type {
  10. name: "acme_cc_defaults",
  11. module_type: "cc_defaults",
  12. config_namespace: "acme",
  13. variables: ["board"],
  14. bool_variables: ["feature"],
  15. value_variables: ["width"],
  16. properties: ["cflags", "srcs"],
  17. }
  18. #这里针对名为board的配置项设定可选值
  19. soong_config_string_variable {
  20. name: "board",
  21. values: ["soc_a", "soc_b"],
  22. }
  23. #这里对soong_config_module_type声明的编译配置模块做详细定义
  24. acme_cc_defaults {
  25. #为该编译配置命名为acme_defaults
  26. name: "acme_defaults",
  27. cflags: ["-DGENERIC"],
  28. soong_config_variables: {
  29. board: {
  30. soc_a: {
  31. cflags: ["-DSOC_A"],
  32. },
  33. soc_b: {
  34. cflags: ["-DSOC_B"],
  35. },
  36. conditions_default: {
  37. cflags: ["-DSOC_DEFAULT"],
  38. },
  39. },
  40. feature: {
  41. cflags: ["-DFEATURE"],
  42. conditions_default: {
  43. cflags: ["-DFEATURE_DEFAULT"],
  44. },
  45. },
  46. width: {
  47. cflags: ["-DWIDTH=%s"],
  48. conditions_default: {
  49. cflags: ["-DWIDTH=DEFAULT"],
  50. },
  51. },
  52. },
  53. }
  54. cc_library {
  55. name: "libacme_foo",
  56. #这里使用名为acme_defaults的编译配置
  57. defaults: ["acme_defaults"],
  58. srcs: ["*.cpp"],
  59. }

这里我们来理解其整个定义过程,soong_config_module_type用于声明一个编译配置模块,其内部包含多个配置子项(variables/value_variables/bool_variables),我们可以将其类比于C/C++中自定义一个结构体,结构体内部含有多个子元素,其中name字段用于表征该配置模块的名称,可类比结构体类型名;之后我们以该结构体类型声明了一个结构体变量,并对其进行赋值,最终我们在cc_library中使用该结构体变量。

相信到这里大家还是蒙的,仅凭上述内容并没有看出是怎么进行条件编译的。其实在进行“结构体变量赋值时”,我们已经针对每一个子成员给出了多个“可选值”,怎样去选择这些可选值呢,这时候就需要Makefile的配合了,以上述定义为例,我们在我们的Makefile中进行使用:

  1. #在Makefile中进行使用,如在BoardConfig中添加
  2. #SOONG_CONFIG_NAMESPACES 用于索引对应namespace内的编译配置
  3. SOONG_CONFIG_NAMESPACES += acme
  4. #SOONG_CONFIG_${NAMESPACE}用于选则可配置的VARIABLE
  5. SOONG_CONFIG_acme += \
  6. board \
  7. feature \
  8. #SOONG_CONFIG_${NAMESPACE}_${VARIABLE}用于选择具体的值
  9. SOONG_CONFIG_acme_board := soc_a
  10. SOONG_CONFIG_acme_feature := true
  11. SOONG_CONFIG_acme_width := 200

 最终我们编译libacme_foo时将会以cflags="-DGENERIC -DSOC_A -DFEATURE"的方式进行编译;如果我们在BoardConfig.mk添加的内容如下:

  1. #在Makefile中进行使用,如在BoardConfig中添加
  2. #SOONG_CONFIG_NAMESPACES 用于索引对应namespace内的编译配置
  3. SOONG_CONFIG_NAMESPACES += acme
  4. #SOONG_CONFIG_${NAMESPACE}用于选则可配置的VARIABLE
  5. SOONG_CONFIG_acme += \
  6. board \
  7. feature \
  8. width \
  9. #SOONG_CONFIG_${NAMESPACE}_${VARIABLE}用于选择具体的值
  10. SOONG_CONFIG_acme_board := soc_b
  11. SOONG_CONFIG_acme_feature := true
  12. SOONG_CONFIG_acme_width := 200

 此时编译libacme_foo时将会以cflags="-DGENERIC -DSOC_B -DFEATURE -DWIDTH=200"的方式进行编译;如果我们需要添加不同的src,那么我们可以修改如下:

  1. acme_cc_defaults {
  2. #为该编译配置命名为acme_defaults
  3. name: "acme_defaults",
  4. cflags: ["-DGENERIC"],
  5. soong_config_variables: {
  6. board: {
  7. soc_a: {
  8. cflags: ["-DSOC_A"],
  9. srcs: ["SocA.cc"],
  10. },
  11. soc_b: {
  12. cflags: ["-DSOC_B"],
  13. srcs: ["SocB.cc"],
  14. },
  15. conditions_default: {
  16. cflags: ["-DSOC_DEFAULT"],
  17. },
  18. },
  19. feature: {
  20. cflags: ["-DFEATURE"],
  21. conditions_default: {
  22. cflags: ["-DFEATURE_DEFAULT"],
  23. },
  24. },
  25. width: {
  26. cflags: ["-DWIDTH=%s"],
  27. conditions_default: {
  28. cflags: ["-DWIDTH=DEFAULT"],
  29. },
  30. },
  31. },
  32. }

 如果我们需要依赖不同的库,那么我们可以修改如下:

  1. #在properties中添加shared_libs
  2. soong_config_module_type {
  3. name: "acme_cc_defaults",
  4. module_type: "cc_defaults",
  5. config_namespace: "acme",
  6. variables: ["board"],
  7. bool_variables: ["feature"],
  8. value_variables: ["width"],
  9. properties: ["cflags", "srcs","shared_libs "],
  10. }
  11. #添加不同的依赖库
  12. acme_cc_defaults {
  13. #为该编译配置命名为acme_defaults
  14. name: "acme_defaults",
  15. cflags: ["-DGENERIC"],
  16. soong_config_variables: {
  17. board: {
  18. soc_a: {
  19. cflags: ["-DSOC_A"],
  20. shared_libs: ["libsoc_a"],
  21. },
  22. soc_b: {
  23. cflags: ["-DSOC_B"],
  24. shared_libs: ["libsoc_b"],
  25. },
  26. conditions_default: {
  27. cflags: ["-DSOC_DEFAULT"],
  28. },
  29. },
  30. feature: {
  31. cflags: ["-DFEATURE"],
  32. conditions_default: {
  33. cflags: ["-DFEATURE_DEFAULT"],
  34. },
  35. },
  36. width: {
  37. cflags: ["-DWIDTH=%s"],
  38. conditions_default: {
  39. cflags: ["-DWIDTH=DEFAULT"],
  40. },
  41. },
  42. },
  43. }

 综上,我们可以看到在Google在引入Android.bp后,想要使用条件编译会变得较为复杂,需要结合Android.bp与Makefile,在两者的共同作用下才能达到我们的目的。当然,这篇文章中所讲的方法并不是唯一的方法,我们还可以通过修改Soong编译系统,编写Golang代码来实现同样的效果,不过在我看来这种方式不够优雅,我们应尽可能在不做侵入式修改的前提下来实现我们的目的。

原文首发于我的个人网站:https://coderfan.net,更多内容请点击直达~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/255814
推荐阅读
相关标签
  

闽ICP备14008679号