您如何处理包含在 Bazel 中作为#defines 传递的依赖项?

How do you handle include dependencies passed as #defines in Bazel?

我正在尝试使用 Bazel 构建遗留​​ C/C++ 嵌入式代码库。代码被分成软件集。因为系统是嵌入式的,所以有一个环境 header include 作为参数传递给每个软件集的编译器。 header 路径是使用 #define:

定义的

software_set_b 的源文件开头可能是:

#include MY_ENV

编译指令会将MY_ENV定义为software_set_a中环境header的绝对路径,例如:

gcc -DMY_ENV=/path/to/software_set_a/headers/MyEnvironmentHeader.h

是否可以使用 Bazel 实现这一点,而无需在 bazel build--define 参数中显式传递 /path/to/software_set_a/headers/MyEnvironment.h,或者在 software_set_b 的 BUILD 文件中对值进行硬编码, 例如:

cc_library(
  name = 'software_set_b',
  defines = [
    'MY_ENV=/path/to/software_set_a/headers/MyEnvironment.h'
  ],
  ...
)

理想情况下,程序员可以 select 带有参数的包,例如bazel build //:software_set_b --//:from_env=software_set_a 在 BUILD 脚本中包含类似于以下内容的片段:

File: software_set_b/BUILD

string_flag(
  name = 'from_env',
  build_setting_default = ''
)

def deps_from_env():
  from_env = get_flag_value('from_env') # A function that gets the value of the flag.
  return '@' + from_env + '//:env' # Evaluate to e.g. '@software_set_a//:env'

cc_library(
  name = 'software_set_b',
  deps = [
    deps_from_env()
  ]
)

File: software_set_a/BUILD

cc_library(
  name = 'env',
  defines = [
    # Something to give me '/path/to/software_set_a/headers/MyEnvironment.h'
    'MY_ENV=$(rootpath)/headers/MyEnvironment.h'
  ],
  ...
)

这相对简单,例如在 software_set_a 和 software_set_b.

下创建一个环境目标
# File: //software_set_a:BUILD
cc_library(
  name = 'env',
  defines = [
    'MY_ENV=$(rootpath)/headers/MyEnvironment.h'
  ],
)

cc_library(
  name = 'software_set_a',
  deps = [
    # Top level switchable target. NOTE: This is NOT ":env".
    "//:from_env",
  ]
)
# File: //software_set_b:BUILD
cc_library(
  name = 'env',
  defines = [
    'MY_ENV=$(rootpath)/headers/MyEnvironment.h'
  ],
)

cc_library(
  name = 'software_set_b',
  deps = [
      # Top level switchable target. NOTE: This is NOT ":env".
      "//:from_env",
  ]
)

当然,这本身是行不通的。所以我们需要创建一个可切换的顶级 env 目标。

# //:BUILD
label_flag(
   name = "from_env",
   build_setting_default = "//software_set_b:env",
)

现在默认情况下,env 定义将从软件集 b 中提取。但是可以用命令覆盖。

bazel build //:software_set_b --//:from_env=software_set_a:env

请注意,您可以通过简单地创建一个 cc_library(name="empty") 并将 default_build_setting 指向它来获得一个空的默认值。此外,您可能会发现围绕 constraint_setting/constraint_value/platform/select 的配置模式对您来说是更有用的模式,而不是基于标志的方法。另请注意,您可以通过将标签标志指向可选择的多路复用器目标来将两者结合起来。可以在文件下的 bazelembedded/rules_cc_toolchain 中找到更高级的示例;

  • config/rules_cc_toolchain_config.BUILD
  • config/BUILD.巴泽尔