05_apollo_tools子模块整体软件架构深入分析文档
1. 概述
Apollo Tools子模块是Apollo自动驾驶平台的开发工具集,提供完整的构建、安装、打包和平台支持工具。采用模块化架构设计,包含外部依赖管理、安装工具、打包工具、平台支持、协议工具和ROS集成等核心组件,实现开发流程自动化和标准化,简化平台构建部署过程,为开发者提供高效便捷的开发工具链。
2. 软件架构图
graph TB
subgraph "Tools子模块"
subgraph "外部依赖管理"
E1[外部库配置]:::key
E2[依赖构建规则]:::key
end
subgraph "安装工具"
I1[安装脚本]:::key
I2[安装配置]:::key
I3[源码安装]:::key
end
subgraph "打包工具"
P1[打包规则]:::key
P2[动态依赖]:::key
P3[补丁管理]:::key
end
subgraph "平台支持"
PL1[构建定义]:::key
PL2[通用规则]:::key
end
subgraph "协议工具"
PR1[Proto构建规则]:::key
PR2[消息定义]:::key
end
subgraph "ROS集成"
R1[ROS构建规则]:::key
R2[ROS配置]:::key
end
subgraph "核心工具"
C1[构建系统扩展]:::key
C2[代码检查]:::key
C3[启动工具]:::key
end
end
subgraph "外部依赖"
EX1[Bazel构建系统]:::key
EX2[Protobuf]:::key
EX3[ROS框架]
EX4[系统工具]
end
E1 --> EX1
E2 --> EX1
I1 --> EX1
I2 --> EX1
I3 --> EX1
P1 --> EX1
P2 --> EX1
P3 --> EX1
PL1 --> EX1
PL2 --> EX1
PR1 --> EX1
PR2 --> EX2
R1 --> EX1
R2 --> EX3
C1 --> EX1
C2 --> EX4
C3 --> EX1
classDef key fill:#e1f5fe
3. 调用流程图
sequenceDiagram
participant User as 开发者
participant Bazel as Bazel构建系统
participant Tools as Tools子模块
participant External as 外部依赖
participant Apollo as Apollo系统
User->>Bazel: 执行bazel build命令
Bazel->>Tools: 加载构建规则
Tools->>Tools: 解析构建配置
Tools->>Tools: 检查外部依赖
Tools->>External: 验证依赖状态
External-->>Tools: 依赖状态返回
alt 依赖未安装
Tools->>Tools: 执行安装脚本
Tools->>External: 下载依赖包
External-->>Tools: 依赖包下载完成
Tools->>External: 安装依赖
External-->>Tools: 依赖安装完成
end
Tools->>Bazel: 返回构建配置
Bazel->>Apollo: 执行构建流程
Apollo->>Apollo: 编译源代码
Apollo->>Apollo: 生成可执行文件
Apollo-->>Bazel: 构建完成
Bazel-->>User: 返回构建结果
User->>Bazel: 执行bazel run命令
Bazel->>Tools: 加载运行规则
Tools->>Tools: 配置运行环境
Tools->>Apollo: 设置环境变量
Apollo->>Apollo: 启动系统组件
Apollo-->>User: 系统运行输出
4. 详细UML类图
4.1. 核心模块类图
classDiagram
class ToolsSystem {
+initialize()
+loadRules()
+executeCommand()
+cleanupResources()
+getToolStatus(): ToolStatus
-buildRules: list
-installers: list
-packagers: list
-config: ToolConfig
-logger: Logger
}
class BuildRule {
<>
+apply()
+validate(): bool
+getDependencies(): list
-ruleName: string
-dependencies: list
-priority: int
}
class BazelRule {
+loadExtension()
+registerRule()
+generateBuildCommands(): list
-extensionName: string
-extensionPath: string
-ruleConfig: RuleConfig
}
class ProtoRule {
+generateProto()
+generateCC()
+generatePython()
+generateROS()
-protoPath: string
-outputPath: string
-language: string
}
class ROSRule {
+generateROS()
+configureROS()
+buildROSNode()
-rosDistro: string
-rosPackage: string
-nodeName: string
}
class Installer {
<>
+install()
+uninstall()
+getVersion(): string
+isInstalled(): bool
-packageName: string
-version: string
-sourceUrl: string
}
class SourceInstaller {
+downloadSource()
+compileSource()
+installBinary()
+cleanupSource()
-sourcePath: string
-buildOptions: string
-installPath: string
}
class Packager {
<>
+package()
+verify()
+sign()
-packageType: string
-outputDir: string
-components: list
}
class DynamicPackager {
+resolveDependencies()
+generateManifest()
+createPackage()
-dependencyGraph: DependencyGraph
-manifestPath: string
-packageFormat: string
}
ToolsSystem --> BuildRule
ToolsSystem --> Installer
ToolsSystem --> Packager
ToolsSystem --> ToolConfig
ToolsSystem --> Logger
BuildRule <|-- BazelRule
BuildRule <|-- ProtoRule
BuildRule <|-- ROSRule
Installer <|-- SourceInstaller
Packager <|-- DynamicPackager
BazelRule --> RuleConfig
ProtoRule --> LanguageConfig
ROSRule --> ROSConfig
DynamicPackager --> DependencyGraph
4.2. 数据流类图
classDiagram
class ToolData {
<>
+getTimestamp(): timestamp
+getDataId(): string
+serialize(): bytes
+deserialize(bytes)
#timestamp: timestamp
#dataId: string
#source: string
}
class BuildData {
+getBuildType(): string
+getTargets(): list
+getOptions(): map
+getDependencies(): list
-buildType: string
-targets: list
-options: map
-dependencies: list
-progress: float
}
class InstallData {
+getPackageName(): string
+getVersion(): string
+getInstallType(): string
+getDependencies(): list
-packageName: string
-version: string
-installType: string
-dependencies: list
-sourceUrl: string
-installPath: string
}
class PackageData {
+getPackageType(): string
+getComponents(): list
+getDependencies(): list
+getManifest(): string
-packageType: string
-components: list
-dependencies: list
-manifest: string
-outputPath: string
-signStatus: bool
}
class ConfigData {
+getConfigKey(): string
+getConfigValue(): string
+getScope(): string
+isMandatory(): bool
-configKey: string
-configValue: string
-scope: string
-isMandatory: bool
-defaultValue: string
-description: string
}
ToolData <|-- BuildData
ToolData <|-- InstallData
ToolData <|-- PackageData
ToolData <|-- ConfigData
BuildData --> ConfigData
InstallData --> ConfigData
PackageData --> ConfigData
BuildData --> PackageData
InstallData --> BuildData
4.3. 配置管理类图
classDiagram
class ToolConfig {
+loadConfig(string): bool
+saveConfig(string): bool
+getModuleConfig(string): ModuleConfig
+setModuleConfig(string, ModuleConfig): bool
+getGlobalConfig(): GlobalConfig
+setGlobalConfig(GlobalConfig): bool
+validateConfig(): bool
-modules: map
-globalConfig: GlobalConfig
-logger: Logger
}
class ModuleConfig {
<>
+validate(): bool
+getModuleName(): string
+isEnabled(): bool
+getPriority(): int
-moduleName: string
-enabled: bool
-priority: int
-configPath: string
}
class BuildConfig {
+getBazelVersion(): string
+getBuildOptions(): map
+getDefaultTargets(): list
+getBuildType(): string
-bazelVersion: string
-buildOptions: map
-defaultTargets: list
-buildType: string
-parallelJobs: int
}
class InstallConfig {
+getDefaultInstallPath(): string
+getProxySettings(): string
+isSourceInstallEnabled(): bool
+getDownloadTimeout(): int
-defaultInstallPath: string
-proxySettings: string
-sourceInstallEnabled: bool
-downloadTimeout: int
-cacheDir: string
}
class PackageConfig {
+getPackageFormat(): string
+getOutputDir(): string
+isSignEnabled(): bool
+getPackageVersion(): string
-packageFormat: string
-outputDir: string
-signEnabled: bool
-packageVersion: string
-manifestTemplate: string
}
class GlobalConfig {
+getLogLevel(): string
+getTempDir(): string
+getCacheDir(): string
+isDebugMode(): bool
-logLevel: string
-tempDir: string
-cacheDir: string
-debugMode: bool
-timeout: int
}
ToolConfig --> ModuleConfig
ToolConfig --> GlobalConfig
ToolConfig --> Logger
ModuleConfig <|-- BuildConfig
ModuleConfig <|-- InstallConfig
ModuleConfig <|-- PackageConfig
BuildConfig --> GlobalConfig
InstallConfig --> GlobalConfig
PackageConfig --> GlobalConfig
5. 状态机
5.1. 工具执行状态机
stateDiagram-v2
[*] --> Ready: 工具初始化完成
Ready --> Running: 执行命令
Running --> Processing: 处理任务
Processing --> Waiting: 等待依赖
Waiting --> Processing: 依赖就绪
Processing --> Success: 任务完成
Processing --> Failed: 任务失败
Success --> Ready: 准备下一个任务
Failed --> Ready: 准备重试
Running --> Canceled: 取消任务
Canceled --> Ready: 任务取消完成
state Processing {
[*] --> Validating: 验证输入
Validating --> Executing: 执行操作
Executing --> PostProcessing: 后处理
PostProcessing --> [*]: 处理完成
}
state Waiting {
[*] --> CheckingDependencies: 检查依赖
CheckingDependencies --> [*]: 依赖检查完成
}
5.2. 依赖管理状态机
stateDiagram-v2
[*] --> Unknown: 未知状态
Unknown --> Checking: 检查依赖
Checking --> Installed: 已安装
Checking --> NotInstalled: 未安装
NotInstalled --> Downloading: 下载依赖
Downloading --> Downloaded: 下载完成
Downloaded --> Installing: 安装依赖
Installing --> Installed: 安装完成
Installed --> Updating: 更新依赖
Updating --> Installed: 更新完成
Downloading --> DownloadFailed: 下载失败
Installing --> InstallFailed: 安装失败
DownloadFailed --> NotInstalled: 重试下载
InstallFailed --> NotInstalled: 重试安装
Installed --> [*]: 依赖管理完成
NotInstalled --> [*]: 依赖管理完成
5.3. 构建流程状态机
stateDiagram-v2
[*] --> Initialized: 构建初始化
Initialized --> Configuring: 配置构建
Configuring --> Validating: 验证配置
Validating --> Building: 开始构建
Building --> Compiling: 编译代码
Compiling --> Linking: 链接库
Linking --> Packaging: 打包输出
Packaging --> Success: 构建成功
Success --> [*]: 构建完成
Configuring --> ConfigError: 配置错误
Validating --> ValidationError: 验证错误
Building --> BuildError: 构建错误
Compiling --> CompileError: 编译错误
Linking --> LinkError: 链接错误
Packaging --> PackageError: 打包错误
ConfigError --> Fixing: 修复错误
ValidationError --> Fixing: 修复错误
BuildError --> Fixing: 修复错误
CompileError --> Fixing: 修复错误
LinkError --> Fixing: 修复错误
PackageError --> Fixing: 修复错误
Fixing --> Configuring: 重新配置
6. 源码分析
6.1. 构建系统扩展核心代码分析
6.1.1. apollo.bzl 核心逻辑
python
# 加载Bazel扩展
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
# 定义外部依赖def apollo_repositories():
"""Apollo 依赖仓库定义"""
# Protobuf 依赖
maybe(
http_archive,
name = "com_google_protobuf",
urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.19.0.zip"],
sha256 = "...",
strip_prefix = "protobuf-3.19.0",
)
# gRPC 依赖
maybe(
http_archive,
name = "com_github_grpc_grpc",
urls = ["https://github.com/grpc/grpc/archive/v1.40.0.zip"],
sha256 = "...",
strip_prefix = "grpc-1.40.0",
)
# 定义构建规则def apollo_cc_library(name, **kwargs):
"""Apollo C++ 库构建规则"""
native.cc_library(
name = name,
copts = ["-std=c++17", "-Wall", "-Werror"],
**kwargs
)
def apollo_cc_binary(name, **kwargs):
"""Apollo C++ 二进制文件构建规则"""
native.cc_binary(
name = name,
copts = ["-std=c++17", "-Wall", "-Werror"],
**kwargs
)
6.1.2. proto.bzl 核心逻辑
python
# Protobuf 构建规则
def apollo_proto_library(
name,
srcs = [],
deps = [],
cc_deps = [],
python_deps = [],
visibility = None,
**kwargs
):
"""Apollo Protobuf 库构建规则"""
# 生成 Protobuf 代码
proto_deps = ["@com_google_protobuf//:protobuf"] + deps
native.proto_library(
name = name,
srcs = srcs,
deps = proto_deps,
visibility = visibility,
**kwargs
)
# 生成 C++ 代码
cc_proto_name = name + "_cc"
native.cc_proto_library(
name = cc_proto_name,
deps = [":" + name],
visibility = visibility,
**kwargs
)
# 生成 Python 代码
py_proto_name = name + "_py"
native.py_proto_library(
name = py_proto_name,
deps = [":" + name],
visibility = visibility,
**kwargs
)
6.2. 安装工具核心代码分析
6.2.1. install.bzl 核心逻辑
python
# 安装规则定义
def apollo_install(
name,
targets = [],
output_dir = "",
data = [],
deps = [],
**kwargs
):
"""Apollo 安装规则"""
# 生成安装脚本
script_name = name + "_install_script"
native.genrule(
name = script_name,
srcs = targets + data,
outs = [name + ".sh"],
cmd = "generate_install_script $@ $^",
**kwargs
)
# 定义安装目标
native.sh_binary(
name = name,
srcs = [script_name],
data = targets + data,
deps = deps,
**kwargs
)
def apollo_source_install(
name,
url,
sha256,
strip_prefix,
install_path = "/usr/local",
**kwargs
):
"""Apollo 源码安装规则"""
# 定义外部仓库
native.new_local_repository(
name = name + "_source",
path = "@" + name + "_archive//:",
build_file_content = generate_build_file(name, install_path),
)
# 定义安装目标
apollo_install(
name = name,
targets = [":" + name + "_source"],
**kwargs
)
6.2.2. install.py.in 核心逻辑
python
#!/usr/bin/env python3
import os
import sys
import shutil
import subprocess
def install_package(package_name, version, install_path):
"""安装包"""
print(f"Installing {package_name} {version}...")
# 检查安装路径
if not os.path.exists(install_path):
os.makedirs(install_path)
# 下载包
download_package(package_name, version)
# 解压包
extract_package(package_name, version)
# 编译安装
compile_install(package_name, version, install_path)
# 清理
cleanup_package(package_name, version)
print(f"{package_name} {version} installed successfully.")
def download_package(package_name, version):
"""下载包"""
url = get_package_url(package_name, version)
cmd = ["wget", "-O", f"{package_name}-{version}.tar.gz", url]
subprocess.check_call(cmd)
def extract_package(package_name, version):
"""解压包"""
cmd = ["tar", "-xzf", f"{package_name}-{version}.tar.gz"]
subprocess.check_call(cmd)
def compile_install(package_name, version, install_path):
"""编译安装"""
src_dir = f"{package_name}-{version}"
os.chdir(src_dir)
# 配置
cmd = ["./configure", f"--prefix={install_path}"]
subprocess.check_call(cmd)
# 编译
cmd = ["make", "-j4"]
subprocess.check_call(cmd)
# 安装
cmd = ["make", "install"]
subprocess.check_call(cmd)
os.chdir("..")
6.3. 打包工具核心代码分析
6.3.1. dynamic_deps.bzl 核心逻辑
python
# 动态依赖解析
def resolve_dependencies(target, deps = []):
"""解析目标的动态依赖"""
# 获取目标信息
target_info = get_target_info(target)
# 解析直接依赖
direct_deps = target_info.get("deps", [])
# 递归解析依赖
all_deps = deps.copy()
for dep in direct_deps:
if dep not in all_deps:
all_deps.append(dep)
all_deps = resolve_dependencies(dep, all_deps)
return all_deps
def generate_manifest(target, output_file):
"""生成依赖清单"""
deps = resolve_dependencies(target)
# 生成清单内容
manifest_content = generate_manifest_content(deps)
# 写入文件
native.genrule(
name = target + "_manifest",
outs = [output_file],
cmd = "echo '" + manifest_content + "' > $@",
)
def create_package(
name,
target,
package_format = "tar.gz",
output_dir = "packages",
**kwargs
):
"""创建包"""
# 生成依赖清单
manifest_file = name + ".manifest"
generate_manifest(target, manifest_file)
# 生成打包脚本
script_name = name + "_package_script"
native.genrule(
name = script_name,
srcs = [manifest_file],
outs = [name + ".sh"],
cmd = "generate_package_script $@ $^ " + package_format + " " + output_dir,
**kwargs
)
# 定义打包目标
native.sh_binary(
name = name,
srcs = [script_name],
data = [manifest_file],
**kwargs
)
6.4. 平台支持核心代码分析
6.4.1. build_defs.bzl 核心逻辑
python
# 平台构建定义
def platform_specific_build(name, **kwargs):
"""平台特定构建"""
# 检测当前平台
platform = detect_platform()
# 根据平台选择构建规则
if platform == "linux_x86_64":
linux_x86_64_build(name, **kwargs)
elif platform == "linux_aarch64":
linux_aarch64_build(name, **kwargs)
elif platform == "windows_x86_64":
windows_x86_64_build(name, **kwargs)
else:
fail("Unsupported platform: " + platform)
def detect_platform():
"""检测当前平台"""
import platform
os_name = platform.system().lower()
arch = platform.machine()
if os_name == "linux":
if arch == "x86_64":
return "linux_x86_64"
elif arch == "aarch64":
return "linux_aarch64"
elif os_name == "windows":
if arch == "AMD64":
return "windows_x86_64"
fail("Unsupported platform: " + os_name + "_" + arch)
def linux_x86_64_build(name, **kwargs):
"""Linux x86_64 构建"""
native.cc_library(
name = name,
copts = ["-m64", "-std=c++17"],
linkopts = ["-m64"],
**kwargs
)
6.5. ROS集成核心代码分析
6.5.1. ros_configure.bzl 核心逻辑
python
# ROS 配置规则
def ros_configure(name, ros_distro = "melodic", **kwargs):
"""ROS 配置"""
# 检测 ROS 环境
ros_env = detect_ros_environment(ros_distro)
# 生成 ROS 配置文件
native.genrule(
name = name + "_config",
outs = [name + ".bzl"],
cmd = "generate_ros_config $@ " + ros_env,
**kwargs
)
# 加载 ROS 配置
load(":" + name + ".bzl", "ros_libraries", "ros_include_dirs")
def ros_cc_library(name, deps = [], **kwargs):
"""ROS C++ 库构建规则"""
# 添加 ROS 依赖
ros_deps = get_ros_dependencies(deps)
native.cc_library(
name = name,
deps = deps + ros_deps,
copts = ["-I/opt/ros/melodic/include"],
linkopts = ["-L/opt/ros/melodic/lib"],
**kwargs
)
def get_ros_dependencies(deps):
"""获取 ROS 依赖"""
ros_deps = []
for dep in deps:
if dep.startswith("ros/"):
ros_deps.append("@ros//:" + dep[4:])
return ros_deps
6.6. 辅助工具核心代码分析
6.6.1. cpplint.bzl 核心逻辑
python
# C++ 代码检查规则
def cpplint(name, srcs = [], include_dirs = [], **kwargs):
"""C++ 代码检查"""
# 生成检查脚本
script_name = name + "_cpplint_script"
native.genrule(
name = script_name,
srcs = srcs,
outs = [name + ".sh"],
cmd = "generate_cpplint_script $@ $^ " + " ".join(include_dirs),
**kwargs
)
# 定义检查目标
native.sh_binary(
name = name,
srcs = [script_name],
data = srcs,
**kwargs
)
def cpplint_test(name, srcs = [], include_dirs = [], **kwargs):
"""C++ 代码检查测试"""
cpplint(
name = name + "_cpplint",
srcs = srcs,
include_dirs = include_dirs,
**kwargs
)
native.test(
name = name,
size = "small",
srcs = [name + "_cpplint"],
data = srcs,
**kwargs
)
6.6.2. bootstrap.py 核心逻辑
python
#!/usr/bin/env python3
# Bootstrap 脚本
import os
import sys
import subprocess
def check_requirements():
"""检查系统要求"""
print("Checking system requirements...")
# 检查 Python 版本
if sys.version_info < (3, 6):
print("Error: Python 3.6 or higher is required.")
return False
# 检查 Bazel
try:
subprocess.check_output(["bazel", "--version"])
except FileNotFoundError:
print("Error: Bazel is not installed.")
return False
print("System requirements checked successfully.")
return True
def setup_environment():
"""设置环境"""
print("Setting up environment...")
# 配置环境变量
os.environ["APOLLO_HOME"] = os.getcwd()
os.environ["PATH"] = os.environ["APOLLO_HOME"] + "/bin:" + os.environ["PATH"]
# 创建必要的目录
for dir_name in ["bin", "lib", "include", "data"]:
if not os.path.exists(dir_name):
os.makedirs(dir_name)
print("Environment set up successfully.")
return True
def build_tools():
"""构建工具"""
print("Building tools...")
# 执行 Bazel 构建
try:
subprocess.check_call(["bazel", "build", "//tools/..."])
except subprocess.CalledProcessError:
print("Error: Failed to build tools.")
return False
print("Tools built successfully.")
return True
def main():
"""主函数"""
print("Apollo Tools Bootstrap")
print("=" * 30)
# 检查系统要求
if not check_requirements():
return 1
# 设置环境
if not setup_environment():
return 1
# 构建工具
if not build_tools():
return 1
print("\nBootstrap completed successfully!")
print("You can now use Apollo tools.")
return 0
if __name__ == "__main__":
sys.exit(main())
7. 设计模式
7.1. 策略模式
Apollo Tools子模块在构建系统中广泛使用策略模式,针对不同平台和构建类型采用不同的构建策略。
python
# 策略模式的实现
def build_target(target, platform):
"""根据平台构建目标"""
# 选择构建策略
build_strategy = get_build_strategy(platform)
# 执行构建
build_strategy.build(target)
def get_build_strategy(platform):
"""获取构建策略"""
if platform == "linux_x86_64":
return LinuxX8664BuildStrategy()
elif platform == "linux_aarch64":
return LinuxAarch64BuildStrategy()
elif platform == "windows_x86_64":
return WindowsX8664BuildStrategy()
else:
raise ValueError("Unsupported platform: " + platform)
# 构建策略基类
class BuildStrategy:
"""构建策略基类"""
def build(self, target):
"""构建目标"""
raise NotImplementedError("build() must be implemented")
# Linux x86_64 构建策略
class LinuxX8664BuildStrategy(BuildStrategy):
"""Linux x86_64 构建策略"""
def build(self, target):
"""构建目标"""
print("Building for Linux x86_64")
# 执行 Linux x86_64 构建逻辑
7.2. 工厂方法模式
在安装工具中,工厂方法模式用于创建不同类型的安装器。
python
# 工厂方法模式的实现
def create_installer(install_type, **kwargs):
"""创建安装器"""
if install_type == "binary":
return BinaryInstaller(**kwargs)
elif install_type == "source":
return SourceInstaller(**kwargs)
elif install_type == "package":
return PackageInstaller(**kwargs)
else:
raise ValueError("Unsupported install type: " + install_type)
# 安装器基类
class Installer:
"""安装器基类"""
def install(self):
"""安装"""
raise NotImplementedError("install() must be implemented")
# 二进制安装器
class BinaryInstaller(Installer):
"""二进制安装器"""
def install(self):
"""安装"""
print("Installing binary package")
# 执行二进制安装逻辑
# 源码安装器
class SourceInstaller(Installer):
"""源码安装器"""
def install(self):
"""安装"""
print("Installing from source")
# 执行源码安装逻辑
7.3. 观察者模式
在依赖管理中,观察者模式用于监控依赖状态变化。
python
# 观察者模式的实现
class DependencyManager:
"""依赖管理器"""
def __init__(self):
self._observers = []
def add_observer(self, observer):
"""添加观察者"""
self._observers.append(observer)
def remove_observer(self, observer):
"""移除观察者"""
self._observers.remove(observer)
def notify_observers(self, dependency, status):
"""通知观察者"""
for observer in self._observers:
observer.update(dependency, status)
def update_dependency_status(self, dependency, status):
"""更新依赖状态"""
# 更新依赖状态
self._dependencies[dependency] = status
# 通知观察者
self.notify_observers(dependency, status)
# 观察者接口
class DependencyObserver:
"""依赖观察者接口"""
def update(self, dependency, status):
"""更新"""
raise NotImplementedError("update() must be implemented")
# 构建观察者
class BuildObserver(DependencyObserver):
"""构建观察者"""
def update(self, dependency, status):
"""更新"""
if status == "installed":
print("Dependency " + dependency + " installed, continuing build")
# 继续构建流程
elif status == "failed":
print("Dependency " + dependency + " failed to install, stopping build")
# 停止构建流程
7.4. 模板方法模式
在安装流程中,模板方法模式用于定义安装流程的骨架。
python
# 模板方法模式的实现
class InstallTemplate:
"""安装模板"""
def install(self):
"""安装流程"""
self.pre_install()
self.do_install()
self.post_install()
self.verify_install()
def pre_install(self):
"""安装前准备"""
print("Preparing for installation...")
def do_install(self):
"""执行安装"""
raise NotImplementedError("do_install() must be implemented")
def post_install(self):
"""安装后处理"""
print("Performing post-installation tasks...")
def verify_install(self):
"""验证安装"""
print("Verifying installation...")
# 具体安装实现
class BazelInstaller(InstallTemplate):
"""Bazel 安装器"""
def do_install(self):
"""执行安装"""
print("Installing Bazel...")
# Bazel 安装逻辑
class ProtobufInstaller(InstallTemplate):
"""Protobuf 安装器"""
def do_install(self):
"""执行安装"""
print("Installing Protobuf...")
# Protobuf 安装逻辑
7.5. 单例模式
在配置管理中,单例模式用于管理全局配置。
python
# 单例模式的实现
class ConfigManager:
"""配置管理器"""
_instance = None
def __new__(cls, *args, **kwargs):
"""创建单例"""
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
cls._instance._initialize()
return cls._instance
def _initialize(self):
"""初始化配置"""
self._config = {}
def load_config(self, config_file):
"""加载配置"""
# 加载配置文件
with open(config_file, "r") as f:
self._config = parse_config(f.read())
def get_config(self, key, default = None):
"""获取配置"""
return self._config.get(key, default)
def set_config(self, key, value):
"""设置配置"""
self._config[key] = value
# 使用单例
config_manager = ConfigManager()
config_manager.load_config("config.yaml")
bazel_version = config_manager.get_config("bazel.version", "4.2.2")
7.6. 装饰器模式
在构建规则中,装饰器模式用于扩展构建规则的功能。
python
# 装饰器模式的实现
def with_debug_info(func):
"""添加调试信息装饰器"""
def wrapper(*args, **kwargs):
"""包装函数"""
# 添加调试信息选项
if "copts" not in kwargs:
kwargs["copts"] = []
kwargs["copts"].append("-g")
if "linkopts" not in kwargs:
kwargs["linkopts"] = []
kwargs["linkopts"].append("-g")
# 调用原始函数
return func(*args, **kwargs)
return wrapper
# 使用装饰器扩展构建规则
@with_debug_info
def debug_cc_library(name, **kwargs):
"""带调试信息的 C++ 库构建规则"""
native.cc_library(name = name, **kwargs)
# 使用装饰后的规则
debug_cc_library(
name = "my_debug_lib",
srcs = ["my_lib.cc"],
hdrs = ["my_lib.h"],
)
7.7. 命令模式
在工具执行中,命令模式用于封装工具命令。
python
# 命令模式的实现
class Command:
"""命令基类"""
def execute(self):
"""执行命令"""
raise NotImplementedError("execute() must be implemented")
def undo(self):
"""撤销命令"""
raise NotImplementedError("undo() must be implemented")
class BuildCommand(Command):
"""构建命令"""
def __init__(self, target):
"""初始化"""
self._target = target
def execute(self):
"""执行命令"""
print("Building target: " + self._target)
subprocess.check_call(["bazel", "build", self._target])
def undo(self):
"""撤销命令"""
print("Cleaning target: " + self._target)
subprocess.check_call(["bazel", "clean", self._target])
class InstallCommand(Command):
"""安装命令"""
def __init__(self, target):
"""初始化"""
self._target = target
def execute(self):
"""执行命令"""
print("Installing target: " + self._target)
subprocess.check_call(["bazel", "run", self._target + "_install"])
def undo(self):
"""撤销命令"""
print("Uninstalling target: " + self._target)
subprocess.check_call(["bazel", "run", self._target + "_uninstall"])
# 命令执行器
class CommandExecutor:
"""命令执行器"""
def __init__(self):
"""初始化"""
self._history = []
def execute_command(self, command):
"""执行命令"""
command.execute()
self._history.append(command)
def undo_last(self):
"""撤销最后一条命令"""
if self._history:
command = self._history.pop()
command.undo()
8. 总结
Apollo Tools子模块是Apollo自动驾驶平台的重要开发工具集,通过模块化架构设计提供了完整的构建、安装、打包和平台支持功能。该模块采用多种设计模式,如策略模式、工厂方法模式、观察者模式等,提高了代码的可维护性和扩展性。Tools子模块为Apollo平台的开发和部署提供了高效、便捷的工具链,是平台生态系统的重要组成部分,为开发者提供了一致的开发体验,促进了Apollo自动驾驶技术的发展和应用。