blob: 4c67c5513ab29517310f380285f3558631a854f8 [file] [log] [blame] [view]
Googlere7634412017-06-07 14:52:50 -04001---
2layout: documentation
3title: Common C++ Build Use Cases
4---
5
Googler1403a162021-01-22 13:42:50 -08006# Common C++ Build Use Cases
Googlere7634412017-06-07 14:52:50 -04007
8Here you will find some of the most common use cases for building C++ projects
9with Bazel. If you have not done so already, get started with building C++
10projects with Bazel by completing the tutorial
Googler032aab22017-09-14 16:49:56 +020011[Introduction to Bazel: Build a C++ Project](tutorial/cpp.html).
Googlere7634412017-06-07 14:52:50 -040012
Googlerab19d442021-04-21 14:38:23 -070013For information on cc_library and hdrs header files, see
14<a href="be/c-cpp.html#cc_library">cc_library</a>.
15
Googlere7634412017-06-07 14:52:50 -040016## Including multiple files in a target
17
18You can include multiple files in a single target with
dzc205125b2017-06-26 11:01:47 +020019[glob](../be/functions.html#glob).
Googlere7634412017-06-07 14:52:50 -040020For example:
21
22```python
23cc_library(
24 name = "build-all-the-files",
steplea6b2a1b2018-08-10 07:03:27 -070025 srcs = glob(["*.cc"]),
Googlere7634412017-06-07 14:52:50 -040026 hdrs = glob(["*.h"]),
27)
28```
29
30With this target, Bazel will build all the `.cc` and `.h` files it finds in the
31same directory as the `BUILD` file that contains this target (excluding
32subdirectories).
33
34## Using transitive includes
35
36If a file includes a header, then the file's rule should depend on that header's
Googler25a3c7d2021-01-22 18:38:49 +010037library. Conversely, only direct dependencies need to be specified as
38dependencies. For example, suppose `sandwich.h` includes `bread.h` and
39`bread.h` includes `flour.h`. `sandwich.h` doesn't include `flour.h` (who wants
Googlere7634412017-06-07 14:52:50 -040040flour in their sandwich?), so the `BUILD` file would look like this:
41
42```python
43cc_library(
44 name = "sandwich",
45 srcs = ["sandwich.cc"],
46 hdrs = ["sandwich.h"],
47 deps = [":bread"],
48)
49
50cc_library(
51 name = "bread",
52 srcs = ["bread.cc"],
53 hdrs = ["bread.h"],
54 deps = [":flour"],
55)
56
57cc_library(
58 name = "flour",
59 srcs = ["flour.cc"],
60 hdrs = ["flour.h"],
61)
62```
63
64Here, the `sandwich` library depends on the `bread` library, which depends
65on the `flour` library.
66
67## Adding include paths
68
69Sometimes you cannot (or do not want to) root include paths at the workspace
70root. Existing libraries might already have an include directory that doesn't
Googler25a3c7d2021-01-22 18:38:49 +010071match its path in your workspace. For example, suppose you have the following
Googlere7634412017-06-07 14:52:50 -040072directory structure:
73
74```
75└── my-project
aolivas7cbe1fb2018-03-09 05:13:17 -080076 ├── legacy
Googlere7634412017-06-07 14:52:50 -040077 │   └── some_lib
78 │   ├── BUILD
79 │   ├── include
80 │   │   └── some_lib.h
81 │   └── some_lib.cc
82 └── WORKSPACE
83```
84
85Bazel will expect `some_lib.h` to be included as
aolivas7cbe1fb2018-03-09 05:13:17 -080086`legacy/some_lib/include/some_lib.h`, but suppose `some_lib.cc` includes
Googler25a3c7d2021-01-22 18:38:49 +010087`"some_lib.h"`. To make that include path valid,
Daniel Martn61191f42019-10-17 02:54:56 -070088`legacy/some_lib/BUILD` will need to specify that the `some_lib/include`
Googlere7634412017-06-07 14:52:50 -040089directory is an include directory:
90
91```python
92cc_library(
93 name = "some_lib",
94 srcs = ["some_lib.cc"],
aolivas7cbe1fb2018-03-09 05:13:17 -080095 hdrs = ["include/some_lib.h"],
96 copts = ["-Ilegacy/some_lib/include"],
Googlere7634412017-06-07 14:52:50 -040097)
98```
99
100This is especially useful for external dependencies, as their header files
101must otherwise be included with a `/` prefix.
102
103## Including external libraries
104
105Suppose you are using [Google Test](https://github.com/google/googletest). You
Klaus Aehlige7008872019-04-24 08:51:46 -0700106can use one of the repository functions in the `WORKSPACE` file to
Googlere7634412017-06-07 14:52:50 -0400107download Google Test and make it available in your repository:
108
109```python
Klaus Aehlige7008872019-04-24 08:51:46 -0700110load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
111
112http_archive(
Googlere7634412017-06-07 14:52:50 -0400113 name = "gtest",
ranjanih15cfe702021-03-10 14:15:28 -0800114 url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
115 sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
Klaus Aehlige7008872019-04-24 08:51:46 -0700116 build_file = "@//:gtest.BUILD",
Googlere7634412017-06-07 14:52:50 -0400117)
118```
119
Klaus Aehlige7008872019-04-24 08:51:46 -0700120**NOTE:** If the destination already contains a `BUILD` file, you can leave
121out the `build_file` attribute.
Googlere7634412017-06-07 14:52:50 -0400122
123Then create `gtest.BUILD`, a `BUILD` file used to compile Google Test.
124Google Test has several "special" requirements that make its `cc_library` rule
125more complicated:
126
ranjanih15cfe702021-03-10 14:15:28 -0800127* `googletest-release-1.10.0/src/gtest-all.cc` `#include`s all other
128 files in `googletest-release-1.10.0/src/`: exclude it from the
Googler480d83e2021-02-26 17:24:10 -0800129 compile to prevent link errors for duplicate symbols.
Googlere7634412017-06-07 14:52:50 -0400130
131* It uses header files that are relative to the
ranjanih15cfe702021-03-10 14:15:28 -0800132`googletest-release-1.10.0/include/` directory (`"gtest/gtest.h"`), so you must
Googlere7634412017-06-07 14:52:50 -0400133add that directory to the include paths.
134
Googler480d83e2021-02-26 17:24:10 -0800135* It needs to link in `pthread`, so add that as a `linkopt`.
Googlere7634412017-06-07 14:52:50 -0400136
137The final rule therefore looks like this:
138
139```python
140cc_library(
141 name = "main",
142 srcs = glob(
ranjanih15cfe702021-03-10 14:15:28 -0800143 ["googletest-release-1.10.0/src/*.cc"],
144 exclude = ["googletest-release-1.10.0/src/gtest-all.cc"]
Googlere7634412017-06-07 14:52:50 -0400145 ),
146 hdrs = glob([
ranjanih15cfe702021-03-10 14:15:28 -0800147 "googletest-release-1.10.0/include/**/*.h",
148 "googletest-release-1.10.0/src/*.h"
Googlere7634412017-06-07 14:52:50 -0400149 ]),
150 copts = [
ranjanih15cfe702021-03-10 14:15:28 -0800151 "-Iexternal/gtest/googletest-release-1.10.0/include",
152 "-Iexternal/gtest/googletest-release-1.10.0"
Googlere7634412017-06-07 14:52:50 -0400153 ],
154 linkopts = ["-pthread"],
155 visibility = ["//visibility:public"],
156)
157```
158
ranjanih15cfe702021-03-10 14:15:28 -0800159This is somewhat messy: everything is prefixed with `googletest-release-1.10.0`
Klaus Aehlige7008872019-04-24 08:51:46 -0700160as a byproduct of the archive's structure. You can make `http_archive` strip
Googlere7634412017-06-07 14:52:50 -0400161this prefix by adding the `strip_prefix` attribute:
162
163```python
Klaus Aehlige7008872019-04-24 08:51:46 -0700164load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
165
166http_archive(
Googlere7634412017-06-07 14:52:50 -0400167 name = "gtest",
ranjanih15cfe702021-03-10 14:15:28 -0800168 url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
169 sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
Emmanuel Gohf1520f72019-09-03 10:45:45 -0700170 build_file = "@//:gtest.BUILD",
ranjanih15cfe702021-03-10 14:15:28 -0800171 strip_prefix = "googletest-release-1.10.0",
Googlere7634412017-06-07 14:52:50 -0400172)
173```
174
175Then `gtest.BUILD` would look like this:
176
177```python
178cc_library(
179 name = "main",
180 srcs = glob(
181 ["src/*.cc"],
182 exclude = ["src/gtest-all.cc"]
183 ),
184 hdrs = glob([
185 "include/**/*.h",
186 "src/*.h"
187 ]),
188 copts = ["-Iexternal/gtest/include"],
189 linkopts = ["-pthread"],
190 visibility = ["//visibility:public"],
191)
192```
193
194Now `cc_` rules can depend on `@gtest//:main`.
195
196## Writing and running C++ tests
197
Googler480d83e2021-02-26 17:24:10 -0800198For example, you could create a test `./test/hello-test.cc`, such as:
Googlere7634412017-06-07 14:52:50 -0400199
200```cpp
201#include "gtest/gtest.h"
ranjanih36d69ae2021-04-22 06:18:09 -0700202#include "main/hello-greet.h"
Googlere7634412017-06-07 14:52:50 -0400203
204TEST(HelloTest, GetGreet) {
205 EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
206}
207```
208
209Then create `./test/BUILD` file for your tests:
210
211```python
212cc_test(
213 name = "hello-test",
214 srcs = ["hello-test.cc"],
215 copts = ["-Iexternal/gtest/include"],
216 deps = [
217 "@gtest//:main",
??2ea81ac2019-03-26 14:53:44 -0700218 "//main:hello-greet",
Googlere7634412017-06-07 14:52:50 -0400219 ],
220)
221```
222
Googler480d83e2021-02-26 17:24:10 -0800223To make `hello-greet` visible to `hello-test`, you must add
??2ea81ac2019-03-26 14:53:44 -0700224`"//test:__pkg__",` to the `visibility` attribute in `./main/BUILD`.
Googlere7634412017-06-07 14:52:50 -0400225
226Now you can use `bazel test` to run the test.
227
228```
229bazel test test:hello-test
230```
231
232This produces the following output:
233
234```
235INFO: Found 1 test target...
236Target //test:hello-test up-to-date:
237 bazel-bin/test/hello-test
238INFO: Elapsed time: 4.497s, Critical Path: 2.53s
239//test:hello-test PASSED in 0.3s
240
241Executed 1 out of 1 tests: 1 test passes.
242```
243
244
245## Adding dependencies on precompiled libraries
246
247If you want to use a library of which you only have a compiled version (for
248example, headers and a `.so` file) wrap it in a `cc_library` rule:
249
250```python
251cc_library(
252 name = "mylib",
253 srcs = ["mylib.so"],
254 hdrs = ["mylib.h"],
255)
256```
257
258This way, other C++ targets in your workspace can depend on this rule.