| --- |
| layout: documentation |
| title: Build Tutorial - C++ |
| --- |
| |
| Introduction to Bazel: Building a C++ Project |
| ========== |
| |
| In this tutorial, you'll learn the basics of building C++ applications with |
| Bazel. You will set up your workspace and build a simple C++ project that |
| illustrates key Bazel concepts, such as targets and `BUILD` files. After |
| completing this tutorial, take a look at |
| [Common C++ Build Use Cases](../cpp-use-cases.md) for information on more advanced |
| concepts such as writing and running C++ tests. |
| |
| Estimated completion time: 30 minutes. |
| |
| ## What you'll learn |
| |
| In this tutorial you'll learn how to: |
| |
| * Build a target |
| * Visualize the project's dependencies |
| * Split the project into multiple targets and packages |
| * Control target visibility across packages |
| * Reference targets through labels |
| |
| ## Contents |
| |
| * [Before you begin](#before-you-begin) |
| * [Install Bazel](#install-bazel) |
| * [Get the sample project](#get-the-sample-project) |
| * [Build with Bazel](#build-with-bazel) |
| * [Set up the workspace](#set-up-the-workspace) |
| * [Understand the BUILD file](#understand-the-build-file) |
| * [Build the project](#build-the-project) |
| * [Review the dependency graph](#review-the-dependency-graph) |
| * [Refine your Bazel build](#refine-your-bazel-build) |
| * [Specify multiple build targets](#specify-multiple-build-targets) |
| * [Use multiple packages](#use-multiple-packages) |
| * [Use labels to reference targets](#use-labels-to-reference-targets) |
| * [Further reading](#further-reading) |
| |
| ## Before you begin |
| |
| To prepare for the tutorial, first [Install Bazel](../install.md) if |
| you don't have it installed already. Then, retrieve the sample project from |
| Bazel's GitHub repository: |
| |
| ``` |
| git clone https://github.com/bazelbuild/examples/ |
| ``` |
| |
| The sample project for this tutorial is in the `examples/cpp-tutorial` directory |
| and is structured as follows: |
| |
| |
| ``` |
| examples |
| └── cpp-tutorial |
| ├──stage1 |
| │ ├── main |
| │ │ ├── BUILD |
| │ │ └── hello-world.cc |
| │ └── WORKSPACE |
| ├──stage2 |
| │ ├── main |
| │ │ ├── BUILD |
| │ │ ├── hello-world.cc |
| │ │ ├── hello-greet.cc |
| │ │ └── hello-greet.h |
| │ └── WORKSPACE |
| └──stage3 |
| ├── main |
| │ ├── BUILD |
| │ ├── hello-world.cc |
| │ ├── hello-greet.cc |
| │ └── hello-greet.h |
| ├── lib |
| │ ├── BUILD |
| │ ├── hello-time.cc |
| │ └── hello-time.h |
| └── WORKSPACE |
| ``` |
| |
| As you can see, there are three sets of files, each set representing a stage in |
| this tutorial. In the first stage, you will build a single target residing in a |
| single package. In the second stage, you will split your project into multiple |
| targets but keep it in a single package. In the third and final stage, you will |
| split your project into multiple packages and build it with multiple targets. |
| |
| ## Build with Bazel |
| |
| ### Set up the workspace |
| |
| Before you can build a project, you need to set up its workspace. A workspace is |
| a directory that holds your project's source files and Bazel's build outputs. It |
| also contains files that Bazel recognizes as special: |
| |
| * The `WORKSPACE` file, which identifies the directory and its contents as a |
| Bazel workspace and lives at the root of the project's directory structure, |
| |
| * One or more `BUILD` files, which tell Bazel how to build different parts of |
| the project. (A directory within the workspace that contains a `BUILD` file |
| is a *package*. You will learn about packages later in this tutorial.) |
| |
| To designate a directory as a Bazel workspace, create an empty file named |
| `WORKSPACE` in that directory. |
| |
| When Bazel builds the project, all inputs and dependencies must be in the same |
| workspace. Files residing in different workspaces are independent of one |
| another unless linked, which is beyond the scope of this tutorial. |
| |
| ### Understand the BUILD file |
| |
| A `BUILD` file contains several different types of instructions for Bazel. |
| The most important type is the *build rule*, which tells Bazel how to build the |
| desired outputs, such as executable binaries or libraries. Each instance |
| of a build rule in the `BUILD` file is called a *target* and points to a |
| specific set of source files and dependencies. A target can also point to other |
| targets. |
| |
| Take a look at the `BUILD` file in the `cpp-tutorial/stage1/main` directory: |
| |
| ``` |
| cc_binary( |
| name = "hello-world", |
| srcs = ["hello-world.cc"], |
| ) |
| ``` |
| |
| In our example, the `hello-world` target instantiates Bazel's built-in |
| [`cc_binary` rule](../be/c-cpp.html#cc_binary). The rule tells Bazel to build |
| a self-contained executable binary from the `hello-world.cc` source file with no |
| dependencies. |
| |
| The attributes in the target explicitly state its dependencies and options. |
| While the `name` attribute is mandatory, many are optional. For example, in the |
| `hello-world` target, `name` is self-explanatory, and `srcs` specifies the |
| source file(s) from which Bazel builds the target. |
| |
| ### Build the project |
| |
| Let's build your sample project. Change into the `cpp-tutorial/stage1` directory |
| and run the following command: |
| |
| ``` |
| bazel build //main:hello-world |
| ``` |
| |
| Notice the target label - the `//main:` part is the location of our `BUILD` |
| file relative to the root of the workspace, and `hello-world` is what we named |
| that target in the `BUILD` file. (You will learn about target labels in more |
| detail at the end of this tutorial.) |
| |
| Bazel produces output similar to the following: |
| |
| ``` |
| INFO: Found 1 target... |
| Target //main:hello-world up-to-date: |
| bazel-bin/main/hello-world |
| INFO: Elapsed time: 2.267s, Critical Path: 0.25s |
| ``` |
| |
| Congratulations, you just built your first Bazel target! Bazel places build |
| outputs in the `bazel-bin` directory at the root of the workspace. Browse |
| through its contents to get an idea for Bazel's output structure. |
| |
| Now test your freshly built binary: |
| |
| ```sh |
| bazel-bin/main/hello-world |
| ``` |
| |
| ### Review the dependency graph |
| |
| A successful build has all of its dependencies explicitly stated in the `BUILD` |
| file. Bazel uses those statements to create the project's dependency graph, |
| which enables accurate incremental builds. |
| |
| Let's visualize our sample project's dependencies. First, generate a text |
| representation of the dependency graph (run the command at the workspace root): |
| |
| ``` |
| bazel query --nohost_deps --noimplicit_deps 'deps(//main:hello-world)' \ |
| --output graph |
| ``` |
| |
| The above command tells Bazel to look for all dependencies for the target |
| `//main:hello-world` (excluding host and implicit dependencies) and format the |
| output as a graph. |
| |
| Then, paste the text into [GraphViz](http://www.webgraphviz.com/). |
| |
| On Ubuntu, you can view the graph locally by installing GraphViz and the xdot |
| Dot Viewer: |
| |
| ``` |
| sudo apt update && sudo apt install graphviz xdot |
| ``` |
| |
| Then you can generate and view the graph by piping the text output above |
| straight to xdot: |
| |
| ``` |
| bazel query --nohost_deps --noimplicit_deps 'deps(//main:hello-world)' \ |
| --output graph | xdot |
| ``` |
| |
| As you can see, the first stage of the sample project has a single target |
| that builds a single source file with no additional dependencies: |
| |
|  |
| |
| Now that you have set up your workspace, built your project, and examined its |
| dependencies, let's add some complexity. |
| |
| ## Refine your Bazel build |
| |
| While a single target is sufficient for small projects, you may want to split |
| larger projects into multiple targets and packages to allow for fast incremental |
| builds (that is, only rebuild what's changed) and to speed up your builds by |
| building multiple parts of a project at once. |
| |
| ### Specify multiple build targets |
| |
| Let's split our sample project build into two targets. Take a look at the |
| `BUILD` file in the `cpp-tutorial/stage2/main` directory: |
| |
| ``` |
| cc_library( |
| name = "hello-greet", |
| srcs = ["hello-greet.cc"], |
| hdrs = ["hello-greet.h"], |
| ) |
| |
| cc_binary( |
| name = "hello-world", |
| srcs = ["hello-world.cc"], |
| deps = [ |
| ":hello-greet", |
| ], |
| ) |
| ``` |
| |
| With this `BUILD` file, Bazel first builds the `hello-greet` library |
| (using Bazel's built-in [`cc_library` rule](../be/c-cpp.html#cc_library), |
| then the `hello-world` binary. The `deps` attribute in the `hello-world` target |
| tells Bazel that the `hello-greet` library is required to build the `hello-world` |
| binary. |
| |
| Let's build this new version of our project. Change into the |
| `cpp-tutorial/stage2` directory and run the following command: |
| |
| ``` |
| bazel build //main:hello-world |
| ``` |
| |
| Bazel produces output similar to the following: |
| |
| ``` |
| INFO: Found 1 target... |
| Target //main:hello-world up-to-date: |
| bazel-bin/main/hello-world |
| INFO: Elapsed time: 2.399s, Critical Path: 0.30s |
| ``` |
| |
| Now test your freshly built binary: |
| |
| ``` |
| bazel-bin/main/hello-world |
| ``` |
| |
| If you now modify `hello-greet.cc` and rebuild the project, Bazel will |
| only recompile that file. |
| |
| Looking at the dependency graph, you can see that `hello-world` depends on the |
| same inputs as it did before, but the structure of the build is different: |
| |
|  |
| |
| You've now built the project with two targets. The `hello-world` target builds |
| one source file and depends on one other target (`//main:hello-greet`), which |
| builds two additional source files. |
| |
| ### Use multiple packages |
| |
| Let’s now split the project into multiple packages. Take a look at the contents |
| of the `cpp-tutorial/stage3` directory: |
| |
| ``` |
| └──stage3 |
| ├── main |
| │ ├── BUILD |
| │ ├── hello-world.cc |
| │ ├── hello-greet.cc |
| │ └── hello-greet.h |
| ├── lib |
| │ ├── BUILD |
| │ ├── hello-time.cc |
| │ └── hello-time.h |
| └── WORKSPACE |
| ``` |
| Notice that we now have two sub-directories, and each contains a `BUILD` file. |
| Therefore, to Bazel, the workspace now contains two packages, `lib` and `main`. |
| |
| Take a look at the `lib/BUILD` file: |
| |
| ```python |
| cc_library( |
| name = "hello-time", |
| srcs = ["hello-time.cc"], |
| hdrs = ["hello-time.h"], |
| visibility = ["//main:__pkg__"], |
| ) |
| ``` |
| |
| And at the `main/BUILD` file: |
| |
| ```python |
| cc_library( |
| name = "hello-greet", |
| srcs = ["hello-greet.cc"], |
| hdrs = ["hello-greet.h"], |
| ) |
| |
| cc_binary( |
| name = "hello-world", |
| srcs = ["hello-world.cc"], |
| deps = [ |
| ":hello-greet", |
| "//lib:hello-time", |
| ], |
| ) |
| ``` |
| |
| As you can see, the `hello-world` target in the `main` package depends on the |
| `hello-time` target in the `lib` package (hence the target label |
| `//lib:hello-time`) - Bazel knows this through the `deps` attribute. Take a look |
| at the dependency graph: |
| |
|  |
| |
| Notice that for the build to succeed, we make the `//lib:hello-time` target in |
| `lib/BUILD` explicitly visible to targets in `main/BUILD` using the `visibility` |
| attribute. This is because by default targets are only visible to other targets |
| in the same `BUILD` file. (Bazel uses target visibility to prevent issues such |
| as libraries containing implementation details leaking into public APIs.) |
| |
| Let's build this final version of our project. Change into the |
| `cpp-tutorial/stage3` directory and run the following command: |
| |
| ``` |
| bazel build //main:hello-world |
| ``` |
| |
| Bazel produces output similar to the following: |
| |
| ``` |
| INFO: Found 1 target... |
| Target //main:hello-world up-to-date: |
| bazel-bin/main/hello-world |
| INFO: Elapsed time: 0.167s, Critical Path: 0.00s |
| ``` |
| |
| Now test the freshly built binary: |
| |
| ``` |
| bazel-bin/main/hello-world |
| ``` |
| |
| You've now built the project as two packages with three targets and understand |
| the dependencies between them. |
| |
| ## Use labels to reference targets |
| |
| In `BUILD` files and at the command line, Bazel uses *labels* to reference |
| targets - for example, `//main:hello-world` or `//lib:hello-time`. Their syntax |
| is: |
| |
| ``` |
| //path/to/package:target-name |
| ``` |
| |
| If the target is a rule target, then `path/to/package` is the path to the |
| directory containing the `BUILD` file, and `target-name` is what you named the |
| target in the `BUILD` file (the `name` attribute). If the target is a file |
| target, then `path/to/package` is the path to the root of the package, and |
| `target-name` is the name of the target file, including its full path. |
| |
| When referencing targets within the same package, you can skip the package path |
| and just use `//:target-name`. When referencing targets within the same `BUILD` |
| file, you can even skip the `//` workspace root identifier and just use |
| `:target-name`. |
| |
| |
| ## Further reading |
| |
| Congratulations! You now know the basics of building a C++ project with Bazel. |
| Next, read up on the most common [C++ build use cases](../cpp-use-cases.md). |
| Then, check out the following: |
| |
| * [External Dependencies](../external.html) to learn more about working with |
| local and remote repositories. |
| |
| * The [Build Encyclopedia](../be/overview.html) to learn more about Bazel. |
| |
| * The [Java build tutorial](java.md) to get started with |
| building Java applications with Bazel. |
| |
| * The [mobile application tutorial](app.md) to get started with |
| building mobile applications for Android and iOS with Bazel. |
| |
| Happy building! |