Bazel初步学习

1,367 阅读9分钟

Bazel基础

简介

  • Bazel是Google开源的,类似于Make、Maven或Gradle的构建和测试工具。它使用可读性强的、高层次的构建语言,支持多种编程语言,以及为多种平台进行交叉编译。
  • 大致工作流程:

    • 根据目标,加载WORKSPACE和BUILD文件
    • 分享目标相关BUILD文件
    • 构建BUILD依赖关系,并产生构建图(Action图)
    • 构建产物(outputs)

概念

  • BUILD文件

    BUILD文件定义了包的所有元数据。其中的语句被从上而下的逐条解释(变量必须先定义后使用,但是规则声明的顺序无所谓。)

    BUILD文件仅能包含ASCII字符,且不得声明函数、使用for/if语句;

    可以在Bazel扩展——扩展名为 .bzl 的文件中声明函数、控制结构等,并在BUILD文件中用 load 语句加载Bazel扩展。

  • Rule

    规则指定输入和输出之间的关系,并且说明产生输出的步骤。

    规则有很多类型。每个规则都具有一个名称属性,此名称亦即目标名称。对于某些规则,此名称就是产生的输出的文件名。

    规则的类型,一般以编程语言为前缀,例如cc,java,后缀通常有:

    • *_binary 用于构建目标语言的可执行文件
    • *_test 用于自动化测试,其目标是可执行文件,如果测试通过应该退出0
    • *_library 用于构建目标语言的库 
  • Workspace

    • 工作空间是一个目录(可以为空以及包含对外部依赖的引用等),它包含:

      • 构建目标所需要的源码文件,以及相应的BUILD文件
      • 指向构建结果的符号链接
  • Package

    • 包是工作空间中主要的代码组织单元,是工作空间的子目录
    • 其中包含一系列相关的文件(主要是代码)以及描述这些文件之间关系的BUILD文件
    • 除了那些具有BUILD文件的子目录——子包——以外,其它子目录属于包的一部分
  • Target

    • 包是一个容器,它的元素定义在BUILD文件中

      • 包括:规则、文件(源文件和由构建工具自动生成的文件)、包组(一组包,用于限制特定规则的可见性)
      • 任何包生成的文件都属于当前包,不能为其它包生成文件,但可以从其它包中读取输入
  • Label

    • 引用一个特定目标(Target)时需要使用“标签”。

    • 标签的规范化表示:@project_name//xx/yy/zz:name

      • 冒号前面是所属的包名,后面是目标名
      • 在BUILD文件中,引用当前包中定义的规则时,冒号不能省略;引用当前包中文件时,冒号可以省略。
      • @project_name这一部分通常不需要使用,引用外部存储库中的目标时,project_name填写外部存储库的名字。
  • Dependency

    • 目标A依赖B,就意味着A在构建或执行期间需要B。所有目标的依赖关系构成非环有向图(DAG)称为依赖图。
    • 距离为1的依赖称为直接依赖,大于1的依赖则称为传递性依赖。
    • 依赖分为以下几种:
      • srcs依赖:直接被当前规则消费的文件
      • deps依赖:独立编译的模块,为当前规则提供头文件、符号、库、数据
      • data依赖:不属于源码,不影响目标如何构建,但是目标在运行时可能依赖之

常用指令

  • 安装指令
# 1 MacOS
brew install bazel 
brew install bazelisk bazel version
  • Bazel指令
# bazel clean
bazel clean # 不会删除外部依赖
bazel clean --expunge # 会删除外部依赖
bazel clean --expunge --async

# bazel build
bazel build :<exe name> # 在BUILD所在的package目录下执行,编译指定的target
bazel build :all  # 编译该package下的所有target
bazel build ...  # 编译该package下的所有target
bazel build <//path/to/package>:<exe name> # 在workspace下的任意目录执行,“//”表示workspace所在目录
bazel build :<exe name> --compilation_mode=dbg # debug mode
bazel build :<exe name> -c dbg # debug mode
bazel build :<exe name> --keep_going # 看到所有的错误
bazel build :<exe name> --config=<asan/tsan/msan> # Build the project with sanitizers by adding the --config=<asan/tsan/msan> build flag to select AddressSanitizer (asan), ThreadSanitizer (tsan) or MemorySanitizer (msan) accordingly.
bazel build :<exe name> --config local_first

#bazel run (不需要先执行build,在执行run,run的时候会自动先build再执行)
bazel run :<target name>
bazel run -- :<target name>

# action graph: bazel依赖这个图来追踪文件变化,以及是否需要重新编译,并且还可以为用户提供代码之间的依赖关系图。
bazel query 'deps(//<path_to_package>:<target_name>)' # 查看target的依赖
bazel query "somepath(//<path_to_package>:<target1_name>, //<path_to_package>:<target2_name>)"

Build文件相关规则

通用

iOS

官方文档:github.com/bazelbuild/…

ios_application

ios_application(name, additional_linker_inputs, alternate_icons, app_clips, app_icons, bundle_id,
                bundle_name, codesign_inputs, codesignopts, deps, entitlements,
                entitlements_validation, executable_name, exported_symbols_lists, extensions,
                families, frameworks, include_symbols_in_bundle, infoplists, ipa_post_processor,
                launch_images, launch_storyboard, linkopts, minimum_deployment_os_version,
                minimum_os_version, platform_type, provisioning_profile, resources, sdk_frameworks,
                settings_bundle, stamp, strings, version, watch_application)
名称描述备注类型
name目标名称Name[required,unique]
app_iconsapp的图标文件每个文件必须有一个名为 ..xcassets/..appiconset 的包含目录,并且列表中可能只有一个这样的 ..appiconset 目录。List of labels[optional]
bundle_idAPP的bundle_idString,[required]
bundle_nameAPP的bundle_name如果未设置此属性,则将使用目标的名称。String,[optional]
deps依赖项List of labels[optional]
families在哪些类型的设备上生效「iphone」或者「iPad」,至少得有一个List of strings[required]
frameworks所依赖的ios_frameworkList of labels[optional]
infoplists.plist 文件List of labels[optional]
launch_images包含应用程序启动图像的文件List of labels[optional]
launch_storyboard应用作应用程序启动屏幕的 .storyboard 或 .xib 文件。Label[optional]
minimum_os_versionapp支持的最低操作系统版本的必需字符串,表示为点分版本号(例如,“9.0”)String,[required]
minimum_deployment_os_versionapp支持的最低部署操作系统版本的必需字符串,表示为点分版本号(例如,“9.0”)。这与在编译时有效的 minimum_os_version 不同。此选项确保版本特定的 API 受到可用子句的保护。String,[optional]
resources资源或文件的列表List of labels[optional]
strings.strings 文件列表,通常做本地化List of labels[optional]

(tips:只列入了一些常见的属性,详见官方文档里关于 ios_application 所有规则的解释)

objc_library

官网地址:bazel.build/reference/b…

属性说明备注类型
name(必填项)库的名称Name; required
deps需要链接到(into)当前库的其它库所依赖的其他模块(非苹果官方库)List of labels; optional
srcs头文件和源码列表正在处理的 C、C++、Objective-C 和 Objective-C++ 源文件和头文件和/或(“s.”、“.S`”或“.asm”)汇编源文件列表。以创建库目标。 这些是您已签入的文件以及生成的任何文件。 使用 Clang 将源文件编译为 .o 文件。此目标的 srcs 属性中的任何源文件或头文件均可包含/导入头文件,但不能由 hdrs 中的头文件或依赖此规则的任何目标包含/导入头文件。 此外,预编译的 .o 文件可能会以 src 的形式提供。 请务必注意所提供的 .o 文件架构和 build 架构的一致性,以避免缺少符号链接器错误。List of labels; optional
hdrs导出的头文件列表,如果启用了该模块,这些将与源文件分开编译。声明的头文件构成库的公共接口List of labels; optional
alwayslink(bool,默认为False)如果为True,任何依赖(直接或间接)依赖此库的捆绑包或二进制文件都将链接到srcs和非_arc_srcs中列出的文件的所有对象文件中,即使有些文件不包含二进制文件引用的符号。如果您的代码没有被二进制文件中的代码显式调用。例如,您的代码注册以接收某些服务提供的一些回调,这将非常有用。Boolean; optional; default is False
copts编译参数列表常用的:-no-warnings-as-errors,-iquote,-Wno-swift-name-attribute,"-ObjC"List of strings; optional
defines宏定义列表List of strings; optional
enable_modules(bool,默认为False)启用clang模块支持(通过-fmodules)。设置为"1"将允许你@导入系统头文件和其他目标:@import UIKit; @import path_to_package_target;Boolean; optional; default is False
includes(字符串列表)需要添加到编译命令所包含的文件列表,即要添加到此目标和所有依赖目标的#include/#import搜索路径列表。这是为了支持那些没有在他们的#import/#include语句中指定整个工作空间路径的第三方和开源库。与copts不同,这些标志是为该规则以及依赖于该规则的所有规则添加的。(注意:不是它所依赖的规则!)。如果不确定,可以在copts中添加“-iquote”标志。别的模块需要引用到该模块的头文件时List of strings; optional
linkopts链接选项List of strings; optional
module_map(标签)这个目标的自定义Clang模块映射。不鼓励使用自定义模块映射。大多数用户应该使用由Bazel生成的模块映射。如果指定了,Bazel将不会为这个目标生成模块映射,而是将提供的模块映射传递给编译器。Label; optional
module_name模块名称String; optional
non_arc_srcs(标签列表)用于创建不使用ARC的目标库的Objective-C文件列表。该属性中的文件处理方式与srcs属性中的文件非常相似,但在编译时不启用ARC。List of labels; optional
pch(标签)要编译的每个源文件前面的头文件。不鼓励在BUILD文件中使用pch文件,这应该被认为是不可取的。由于pch文件实际上没有预编译,这并不能提高构建速度,而只是一个全局依赖。从构建效率的角度来看,在需要的地方直接将需要的内容包含在资源中实际上更好独立的SDK,需要用到?Label; optional
runtime_deps(标签列表)在运行时延迟加载的框架目标列表。它们包含在应用包中,但在构建时没有链接。List of labels; optional
sdk_dylibs(字符串列表)要链接的SDK .dylib库的名称。例如,“libz”或“libarchive”。List of strings; optional
sdk_frameworks(字符串列表)要链接的SDK框架的名称(例:“AddressBook”、“QuartzCore”)对于iOS, tvOS和watchOS平台构建时,“UIKit”和“Foundation”总是被包含在内对于macOS,只包含"Foundation"当链接一个顶级的Apple二进制文件时,该二进制文件的传递依赖关系图中列出的所有SDK框架都会被链接。即当模块内需要用到<QuartzCore/**>时,就需要添加引用“QuartzCore”引用List of strings; optional
sdk_includes(字符串列表)要添加到此目标和所有依赖目标的#include/#import搜索路径列表,其中每个路径相对于$(SDKROOT)/usr/include。List of strings; optional
textual_hdrs(字符串列表)头文件列表,这些头文件是不能独立编译的。依赖此库的目标,直接以文本形式包含这些头文件到它的源码列表中,这样才能正确编译这些头文件List of labels; optional

copts-相关编译参数:GCC指令

Swift

官网地址:github.com/bazelbuild/…

Learning....

实战

bbstudy-oc

实战项目地址(OC)

bbstudy-swift

Learning...

bbstudy-oc-swift

Learning...

相关文档