Bazel C++ 构建系列文档(七):编译选项与工具链
1. 编译模式配置
Bazel 提供了多种编译模式,满足不同的开发需求。
1.1 三种主要编译模式
# 快速构建(默认)bazel build //:app -c fastbuild# 调试模式bazel build //:app -c dbg# 优化模式bazel build //:app -c opt
1.2 编译模式详解
|
|
|
|
|---|---|---|
fastbuild |
|
|
dbg |
|
|
opt |
|
|
1.3 在 .bazelrc 中配置默认模式
# .bazelrcbuild -c fastbuild # 默认使用 fastbuild# 针对不同模式配置build:opt -c optbuild:dbg -c dbg# 快速模式特定的优化build:fastbuild --copt=-Ogbuild:fastbuild --linkopt=-O1# 调试模式特定的配置build:dbg --copt=-gbuild:dbg --copt=-DDEBUG=1# 优化模式特定配置build:opt --copt=-O3build:opt --copt=march=native
1.4 使用 --config 简化命令
# .bazelrcconfig debug --config=dbgconfig release --config=optconfig profile --config=fastbuild# 使用bazel build //:app --config=debug
2. 编译器选项(copts, cxxopts)
copts 用于 C 编译选项,cxxopts 用于 C++ 编译选项。
2.1 基本用法
cc_library(name = "my_lib",srcs = ["mylib.cc"],hdrs = ["mylib.h"],copts = ["-Wall", "-Wextra"], # C 编译选项cxxopts = ["-std=c++17", "-fPIC"], # C++ 特定选项)
2.2 条件编译选项
cc_library(name = "platform_lib",copts = select({"//:windows": ["/W4", "/EHsc"], # MSVC 选项"//:linux": ["-Wall", "-Wpedantic"], # GCC 选项"//conditions:default": [], # 默认选项}),cxxopts = select({"//:windows": ["/std:c++17"],"//:linux": ["-std=c++17"],"//conditions:default": ["-std=c++14"],}),deps = select({"//:windows": ["//third_party:msvc_runtime"],"//:linux": ["//third_party:libcxx"],}),)
2.3 多个源文件的不同选项
cc_library(name = "mixed_lib",srcs = {"production": ["prod.cc"], # 生产代码"test": ["test.cc"], # 测试代码},copts = ["-Wall"],# 不同源文件使用不同选项copts = select({":production_config": ["-O2", "-DNDEBUG"],":test_config": ["-g", "-DDEBUG"],}),)
2.4 针对特定文件的选项
cc_library(name = "optimizable_lib",srcs = glob(["*.cc"]),# 对某些文件使用特殊优化copts = ["-Wno-missing-field-initializers", # 全局选项] + select({"**/*_simd.cc": ["-mavx2", "-mfma"], # SIMD 文件"//conditions:default": [], # 其他文件}),)
3. 预处理器宏定义
3.1 defines 属性
cc_library(name = "configurable_lib",defines = ["DEBUG=1","ENABLE_LOGGING","VERSION=\"1.2.3\"",],)
3.2 条件宏定义
cc_library(name = "feature_lib",defines = select({"//:enable_feature_x": ["FEATURE_X=1"],"//:enable_feature_y": ["FEATURE_Y=1"],"//conditions:default": [], # 没有定义任何特性}),)
3.3 从外部传入定义
# 命令行定义bazel build //:app --defines="DEBUG=1,ENABLE_TRACE"# 通过环境变量export MY_DEFINE="CUSTOM_VALUE=123"bazel build //:app --action_env=MY_DEFINE
3.4 CMake 风格的宏
# 模拟 CMake 的 add_definitionsdefines = [# 定义宏的值"VERSION=2.0",# 定义没有值的宏"ENABLE_PROFILING",# 定义布尔值"USE_ASYNC_IO=true",]
4. 工具链配置
4.1 默认工具链
Bazel 使用 @local_config_cc 仓库自动检测系统中的 C++ 编译器。
4.2 自定义工具链
# tools/cpp_toolchain/BUILDpackage(default_visibility = ["//visibility:public"])toolchain(name = "clang_toolchain",toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",toolchain = ":clang_toolchain_impl",)cc_toolchain(name = "clang_toolchain_impl",all_files = ":clang_files",compiler_files = ":clang_compiler",compiler_files_executable = ":clang_compiler_exe",archiver_files = ":clang_ar",archiver_files_executable = ":clang_ar_exe",runtime_files = ":clang_runtime",runtime_files_executable = ":clang_runtime_exe",objcopy_files = ":clang_objcopy",objcopy_files_executable = ":clang_objcopy_exe",strip_files = ":clang_strip",strip_files_executable = ":clang_strip_exe",dwp_files = ":clang_dwp",dwp_files_executable = ":clang_dwp_exe",coverage_files = ":clang_cov",coverage_files_executable = ":clang_cov_exe",asm_files = ":clang_asm",asm_files_executable = ":clang_asm_exe",ld_files = ":clang_ld",ld_files_executable = ":clang_ld_exe",linker_files = ":clang_linker",linker_files_executable = ":clang_linker_exe",)
4.3 使用自定义工具链
# 使用自定义工具链bazel build //:app --toolchain_resolution_debug --extra_toolchains="//tools/cpp_toolchain:clang_toolchain"# 在 .bazelrc 中配置build --extra_toolchains=//tools/cpp_toolchain:clang_toolchain
4.4 选择不同编译器
# 通过 constraint 选择编译器cc_library(name = "compiler_specific",copts = select({"@platforms//cpu:x86_64": ["-m64"],"@platforms//cpu:arm64": ["-march=armv8-a"],}),)
5. 链接配置
5.1 链接选项(linkopts)
cc_binary(name = "app",srcs = ["main.cc"],deps = ["//lib:utils"],linkopts = ["-pthread", # 链接 POSIX 线程"-lm", # 链接数学库"-lrt", # 链接实时库],)
5.2 库类型控制
cc_library(name = "shared_lib",srcs = ["lib.cc"],linkstatic = False, # 生成动态库(默认))cc_library(name = "static_lib",srcs = ["lib.cc"],linkstatic = True, # 生成静态库)
5.3 动态链接 vs 静态链接
# 动态链接(默认)cc_binary(name = "dynamic_app",deps = ["//lib:shared_lib", # 依赖动态库],)# 静态链接cc_binary(name = "static_app",deps = ["//lib:static_lib", # 依赖静态库],linkopts = ["-static"], # 强制静态链接)
5.4 alwayslink 属性
# 即使不被直接依赖也始终链接cc_library(name = "always_linked_lib",srcs = ["lib.cc"],alwayslink = True, # 影响所有依赖此库的目标)
6. 跨平台构建
6.1 平台约束
# 定义平台标签config_setting(name = "linux",constraint_values = ["@platforms//os:linux"],)config_setting(name = "windows",constraint_values = ["@platforms//os:windows"],)config_setting(name = "macos",constraint_values = ["@platforms//os:macos"],)
6.2 条件编译示例
# platform_lib/BUILDpackage(default_visibility = ["//visibility:public"])cc_library(name = "platform_lib",srcs = ["platform.cc"],hdrs = ["platform.h"],copts = select({"//:linux": ["-fPIC", "-Wall"],"//:windows": ["/W4", "/EHsc"],"//:macos": ["-fPIC", "-Wall"],"//conditions:default": ["-Wall"],}),linkopts = select({"//:linux": ["-lpthread"],"//:windows": [],"//:macos": [],}),deps = select({"//:linux": ["//lib:linux_specific"],"//:windows": ["//lib:windows_specific"],"//:macos": ["//lib:macos_specific"],}),)
6.3 多目标平台支持
# 构建不同平台的版本bazel build //:app --platforms=@platforms//os:linuxbazel build //:app --platforms=@platforms//os:windowsbazel build //:app --platforms=@platforms//os:macos# 交叉编译bazel build //:app --platforms=@platforms//os:linux --platforms_target=@platforms//cpu:x86_64
7. 高级编译配置
7.1 使用 asan/ubsan 等工具
# .bazelrcbuild:asan --copt=-fsanitize=addressbuild:asan --linkopt=-fsanitize=addressbuild:asan --copt=-gbuild:asan --copt=-O1build:ubsan --copt=-fsanitize=undefinedbuild:ubsan --linkopt=-fsanitize=undefined
7.2 覆盖率测试
# .bazelrcbuild:coverage --copt=-coveragebuild:coverage --linkopt=-coverage# 运行带覆盖率的测试bazel test //... --coverage --test_output=all# 生成覆盖率报告bazel coverage //... --html
7.3 性能分析
# 生成 profile 数据bazel build //:app --collect_code_coverage# 使用 perf 分析perf record -g bazel run //:appperf report
8. 自定义编译规则
8.1 创建自定义规则
# 自定义编译规则 my_cc_librarydef my_cc_lib(name, srcs, hdrs = None, deps = []):native.cc_library(name = name,srcs = srcs,hdrs = hdrs,deps = deps,copts = ["-Wall","-Wextra","-Werror",],)# 使用my_cc_lib(name = "my_lib",srcs = ["lib.cc"],hdrs = ["lib.h"],)
8.2 使用宏简化配置
# 自定义编译配置宏def optimized_cc_binary(name, srcs, deps = [], mode = "fastbuild"):native.cc_binary(name = name,srcs = srcs,deps = deps,copts = select({":opt_config": ["-O3", "-march=native"],":dbg_config": ["-g", "-O0"],"//conditions:default": ["-Og"],}),)# 使用optimized_cc_binary(name = "app",srcs = ["main.cc"],deps = ["//lib:utils"],)
9. 常用编译配置模板
9.1 模块化项目的编译配置
# .bazelrc# 默认配置build --copt=-Wallbuild --copt=-Wextrabuild --cxxopt=-std=c++17# 调试模式build:debug --copt=-gbuild:debug --copt=-DDEBUG=1build:debug --copt=-O0# 发布模式build:release --copt=-O3build:release --copt=-DNDEBUGbuild:release --cxxopt=march=native# 测试模式build:test --copt=-DTESTING=1build:test --test_output=allbuild:test --test_filter="*Test"# 优化选项build:opt --copt=-O3build:opt --copt=-march=nativebuild:opt --copt=-flto
9.2 项目级别的 BUILD 模板
# BUILD 模板def cc_library_with_common_options(name, **kwargs):kwargs.setdefault("copts", []).extend(["-Wall","-Wextra",])kwargs.setdefault("cxxopts", []).extend(["-std=c++17"])kwargs.setdefault("visibility", ["//visibility:public"])native.cc_library(name = name, **kwargs)def cc_binary_with_common_options(name, **kwargs):kwargs.setdefault("copts", []).extend(["-Wall","-Wextra",])kwargs.setdefault("cxxopts", []).extend(["-std=c++17"])native.cc_binary(name = name, **kwargs)
10. 小结
本篇详细介绍了 Bazel 的编译选项与工具链配置:
-
✅ 三种编译模式(fastbuild、dbg、opt)及其配置 -
✅ 编译器选项(copts、cxxopts)的使用方法 -
✅ 预处理器宏定义(defines)的配置 -
✅ 工具链的自定义与选择 -
✅ 链接选项与库类型控制 -
✅ 跨平台构建的策略 -
✅ 高级编译配置(asan、ubsan、覆盖率) -
✅ 自定义编译规则与宏
夜雨聆风