基于Bazel实现跨平台构建:OSX+Homebrew与Linux+{RPM,DPKG}
用Bazel跨平台处理外部依赖与C/C++构建
要实现同一源码库在不同平台(OSX、Debian系、RedHat系)复用系统包管理依赖,并传递平台专属编译标志,核心是利用Bazel的条件选择机制和系统依赖绑定能力,下面分步骤拆解实现:
一、平台检测与系统依赖绑定
Bazel通过select()和预定义平台标签区分操作系统,结合cc_library的system_provided=True标记复用系统已安装的包(Homebrew/DPKG/RPM)。
1. 定义平台匹配规则
在BUILD文件中,通过config_setting匹配不同平台:
# 匹配OSX系统(Homebrew环境) config_setting( name = "macos", constraint_values = ["@platforms//os:macos"], ) # 匹配Debian/Ubuntu等DPKG系统(需提前设置环境变量DISTRO=debian) config_setting( name = "debian", constraint_values = ["@platforms//os:linux"], env = {"DISTRO": "debian"}, ) # 匹配CentOS/RHEL等RPM系统(需提前设置环境变量DISTRO=redhat) config_setting( name = "redhat", constraint_values = ["@platforms//os:linux"], env = {"DISTRO": "redhat"}, )
Linux系区分Debian/RedHat时,可在构建前通过
export DISTRO=debian或redhat设置环境变量,也可结合脚本读取/etc/os-release自动判断。
2. 绑定系统依赖
以依赖zlib为例,针对不同平台配置头文件路径、库路径:
cc_library( name = "system_zlib", system_provided = True, hdrs = select({ ":macos": ["@homebrew_zlib//:include/zlib.h"], ":debian": ["/usr/include/zlib.h"], ":redhat": ["/usr/include/zlib.h"], }), includes = select({ ":macos": ["@homebrew_zlib//:include"], ":debian": ["/usr/include"], ":redhat": ["/usr/include"], }), linkopts = select({ ":macos": ["-L@homebrew_zlib//:lib", "-lz"], ":debian": ["-lz"], ":redhat": ["-lz"], }), visibility = ["//visibility:public"], )
OSX的Homebrew包需在WORKSPACE中通过
local_repository定位:local_repository( name = "homebrew_zlib", path = "/usr/local/opt/zlib", )
二、传递Autoconf风格的平台编译标志
针对C/C++的平台专属编译选项(如-fPIC、-mmacosx-version-min、宏定义),通过select()在cc_binary或cc_library的copts中配置:
cc_binary( name = "my_app", srcs = ["main.cc"], deps = [":system_zlib"], copts = select({ ":macos": [ "-mmacosx-version-min=10.15", "-D__APPLE__", ], ":debian": [ "-fPIC", "-D__DEBIAN__", "-Wall", ], ":redhat": [ "-fPIC", "-D__REDHAT__", "-O2", ], }), )
若需更精细的版本检测(如Debian 10+),可扩展config_setting结合环境变量或脚本输出实现。
三、完整配置示例
1. WORKSPACE文件
# 加载平台约束库 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "platforms", urls = ["https://github.com/bazelbuild/platforms/releases/download/0.0.6/platforms-0.0.6.tar.gz"], sha256 = "379113459b0feaf6bfbb584a91874c065078aa673222846ac765f86661c27407", ) # 仅OSX需要:定位Homebrew安装的zlib local_repository( name = "homebrew_zlib", path = "/usr/local/opt/zlib", )
2. BUILD文件
config_setting( name = "macos", constraint_values = ["@platforms//os:macos"], ) config_setting( name = "debian", constraint_values = ["@platforms//os:linux"], env = {"DISTRO": "debian"}, ) config_setting( name = "redhat", constraint_values = ["@platforms//os:linux"], env = {"DISTRO": "redhat"}, ) cc_library( name = "system_zlib", system_provided = True, hdrs = select({ ":macos": ["@homebrew_zlib//:include/zlib.h"], ":debian": ["/usr/include/zlib.h"], ":redhat": ["/usr/include/zlib.h"], }), includes = select({ ":macos": ["@homebrew_zlib//:include"], ":debian": ["/usr/include"], ":redhat": ["/usr/include"], }), linkopts = select({ ":macos": ["-L@homebrew_zlib//:lib", "-lz"], ":debian": ["-lz"], ":redhat": ["-lz"], }), visibility = ["//visibility:public"], ) cc_binary( name = "my_app", srcs = ["main.cc"], deps = [":system_zlib"], copts = select({ ":macos": [ "-mmacosx-version-min=10.15", "-D__APPLE__", ], ":debian": [ "-fPIC", "-D__DEBIAN__", "-Wall", ], ":redhat": [ "-fPIC", "-D__REDHAT__", "-O2", ], }), )
四、构建与验证
- OSX平台:直接执行
bazel build //:my_app,Bazel自动使用Homebrew的zlib - Debian平台:先设置
export DISTRO=debian,再执行构建命令 - RedHat平台:先设置
export DISTRO=redhat,再执行构建命令
调试方法:
bazel query //:system_zlib --output=build:查看依赖的实际配置细节bazel build //:my_app --verbose_failures:查看完整编译命令,确认标志是否生效
内容的提问来源于stack exchange,提问作者Maxim Razin
相关产品推荐
相关产品推荐

