百度Apollo源码学习之Bazel编译介绍

image.png

什么是Bazel

Bazel是一个类似于Make的编译工具,是Google为其内部软件开发的特点量身定制的工具,如今Google使用它来构建内部大多数的软件。(怪不得看起来很像Android.bp语法 O(∩_∩)O)

Google认为直接用Makefile构建软件速度太慢,结果不可靠,所以构建了一个新的工具叫做Bazel,Bazel的规则层级更高。

image.png

开始使用

Bazel的编译是基于工作区(workspace)的概念。

workspace

workspace存放了所有源代码和Bazel编译输出文件的目录,也就是整个项目的根目录。

workspace需要包含的必要文件:

  • WORKSPACE文件,用于指定当前文件夹就是一个Bazel的工作区。所以WORKSPACE文件总是存在于项目的根目录下。

  • BUILD文件,用于告诉Bazel怎么构建项目的不同部分。(如果工作区中的一个目录包含BUILD文件,那么它就是一个package)

要指定一个目录为Bazel的工作区,就只要在该目录下创建一个空的WORKSPACE文件即可。

但是在百度Apollo源码我们只能看到一个WORKSPACE.in文件:
.
├── apollo_docker.sh
├── apollo.doxygen
├── apollo.sh
├── BUILD
├── CONTRIBUTING.md
├── CPPLINT.cfg
├── cyber
├── docker
├── docs
├── LICENSE
├── MANIFESTO.md
├── modules
├── README.md
├── readthedocs.yml
├── RELEASE.md
├── scripts
├── third_party
├── tools
├── ubuntu_18.04_env
└── WORKSPACE.in

根据官网的描述:

一个工作区是在文件系统包含的源文件要构建的软件,以及符号链接到包含生成输出目录的目录。每个工作空间目录都有一个名为的文本文件WORKSPACE,该文件可以为空,或者可以包含 对构建输出所需的外部依赖项的引用。

包含名为的文件 WORKSPACE的目录被视为工作空间的根。因此,Bazel会忽略工作空间中的任何目录树,这些工作树植根于包含WORKSPACE文件的子目录(因为它们形成另一个工作空间)。

Bazel还支持将WORKSPACE.bazelfile作为文件的别名WORKSPACE。如果两个文件都存在,WORKSPACE.bazel将具有优先权。

可以看出bazel并不支持名为WORKSPACE.in的文件.

继续搜索源码,在文件apollo.sh中:

image.png

这里sed的作用:

sed 可依照脚本的指令来处理、编辑文本文件。
Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。

文件中大部分描述的就是编译过程中所需要的外部依赖.

具体语法可以参考官网.

BUILD文件

BUILD文件中包含了多个不同类型的bazel指令。

其中最重要的是编译规则(build rule),它告诉bazel怎么编译目标输出,是一个执行文件还是一个库。

BUILD文件中每一个编译规则被称为target,指向了一堆源文件和相关的依赖,一个target也可以指向其他target。
例子:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.c"],
)

其中的cc_binary,name,srcs都是相关的target.这些语法和Android.bp的语法很像,就不在多说.

看一下Apollo源码中的写法:(以location为例)

load("//tools:cpplint.bzl", "cpplint")

package(default_visibility = ["//visibility:public"])

filegroup(
    name = "localization_testdata",
    srcs = glob(["testdata/*"]),
)

cpplint()

这里声明加载tools:cpplint.bzl文件的cpplint函数:

def cpplint(data=None, extra_srcs=None):
  """For every rule in the BUILD file so far, adds a test rule that runs
  cpplint over the C++ sources listed in that rule.  Thus, BUILD file authors
  should call this function at the *end* of every C++-related BUILD file.
  By default, only the CPPLINT.cfg from the project root and the current
  directory are used.  Additional configs can be passed in as data labels.
  Sources that are not discoverable through the "sources so far" heuristic can
  be passed in as extra_srcs=[].
  """
  # Iterate over all rules.
  for rule in native.existing_rules().values():
    # Extract the list of C++ source code labels and convert to filenames.
    candidate_labels = (
      _extract_labels(rule.get("srcs", ())) +
      _extract_labels(rule.get("hdrs", ()))
    )
    source_labels = [
      label for label in candidate_labels
      if _is_source_label(label)
    ]
    source_filenames = ["$(location %s)" % x for x in source_labels]

    # Run the cpplint checker as a unit test.
    if len(source_filenames) > 0:
      _add_linter_rules(source_labels, source_filenames, rule["name"], data)

  # Lint all of the extra_srcs separately in a single rule.
  if extra_srcs:
    source_labels = extra_srcs
    source_filenames = ["$(location %s)" % x for x in source_labels]
    _add_linter_rules(source_labels, source_filenames,
                      "extra_srcs_cpplint", data)

Bazel编译看来也不是那么简单的.....

我们看一下根目录的BUILD文件:

package(
    default_visibility = ["//visibility:public"],
)

exports_files([
    "CPPLINT.cfg",
])

其中导入了一个cfg文件:

# Stop searching for additional config files.
set noparent

# Disable a warning about C++ features that were not in the original
# C++11 specification (and so might not be well-supported).
filter=-build/c++11

# Disable header_guard warning
# Consider using #pragma once instead
filter=-build/header_guard

cfg文件中设置了一些编译器的使用.

我们再看一下Bazel自己的配置文件.bazelrc

# load bazelrc from the legacy location
# as recommended in https://github.com/bazelbuild/bazel/issues/6319
import %workspace%/tools/bazel.rc

导入tools/bazel.rc文件,这个文件的内容如下:

# bazelrc file
# https://docs.bazel.build/versions/master/user-manual.html

# bazel >= 0.18 looks for %workspace%/.bazelrc (which redirects here)
# Older bazel versions look for %workspace%/tools/bazel.rc (this file)
# See https://github.com/bazelbuild/bazel/issues/6319

# +------------------------------------------------------------+
# | Startup Options                                            |
# +------------------------------------------------------------+
startup --batch_cpu_scheduling

startup --host_jvm_args=-XX:-UseParallelGC

startup --output_user_root=/apollo/.cache/bazel
# +------------------------------------------------------------+
# | Test Configurations                                        |
# +------------------------------------------------------------+

# By default prints output only from failed tests.
test --test_output=errors

# Work around the sandbox issue.
test --spawn_strategy=standalone

# Specify protobuf cc toolchain
test --proto_toolchain_for_cc="@com_google_protobuf//:cc_toolchain"

# +------------------------------------------------------------+
# | CPP Lint Tests & Unit Tests                                |
# +------------------------------------------------------------+
# By default, cpplint tests are run as part of `bazel test` alongside all of
# the other compilation and test targets.  This is a convenience shortcut to
# only do the cpplint testing and nothing else.
# Do bazel test --config=cpplint <target> to enable this configuration.
# To enable the lint test, the BUILD *must* load the cpplint.bzl by having
# 'load("//tools:cpplint.bzl", "cpplint")' at the beginning and 'cpplint()'
# at the end.
test:cpplint --test_tag_filters=cpplint
test:cpplint --build_tests_only

# Regular unit tests.
test:unit_test --test_tag_filters=-cpplint

# Coverage tests
test:coverage --test_tag_filters=-cpplint
test:coverage --copt=--coverage
test:coverage --cxxopt=--coverage
test:coverage --cxxopt=-fprofile-arcs
test:coverage --cxxopt=-ftest-coverage
test:coverage --linkopt=-coverage
test:coverage --linkopt=-lgcov
test:coverage --linkopt=-lgcc
test:coverage --linkopt=-lc

# +------------------------------------------------------------+
# | Build Configurations                                       |
# +------------------------------------------------------------+
# Do not show warnings from external dependencies.
build --output_filter="^//"

build --show_timestamps

# Work around the sandbox issue.
build --spawn_strategy=standalone

# Specify protobuf cc toolchain
build --proto_toolchain_for_cc="@com_google_protobuf//:cc_toolchain"

# build with profiling
build:cpu_prof --linkopt=-lprofiler

build --copt="-Werror=sign-compare"
build --copt="-Werror=return-type"
build --copt="-Werror=reorder"
build --copt="-Werror=unused-variable"
build --copt="-Werror=unused-but-set-variable"
build --copt="-Werror=switch"

# Strict check on type conversion.
# absl/strings/str_cat.h breaks the rule.
# build --per_file_copt=^modules/.*\.cc,-modules/tools/visualizer/.*\.cc,^cyber/.*\.cc@-Werror=conversion


# Enable C++14
build --cxxopt="-std=c++1y"
# Enable colorful output of GCC
# build --cxxopt="-fdiagnostics-color=always"

# +------------------------------------------------------------+
# | Python Configurations                                      |
# +------------------------------------------------------------+
run --python_path=/usr/bin/python3

也是配置各种编译环境,写的还是蛮复杂的.

参考

官网Bazel简介:编译一个C++工程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bynull

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值