乐于分享
好东西不私藏

Bazel C++ 构建系列文档(七):编译选项与工具链

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、覆盖率)
  • ✅ 自定义编译规则与宏