15_apollo_tools_platform子模块软件架构分析
1. 概述
apollo_tools_platform子模块是Apollo构建系统的平台配置工具,负责管理跨平台构建的条件编译和平台特定的配置选项。该模块通过build_defs.bzl和common.bzl文件提供了丰富的平台抽象函数,支持GPU、CPU架构、CAN总线、远程控制等特性的条件编译,为Apollo系统在多种硬件平台上的构建提供了统一的接口。
2. 软件架构图
graph TB
subgraph "Bazel构建系统"
B1[Bazel工作空间]
B2[配置系统]
B3[条件编译器]
end
subgraph "Platform模块"
P1[build_defs.bzl]
P2[common.bzl]
P3[平台抽象层]
P4[工具链管理器]
end
subgraph "平台特性"
F1[GPU支持]
F2[CPU架构]
F3[CAN总线]
F4[远程控制]
F5[性能分析]
end
subgraph "工具链"
T1[Python工具链]
T2[Bash工具链]
T3[编译器工具链]
end
subgraph "构建目标"
G1[x86_64目标]
G2[aarch64目标]
G3[GPU目标]
G4[CPU目标]
end
B1 --> B2
B2 --> P1
B2 --> P2
P1 --> P3
P2 --> P4
P3 --> F1
P3 --> F2
P3 --> F3
P3 --> F4
P3 --> F5
P4 --> T1
P4 --> T2
P4 --> T3
B3 --> G1
B3 --> G2
B3 --> G3
B3 --> G4
style P1 fill:#e1f5fe
style P2 fill:#f3e5f5
style P3 fill:#fff3e0
3. 调用流程图
sequenceDiagram
participant Build as 构建系统
participant Platform as Platform模块
participant BuildDefs as build_defs.bzl
participant Common as common.bzl
participant Config as 配置系统
participant Toolchain as 工具链
Build->>Platform: 初始化平台配置
Platform->>BuildDefs: 加载build_defs.bzl
BuildDefs->>Config: 查询平台配置
Config-->>BuildDefs: 返回配置值
BuildDefs->>BuildDefs: 生成条件编译选项
BuildDefs-->>Platform: 返回平台抽象函数
Platform->>Common: 加载common.bzl
Common->>Toolchain: 查询工具链路径
Toolchain-->>Common: 返回工具链路径
Common->>Common: 执行工具链检查
Common-->>Platform: 返回工具链管理器
Platform-->>Build: 平台配置完成
Build->>BuildDefs: 应用平台条件
BuildDefs->>Config: 评估select语句
Config-->>BuildDefs: 返回选中的值
BuildDefs-->>Build: 条件编译完成
4. UML类图
4.1 平台抽象类图
classDiagram
class PlatformConfig {
+use_gpu: bool
+with_teleop: bool
+use_esd_can: bool
+enable_profiler: bool
+cpu_arch: string
+getGpuConfig(): bool
+getTeleopConfig(): bool
+getCanConfig(): bool
+getProfilerConfig(): bool
-configMap: map
}
class PlatformAbstraction {
+if_gpu(if_true, if_false): list
+if_teleop(if_true, if_false): list
+if_x86_64(if_true, if_false): list
+if_aarch64(if_true, if_false): list
+if_esd_can(if_true, if_false): list
+if_profiler(): list
+copts_if_gpu(): list
+copts_if_teleop(): list
+copts_if_esd_can(): list
}
class ToolchainManager {
+python_bin: string
+bash_bin: string
+getPythonBin(): string
+getBashBin(): string
+findTool(tool_name): string
-toolPaths: map
}
class ConfigResolver {
+resolve(config_name): string
+select(conditions): any
+validate(config): bool
-configCache: map
}
class PlatformDetector {
+detectCPU(): string
+detectGPU(): bool
+detectFeatures(): list
-cpuInfo: string
-gpuInfo: string
}
PlatformConfig --> PlatformAbstraction
PlatformAbstraction --> ConfigResolver
PlatformAbstraction --> ToolchainManager
ToolchainManager --> PlatformDetector
4.2 工具链管理类图
classDiagram
class ToolchainLocator {
+which(repository_ctx, program_name): string
+getPythonBin(repository_ctx): string
+getBashBin(repository_ctx): string
+getEnviron(repository_ctx, name): string
-path: string
}
class ToolchainValidator {
+validatePython(path): bool
+validateBash(path): bool
+validateCompiler(path): bool
+checkVersion(path, min_version): bool
}
class ToolchainConfigurator {
+configurePython(repository_ctx)
+configureBash(repository_ctx)
+configureCompiler(repository_ctx)
-config: map
}
class FileOperator {
+readDir(repository_ctx, src_dir): list
+filesExist(repository_ctx, paths): list
+realpath(repository_ctx, path): string
+copyFiles(src, dst): bool
}
class TemplateProcessor {
+loadTemplate(template): string
+expandTemplate(content, substitutions): string
+saveTemplate(content, output): bool
-templates: map
}
ToolchainLocator --> ToolchainValidator
ToolchainLocator --> ToolchainConfigurator
ToolchainConfigurator --> FileOperator
ToolchainConfigurator --> TemplateProcessor
4.3 条件编译类图
classDiagram
class ConditionalCompiler {
+conditions: map
+evaluate(condition): bool
+select(conditions): any
+apply(target, config): list
-evaluated: map
}
class GPUCondition {
+enabled: bool
+evaluate(): bool
+getCopts(): list
+getLinkopts(): list
}
class CPUCondition {
+arch: string
+evaluate(): bool
+getCopts(): list
+getLinkopts(): list
}
class FeatureCondition {
+feature: string
+enabled: bool
+evaluate(): bool
+getCopts(): list
}
class SelectStatement {
+conditions: map
+default: any
+evaluate(): any
-context: Context
}
ConditionalCompiler --> GPUCondition
ConditionalCompiler --> CPUCondition
ConditionalCompiler --> FeatureCondition
ConditionalCompiler --> SelectStatement
5. 状态机分析
5.1 平台配置状态机
stateDiagram-v2
[*] --> UNCONFIGURED: 模块加载
UNCONFIGURED --> DETECTING_PLATFORM: 开始检测平台
DETECTING_PLATFORM --> LOADING_CONFIG: 平台检测完成
LOADING_CONFIG --> VALIDATING_CONFIG: 配置加载完成
VALIDATING_CONFIG --> READY: 配置验证通过
VALIDATING_CONFIG --> ERROR: 配置验证失败
READY --> APPLYING_CONFIG: 开始应用配置
APPLYING_CONFIG --> COMPLETED: 配置应用完成
ERROR --> RECOVERING: 开始恢复
RECOVERING --> READY: 恢复成功
RECOVERING --> FATAL: 恢复失败
FATAL --> [*]: 致命错误
COMPLETED --> [*]: 配置完成
note right of DETECTING_PLATFORM : 检测CPU架构和GPU
note right of LOADING_CONFIG : 加载平台配置文件
note right of VALIDATING_CONFIG : 验证配置有效性
note right of APPLYING_CONFIG : 应用条件编译选项
5.2 工具链检测状态机
stateDiagram-v2
[*] --> IDLE: 检测开始
IDLE --> CHECKING_PYTHON: 检查Python
CHECKING_PYTHON --> CHECKING_BASH: Python检查完成
CHECKING_BASH --> CHECKING_COMPILER: Bash检查完成
CHECKING_COMPILER --> VALIDATING_VERSIONS: 编译器检查完成
VALIDATING_VERSIONS --> READY: 版本验证通过
VALIDATING_VERSIONS --> ERROR: 版本验证失败
READY --> CONFIGURING: 开始配置
CONFIGURING --> COMPLETED: 配置完成
ERROR --> [*]: 检测失败
COMPLETED --> [*]: 检测完成
note right of CHECKING_PYTHON : 查找Python解释器
note right of CHECKING_BASH : 查找Bash解释器
note right of CHECKING_COMPILER : 查找C++编译器
note right of VALIDATING_VERSIONS : 验证工具链版本
5.3 条件编译状态机
stateDiagram-v2
[*] --> IDLE: 编译开始
IDLE --> EVALUATING_CONDITIONS: 评估条件
EVALUATING_CONDITIONS --> SELECTING_TARGETS: 条件评估完成
SELECTING_TARGETS --> GENERATING_COPTS: 目标选择完成
GENERATING_COPTS --> GENERATING_LOPTS: 编译选项生成完成
GENERATING_LOPTS --> COMPILING: 链接选项生成完成
COMPILING --> COMPLETED: 编译完成
COMPLETED --> [*]: 编译成功
note right of EVALUATING_CONDITIONS : 评估GPU、CPU等条件
note right of SELECTING_TARGETS : 选择编译目标
note right of GENERATING_COPTS : 生成编译选项
note right of GENERATING_LOPTS : 生成链接选项
5.4 配置解析状态机
stateDiagram-v2
[*] --> IDLE: 解析开始
IDLE --> PARSING_CONFIG: 解析配置文件
PARSING_CONFIG --> RESOLVING_VARIABLES: 配置解析完成
RESOLVING_VARIABLES --> EXPANDING_TEMPLATES: 变量解析完成
EXPANDING_TEMPLATES --> VALIDATING: 模板展开完成
VALIDATING --> READY: 验证通过
VALIDATING --> ERROR: 验证失败
READY --> CACHING: 开始缓存
CACHING --> COMPLETED: 缓存完成
ERROR --> [*]: 解析失败
COMPLETED --> [*]: 解析完成
note right of PARSING_CONFIG : 解析.bzl配置文件
note right of RESOLVING_VARIABLES : 解析环境变量
note right of EXPANDING_TEMPLATES : 展开模板变量
note right of VALIDATING : 验证配置有效性
6. 源码分析
6.1 build_defs.bzl文件分析
6.1.1 文件结构概述
build_defs.bzl文件是Apollo平台配置的核心文件,定义了多个平台抽象函数,用于处理不同平台和特性的条件编译。
def if_gpu(if_true, if_false = []):
"""Shorthand for select()'ing on whether we're building with gpu enabled"""
return select({
"//tools/platform:use_gpu": if_true,
"//conditions:default": if_false,
})
6.1.2 if_gpu函数分析
def if_gpu(if_true, if_false = []):
"""Shorthand for select()'ing on whether we're building with gpu enabled
Returns a select statement which evaluates to if_true if we're building
with use_gpu enabled. Otherwise, the select statement evaluates to
if_false.
"""
return select({
"//tools/platform:use_gpu": if_true,
"//conditions:default": if_false,
})
该函数提供了一个简化的接口来处理GPU相关的条件编译。它使用Bazel的select语句,根据//tools/platform:use_gpu配置的值来选择返回if_true或if_false。
使用示例:
cc_library(
name = "gpu_module",
srcs = if_gpu(["gpu.cc"], ["cpu.cc"]),
copts = if_gpu(["-DUSE_GPU=1"], ["-DUSE_GPU=0"]),
)
6.1.3 copts_if_gpu函数分析
def copts_if_gpu():
return if_gpu(["-DUSE_GPU=1"], ["-DUSE_GPU=0"])
该函数是if_gpu的特化版本,专门用于生成编译选项。它返回一个列表,包含-DUSE_GPU=1(启用GPU)或-DUSE_GPU=0(禁用GPU)。
这种设计使得在cc_library规则中可以更简洁地使用:
cc_library(
name = "module",
copts = copts_if_gpu(),
)
6.1.4 if_teleop函数分析
def if_teleop(if_true, if_false = []):
return select({
"//tools/platform:with_teleop": if_true,
"//conditions:default": if_false,
})
该函数处理远程控制(teleoperation)相关的条件编译。远程控制功能允许通过远程接口控制车辆,这对于测试和调试非常有用。
6.1.5 copts_if_teleop函数分析
def copts_if_teleop():
return if_teleop(["-DWITH_TELEOP=1"], ["-DWITH_TELEOP=0"])
该函数生成远程控制相关的编译选项。
6.1.6 if_x86_64函数分析
def if_x86_64(if_true, if_false = []):
return select({
"@platforms//cpu:x86_64": if_true,
"//conditions:default": if_false,
})
该函数处理x86_64 CPU架构的条件编译。x86_64是Apollo在开发和测试中最常用的CPU架构。
6.1.7 if_aarch64函数分析
def if_aarch64(if_true, if_false = []):
return select({
"@platforms//cpu:aarch64": if_true,
"//conditions:default": if_false,
})
该函数处理ARM64(aarch64)CPU架构的条件编译。ARM64架构常用于嵌入式和车载系统。
6.1.8 if_esd_can函数分析
def if_esd_can(if_true, if_false = []):
return select({
"//tools/platform:use_esd_can": if_true,
"//conditions:default": if_false,
})
该函数处理ESD CAN总线相关的条件编译。ESD(Electronic System Design)是一家提供CAN接口卡的公司,其产品常用于车辆通信。
6.1.9 copts_if_esd_can函数分析
def copts_if_esd_can():
return if_esd_can(["-DUSE_ESD_CAN=1"], ["-DUSE_ESD_CAN=0"])
该函数生成ESD CAN总线相关的编译选项。
6.1.10 if_profiler函数分析
def if_profiler():
return select({
"//tools/platform:enable_profiler": ["-DENABLE_PROFILER=1"],
"//conditions:default": ["-DENABLE_PROFILER=0"],
})
该函数处理性能分析器相关的条件编译。性能分析器用于分析和优化代码性能。
6.2 common.bzl文件分析
6.2.1 文件结构概述
common.bzl文件提供了跨平台的通用工具函数,用于工具链定位、环境变量处理、文件操作等。该文件从TensorFlow项目借鉴而来,提供了丰富的实用函数。
# This file was adapted from third_party/remote_config/common.bzl in tensorflow.git
"""Functions common across configure rules."""
BAZEL_SH = "BAZEL_SH"
PYTHON_BIN_PATH = "PYTHON_BIN_PATH"
PYTHON_LIB_PATH = "PYTHON_LIB_PATH"
TF_PYTHON_CONFIG_REPO = "TF_PYTHON_CONFIG_REPO"
6.2.2 auto_config_fail函数分析
def auto_config_fail(msg):
"""Output failure message when auto configuration fails."""
red = "\033[0;31m"
no_color = "\033[0m"
fail("%sConfiguration Error:%s %s\n" % (red, no_color, msg))
该函数用于输出配置失败的错误信息。它使用ANSI颜色代码将错误信息显示为红色,提高可读性。
6.2.3 which函数分析
def which(repository_ctx, program_name):
"""Returns the full path to a program on the execution platform.
Args:
repository_ctx: the repository_ctx
program_name: name of the program on the PATH
Returns:
The full path to a program on the execution platform.
"""
result = execute(repository_ctx, ["which", program_name])
return result.stdout.rstrip()
该函数在执行平台上查找程序的全路径。它使用Unix的which命令来定位程序。
6.2.4 get_python_bin函数分析
def get_python_bin(repository_ctx):
"""Gets the python bin path.
Args:
repository_ctx: the repository_ctx
Returns:
The python bin path.
"""
python_bin = get_host_environ(repository_ctx, PYTHON_BIN_PATH)
if python_bin != None:
return python_bin
python_bin_path = which(repository_ctx, "python")
if python_bin_path == None:
auto_config_fail("Cannot find python in PATH, please make sure " +
"python is installed and add its directory in PATH, or --define " +
"%s='/something/else'.\nPATH=%s" % (
PYTHON_BIN_PATH,
get_environ("PATH", ""),
))
return python_bin_path
该函数获取Python解释器的路径。它首先检查环境变量PYTHON_BIN_PATH,如果未设置,则使用which命令查找Python。如果找不到Python,则输出错误信息并失败。
6.2.5 get_bash_bin函数分析
def get_bash_bin(repository_ctx):
"""Gets the bash bin path.
Args:
repository_ctx: the repository_ctx
Returns:
The bash bin path.
"""
bash_bin = get_host_environ(repository_ctx, BAZEL_SH)
if bash_bin != None:
return bash_bin
bash_bin_path = which(repository_ctx, "bash")
if bash_bin_path == None:
auto_config_fail("Cannot find bash in PATH, please make sure " +
"bash is installed and add its directory in PATH, or --define " +
"%s='/path/to/bash'.\nPATH=%s" % (
BAZEL_SH,
get_environ("PATH", ""),
))
return bash_bin_path
该函数获取Bash解释器的路径,逻辑与get_python_bin类似。
6.2.6 read_dir函数分析
def read_dir(repository_ctx, src_dir):
"""Returns a sorted list with all files in a directory.
Finds all files inside a directory, traversing subfolders and following
symlinks.
Args:
repository_ctx: the repository_ctx
src_dir: the directory to traverse
Returns:
A sorted list with all files in a directory.
"""
find_result = execute(
repository_ctx,
["find", src_dir, "-follow", "-type", "f"],
empty_stdout_fine = True,
)
result = find_result.stdout
return sorted(result.splitlines())
该函数递归地读取目录中的所有文件,包括子目录和符号链接。它使用Unix的find命令来查找文件。
6.2.7 get_environ函数分析
def get_environ(repository_ctx, name, default_value = None):
"""Returns the value of an environment variable on the execution platform.
Args:
repository_ctx: the repository_ctx
name: the name of environment variable
default_value: the value to return if not set
Returns:
The value of the environment variable 'name' on the execution platform
or 'default_value' if it's not set.
"""
cmd = "echo -n \"$%s\"" % name
result = execute(
repository_ctx,
[get_bash_bin(repository_ctx), "-c", cmd],
empty_stdout_fine = True,
)
if len(result.stdout) == 0:
return default_value
return result.stdout
该函数获取执行平台上的环境变量值。它使用Bash的echo命令来读取环境变量。
6.2.8 get_host_environ函数分析
def get_host_environ(repository_ctx, name, default_value = None):
"""Returns the value of an environment variable on the host platform.
The host platform is the machine that Bazel runs on.
Args:
repository_ctx: the repository_ctx
name: the name of environment variable
default_value: the value to return if not set
Returns:
The value of the environment variable 'name' on the host platform
or 'default_value' if it's not set.
"""
if name in repository_ctx.os.environ:
return repository_ctx.os.environ.get(name).strip()
if hasattr(repository_ctx.attr, "environ") and name in repository_ctx.attr.environ:
return repository_ctx.attr.environ.get(name).strip()
return default_value
该函数获取主机平台上的环境变量值。它首先检查repository_ctx.os.environ,然后检查repository_ctx.attr.environ。
6.2.9 execute函数分析
def execute(
repository_ctx,
cmdline,
error_msg = None,
error_details = None,
empty_stdout_fine = False,
ignore_error = True):
"""Executes an arbitrary shell command.
Args:
repository_ctx: the repository_ctx object
cmdline: list of strings, the command to execute
error_msg: string, a summary of the error if the command fails
error_details: string, details about the error or steps to fix it
empty_stdout_fine: bool, if True, an empty stdout result is fine,
otherwise it's an error
ignore_error: bool, if True, ignore errors
Returns:
The result of repository_ctx.execute(cmdline)
"""
result = raw_exec(repository_ctx, cmdline)
if result.stderr or not (empty_stdout_fine or result.stdout):
if not ignore_error:
fail(
"\n".join([
error_msg.strip() if error_msg else "Repository command failed",
result.stderr.strip(),
error_details if error_details else "",
]),
)
return result
该函数执行任意的shell命令,并提供错误处理机制。它调用raw_exec来执行命令,然后根据结果决定是否失败。
6.2.10 files_exist函数分析
def files_exist(repository_ctx, paths, bash_bin = None):
"""Checks which files in paths exists.
Args:
repository_ctx: the repository_ctx
paths: a list of paths
bash_bin: path to the bash interpreter
Returns:
Returns a list of Bool. True means that the path at the
same position in the paths list exists.
"""
if bash_bin == None:
bash_bin = get_bash_bin(repository_ctx)
cmd_tpl = "[ -e \"%s\" ] && echo True || echo False"
cmds = [cmd_tpl % path for path in paths]
cmd = " ; ".join(cmds)
stdout = execute(repository_ctx, [bash_bin, "-c", cmd]).stdout.strip()
return [val == "True" for val in stdout.splitlines()]
该函数检查哪些文件存在。它使用Bash的[ -e ]测试命令来检查文件存在性。
6.2.11 realpath函数分析
def realpath(repository_ctx, path, bash_bin = None):
"""Returns the result of "realpath path".
Args:
repository_ctx: the repository_ctx
path: a path on the file system
bash_bin: path to the bash interpreter
Returns:
Returns the result of "realpath path"
"""
if bash_bin == None:
bash_bin = get_bash_bin(repository_ctx)
return execute(repository_ctx, [bash_bin, "-c", "realpath \"%s\"" % path]).stdout.strip()
该函数返回路径的规范形式(解析所有符号链接)。
6.2.12 make_copy_files_rule函数分析
def make_copy_files_rule(repository_ctx, name, srcs, outs):
"""Returns a rule to copy a set of files."""
cmds = []
# Copy files.
for src, out in zip(srcs, outs):
cmds.append('cp -f "%s" "$(location %s)"' % (src, out))
outs = [(' "%s",' % out) for out in outs]
return """genrule(
name = "%s",
outs = [
%s
],
cmd = \"""%s \\""",
)""" % (name, "\n".join(outs), " && \\\n".join(cmds))
该函数生成一个Bazel genrule来复制一组文件。
6.2.13 make_copy_dir_rule函数分析
def make_copy_dir_rule(repository_ctx, name, src_dir, out_dir, exceptions = None):
"""Returns a rule to recursively copy a directory.
If exceptions is not None, it must be a list of files or directories in
'src_dir'; these will be excluded from copying.
"""
src_dir = _norm_path(src_dir)
out_dir = _norm_path(out_dir)
outs = read_dir(repository_ctx, src_dir)
post_cmd = ""
if exceptions != None:
outs = [x for x in outs if not any([
x.startswith(src_dir + "/" + y)
for y in exceptions
])]
outs = [(' "%s",' % out.replace(src_dir, out_dir)) for out in outs]
out_dir = "$(@D)/%s" % out_dir if len(outs) > 1 else "$(@D)"
if exceptions != None:
for x in exceptions:
post_cmd += " ; rm -fR " + out_dir + "/" + x
return """genrule(
name = "%s",
outs = [
%s
],
cmd = \"""cp -rLf "%s/." "%s/" %s\"\"",
)""" % (name, "\n".join(outs), src_dir, out_dir, post_cmd)
该函数生成一个Bazel genrule来递归复制目录,支持排除特定文件。
6.3 平台配置集成分析
6.3.1 WORKSPACE文件配置
平台配置需要在WORKSPACE文件中定义相应的配置标志:
# WORKSPACE文件
new_local_repository(
name = "platform",
path = "tools/platform",
build_file = "tools/platform/BUILD",
)
# 定义平台配置
# 通过命令行参数或配置文件设置
# --define use_gpu=1
# --define with_teleop=1
# --define use_esd_can=1
6.3.2 BUILD文件配置
在BUILD文件中使用平台抽象函数:
load("//tools/platform:build_defs.bzl", "if_gpu", "if_x86_64", "copts_if_gpu")
cc_library(
name = "perception_module",
srcs = if_gpu(["gpu_perception.cc"], ["cpu_perception.cc"]),
copts = copts_if_gpu() + if_x86_64(["-march=haswell"], []),
deps = [
"//cyber:cyber",
],
)
6.3.3 跨平台构建
支持跨平台构建的命令:
# x86_64平台构建
bazel build --config=linux //modules/...
# ARM64平台构建
bazel build --config=linux_aarch64 //modules/...
# GPU构建
bazel build --config=gpu //modules/...
6.4 工具链管理分析
6.4.1 Python工具链
Python工具链用于执行配置脚本和生成代码:
# 在配置规则中使用
python_bin = get_python_bin(repository_ctx)
result = execute(repository_ctx, [python_bin, "configure.py"])
6.4.2 Bash工具链
Bash工具链用于执行shell命令:
# 在配置规则中使用
bash_bin = get_bash_bin(repository_ctx)
result = execute(repository_ctx, [bash_bin, "-c", "ls -la"])
6.4.3 编译器工具链
编译器工具链通过Bazel的C++工具链配置:
# 在BUILD文件中使用
cc_toolchain_suite(
name = "toolchain",
toolchains = {
"//conditions:default": ":gcc_toolchain",
"@platforms//cpu:x86_64": ":gcc_x86_64_toolchain",
"@platforms//cpu:aarch64": ":gcc_aarch64_toolchain",
},
)
7. 设计模式
7.1 策略模式(Strategy Pattern)
build_defs.bzl中的条件函数体现了策略模式:
def if_gpu(if_true, if_false = []):
return select({
"//tools/platform:use_gpu": if_true,
"//conditions:default": if_false,
})
根据不同的配置选择不同的编译策略。
7.2 工厂模式(Factory Pattern)
工具链定位器使用工厂模式创建工具链实例:
def get_python_bin(repository_ctx):
python_bin = get_host_environ(repository_ctx, PYTHON_BIN_PATH)
if python_bin != None:
return python_bin
python_bin_path = which(repository_ctx, "python")
if python_bin_path == None:
auto_config_fail("Cannot find python...")
return python_bin_path
7.3 适配器模式(Adapter Pattern)
common.bzl中的函数适配了不同平台的差异:
def get_host_environ(repository_ctx, name, default_value = None):
if name in repository_ctx.os.environ:
return repository_ctx.os.environ.get(name).strip()
if hasattr(repository_ctx.attr, "environ") and name in repository_ctx.attr.environ:
return repository_ctx.attr.environ.get(name).strip()
return default_value
7.4 模板方法模式(Template Method Pattern)
规则生成函数使用模板方法模式:
def make_copy_files_rule(repository_ctx, name, srcs, outs):
cmds = []
for src, out in zip(srcs, outs):
cmds.append('cp -f "%s" "$(location %s)"' % (src, out))
# 生成genrule模板
return """genrule(...)"""
7.5 单例模式(Singleton Pattern)
全局常量体现了单例模式:
BAZEL_SH = "BAZEL_SH"
PYTHON_BIN_PATH = "PYTHON_BIN_PATH"
7.6 建造者模式(Builder Pattern)
复杂的配置可以使用建造者模式构建:
class PlatformConfigBuilder:
def __init__(self):
self.config = {}
def with_gpu(self, enabled):
self.config["use_gpu"] = enabled
return self
def with_teleop(self, enabled):
self.config["with_teleop"] = enabled
return self
def build(self):
return self.config
8. 总结
apollo_tools_platform子模块通过平台抽象层实现跨平台构建统一管理。模块采用build_defs.bzl和common.bzl核心文件,分别提供平台特定条件编译函数和通用工具链管理函数。通过if_gpu、if_x86_64、if_aarch64等函数实现GPU、CPU架构等特性条件编译,为Apollo多硬件平台构建提供基础设施支持。